everything in src for packaging purposes
authorgwen <gremond@cadoles.com>
Fri, 13 Jul 2012 07:37:35 +0000 (09:37 +0200)
committergwen <gremond@cadoles.com>
Fri, 13 Jul 2012 07:37:35 +0000 (09:37 +0200)
87 files changed:
src/README [new file with mode: 0644]
src/__init__.py [new file with mode: 0644]
src/autolib.py [new file with mode: 0644]
src/basetype.py [new file with mode: 0644]
src/config.py [new file with mode: 0644]
src/doc/Makefile [new file with mode: 0644]
src/doc/build/Makefile [new file with mode: 0644]
src/doc/build/api/Readme [new file with mode: 0644]
src/doc/build/architecture.dia [new file with mode: 0644]
src/doc/build/architecture.png [new file with mode: 0644]
src/doc/build/default.css [new file with mode: 0644]
src/doc/build/docutils.css [new file with mode: 0644]
src/doc/build/pydoc/Makefile [new file with mode: 0644]
src/doc/build/pydoc/api-objects.txt [new file with mode: 0644]
src/doc/build/pydoc/crarr.png [new file with mode: 0644]
src/doc/build/pydoc/epydoc.css [new file with mode: 0644]
src/doc/build/pydoc/epydoc.js [new file with mode: 0644]
src/doc/build/style.css [new file with mode: 0644]
src/doc/build/tiramisu.jpeg [new file with mode: 0644]
src/doc/code2html [new file with mode: 0755]
src/doc/config.txt [new file with mode: 0644]
src/doc/configapi.txt [new file with mode: 0644]
src/doc/consistency.txt [new file with mode: 0644]
src/doc/eole-report/eolreport/D01AccesVariables.txt [new file with mode: 0644]
src/doc/eole-report/eolreport/D02CoherenceVariables.txt [new file with mode: 0644]
src/doc/eole-report/eolreport/D03ReglesEtats.txt [new file with mode: 0644]
src/doc/eole-report/eolreport/Makefile [new file with mode: 0644]
src/doc/eole-report/eolreport/build/Makefile [new file with mode: 0644]
src/doc/eole-report/eolreport/build/default.css [new file with mode: 0644]
src/doc/eole-report/eolreport/build/docutils.css [new file with mode: 0644]
src/doc/eole-report/eolreport/build/imgs/eol.png [new file with mode: 0644]
src/doc/eole-report/eolreport/build/imgs/logo.png [new file with mode: 0644]
src/doc/eole-report/eolreport/build/index-report.html [new file with mode: 0644]
src/doc/eole-report/eolreport/build/pdfreport/D01AccesVariables.pdf [new file with mode: 0644]
src/doc/eole-report/eolreport/build/pdfreport/D02CoherenceVariables.pdf [new file with mode: 0644]
src/doc/eole-report/eolreport/build/pdfreport/D03ReglesEtats.pdf [new file with mode: 0644]
src/doc/eole-report/eolreport/build/pdfreport/make_index [new file with mode: 0755]
src/doc/eole-report/eolreport/build/pdfreport/rst.py [new file with mode: 0644]
src/doc/eole-report/eolreport/build/style.css [new file with mode: 0644]
src/doc/eole-report/eolreport/inc/00-Redacteur.txt [new file with mode: 0644]
src/doc/eole-report/eolreport/inc/eol.png [new file with mode: 0644]
src/doc/eole-report/eolreport/inc/logo.png [new file with mode: 0644]
src/doc/eole-report/eolreport/inc/menjva.gif [new file with mode: 0644]
src/doc/eole-report/eolreport/inc/preambule.txt [new file with mode: 0644]
src/doc/eole-report/eolreport/index-report.txt [new file with mode: 0644]
src/doc/eole-report/eolreport/styles.odt [new file with mode: 0644]
src/doc/eole-report/presentation/Makefile [new file with mode: 0644]
src/doc/eole-report/presentation/definition.tex [new file with mode: 0644]
src/doc/eole-report/presentation/statut.tex [new file with mode: 0644]
src/doc/eole-report/presentation/tiramisu.tex [new file with mode: 0644]
src/doc/epydoc.sh [new file with mode: 0755]
src/doc/gaspacho.txt [new file with mode: 0644]
src/doc/getting-started.txt [new file with mode: 0644]
src/doc/glossary.txt [new file with mode: 0644]
src/doc/index.txt [new file with mode: 0644]
src/doc/optionapi.txt [new file with mode: 0644]
src/doc/rst2html.py [new file with mode: 0755]
src/doc/status.txt [new file with mode: 0644]
src/doc/todo.txt [new file with mode: 0644]
src/error.py [new file with mode: 0644]
src/gpl-3.0.txt [new file with mode: 0644]
src/option.py [new file with mode: 0644]
src/report/Makefile [new file with mode: 0644]
src/report/__init__.py [new file with mode: 0644]
src/report/build/Makefile [new file with mode: 0644]
src/report/build/basic.css [new file with mode: 0644]
src/report/build/rst2html.py [new file with mode: 0755]
src/report/build/style.css [new file with mode: 0644]
src/report/generate.py [new file with mode: 0644]
src/report/makerestdoc.py [new file with mode: 0644]
src/report/rst.py [new file with mode: 0644]
src/report/test_config_big_example.py [new file with mode: 0644]
src/test/__init__.py [new file with mode: 0644]
src/test/autopath.py [new file with mode: 0644]
src/test/test_config.py [new file with mode: 0644]
src/test/test_config_api.py [new file with mode: 0644]
src/test/test_config_big_example.py [new file with mode: 0644]
src/test/test_option_consistency.py [new file with mode: 0644]
src/test/test_option_default.py [new file with mode: 0644]
src/test/test_option_owner.py [new file with mode: 0644]
src/test/test_option_setting.py [new file with mode: 0644]
src/test/test_option_type.py [new file with mode: 0644]
src/test/test_option_with_special_name.py [new file with mode: 0644]
src/test/test_parsing_group.py [new file with mode: 0644]
src/test/test_reverse_from_path.py [new file with mode: 0644]
src/test/test_tool.py [new file with mode: 0644]
src/tool.py [new file with mode: 0644]

diff --git a/src/README b/src/README
new file mode 100644 (file)
index 0000000..23929c6
--- /dev/null
@@ -0,0 +1,18 @@
+--------
+LICENSES
+--------
+
+Tiramisu is under the terms of the GNU General Public License v3.0 as 
+published by the Free Software Foundation; either version 3 of the 
+License, or (at your option) any later version.
+
+See gpl-3.0.txt for more informations.
+
+Contributors:
+
+Gwenaël Rémond <gremond@cadoles.com> lead developer
+Emmanuel Garette <egarette@cadoles.com> contributor
+
+
+
+
diff --git a/src/__init__.py b/src/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/autolib.py b/src/autolib.py
new file mode 100644 (file)
index 0000000..febc172
--- /dev/null
@@ -0,0 +1,94 @@
+# Copyright (C) 2012 Team tiramisu (see README for all contributors)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# The original `Config` design model is unproudly borrowed from 
+# the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
+# the whole pypy projet is under MIT licence
+# ____________________________________________________________
+"enables us to carry out a calculation and return an option's value"
+from tiramisu.error import DisabledOptionError, SpecialOwnersError
+# ____________________________________________________________
+# automatic Option object
+special_owners = ['auto', 'fill']
+                  
+def special_owner_factory(name, owner, value, 
+                          callback, callback_params=None, config=None):
+    # in case of an 'auto' and a 'fill' without a value, 
+    # we have to carry out a calculation
+    return calc_factory(name, callback, callback_params, config)
+
+def calc_factory(name, callback, callback_params, config):
+    # FIXME we have to know the exact status of the config 
+    # not to disrupt it
+    # config.freeze()
+    if callback_params is None:
+        callback_params = {}
+    tcparams = {}
+    one_is_multi = False
+    len_multi = 0
+    for key, value in callback_params.items():
+        if type(value) == tuple:
+            path, check_disabled = value
+            try:
+                opt_value = getattr(config, path)
+                opt = config.unwrap_from_path(path)
+            except DisabledOptionError, e:
+                if chek_disabled:
+                    continue
+                raise DisabledOptionError(e)
+            is_multi = opt.is_multi()
+            if is_multi:
+                if opt_value != None:
+                    len_value = len(opt_value)
+                    if len_multi != 0 and len_multi != len_value:
+                        raise SpecialOwnersError('unable to carry out a calculation, '
+                        'option values with multi types must have same length for: '
+                         + name)
+                    len_multi = len_value
+                one_is_multi = True
+            tcparams[key] = (opt_value, is_multi)
+        else:
+            tcparams[key] = (value, False)
+
+    if one_is_multi:
+        ret = []
+        for incr in range(len_multi):
+            tcp = {}
+            for key, couple in tcparams.items():
+                value, ismulti = couple
+                if ismulti and value != None:
+                    tcp[key] = value[incr]
+                else:
+                    tcp[key] = value
+            ret.append(calculate(name, callback, tcp))
+        return ret
+    else:
+        tcp = {}
+        for key, couple in tcparams.items():
+            tcp[key] = couple[0]
+        return calculate(name, callback, tcp)
+    
+def calculate(name, callback, tcparams):
+    try:
+        # XXX not only creole...
+        from creole import eosfunc
+        return getattr(eosfunc, callback)(**tcparams) 
+    except AttributeError, err:
+        import traceback
+        traceback.print_exc()
+        raise SpecialOwnersError("callback: {0} return error {1} for "
+                       "option: {2}".format(callback, str(err), name))
+
diff --git a/src/basetype.py b/src/basetype.py
new file mode 100644 (file)
index 0000000..c501ccb
--- /dev/null
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+"base 'interface' types for option types"
+# Copyright (C) 2012 Team tiramisu (see README for all contributors)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# The original `Config` design model is unproudly borrowed from 
+# the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
+# the whole pypy projet is under MIT licence
+# ____________________________________________________________
+# Option and OptionDescription modes
+modes = ['normal', 'expert']
+
+class HiddenBaseType(object):
+    hidden = False
+    def hide(self):
+        self.hidden = True
+    def show(self):
+        self.hidden = False
+    def _is_hidden(self):
+        # dangerous method: how an Option can determine its status by itself ? 
+        return self.hidden
+
+class DisabledBaseType(object):
+    disabled = False   
+    def disable(self):
+        self.disabled = True
+    def enable(self):
+        self.disabled = False
+    def _is_disabled(self):
+        return self.disabled
+
+class ModeBaseType(object):
+    mode = 'normal'
+    def get_mode(self):
+        return self.mode
+    def set_mode(self, mode):
+        if mode not in modes:
+            raise TypeError("Unknown mode: {0}".format(mode))
+        self.mode = mode    
+
diff --git a/src/config.py b/src/config.py
new file mode 100644 (file)
index 0000000..f4fabdd
--- /dev/null
@@ -0,0 +1,540 @@
+# -*- coding: utf-8 -*-
+"pretty small and local configuration management tool"
+# Copyright (C) 2012 Team tiramisu (see README for all contributors)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# The original `Config` design model is unproudly borrowed from 
+# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
+# the whole pypy projet is under MIT licence
+# ____________________________________________________________
+from error import (HiddenOptionError, ConfigError, NotFoundError, 
+                AmbigousOptionError, ConflictConfigError, NoMatchingOptionFound, 
+                            SpecialOwnersError, MandatoryError, MethodCallError, 
+                                           DisabledOptionError, ModeOptionError)
+from option import (OptionDescription, Option, SymLinkOption, group_types, 
+                    Multi, apply_requires, modes)
+from autolib import special_owners, special_owner_factory
+# ______________________________________________________________________
+# generic owner. 'default' is the general config owner after init time
+default_owner = 'user'
+# ____________________________________________________________
+class Config(object):
+    _cfgimpl_hidden = True
+    _cfgimpl_disabled = True
+    _cfgimpl_mandatory = True
+    _cfgimpl_frozen = False
+    _cfgimpl_owner = default_owner
+    _cfgimpl_toplevel = None
+    _cfgimpl_mode = 'normal'
+    
+    def __init__(self, descr, parent=None, **overrides):
+        self._cfgimpl_descr = descr
+        self._cfgimpl_value_owners = {}
+        self._cfgimpl_parent = parent
+        # `Config()` indeed takes care of the `Option()`'s values
+        self._cfgimpl_values = {}
+        self._cfgimpl_previous_values = {}
+        # XXX warnings are a great idea, let's make up a better use of it 
+        self._cfgimpl_warnings = []
+        self._cfgimpl_toplevel = self._cfgimpl_get_toplevel()
+        # `freeze()` allows us to carry out this calculation again if necessary 
+        self._cfgimpl_frozen = self._cfgimpl_toplevel._cfgimpl_frozen 
+        self._cfgimpl_build(overrides)
+
+    def _validate_duplicates(self, children):
+        duplicates = []
+        for dup in children:
+            if dup._name not in duplicates:
+                duplicates.append(dup._name)
+            else:
+                raise ConflictConfigError('duplicate option name: ' 
+                    '{0}'.format(dup._name))
+
+    def _cfgimpl_build(self, overrides):
+        self._validate_duplicates(self._cfgimpl_descr._children)
+        for child in self._cfgimpl_descr._children:
+            if isinstance(child, Option):
+                if child.is_multi():
+                    childdef = Multi(child.getdefault(), config=self, 
+                                     child=child)
+                    self._cfgimpl_values[child._name] = childdef
+                    self._cfgimpl_previous_values[child._name] = childdef
+                else:
+                    childdef = child.getdefault()
+                    self._cfgimpl_values[child._name] = childdef
+                    self._cfgimpl_previous_values[child._name] = childdef 
+                if child.getcallback() is not None:
+                    if child._is_hidden():
+                        self._cfgimpl_value_owners[child._name] = 'auto'
+                    else:
+                        self._cfgimpl_value_owners[child._name] = 'fill'
+                else:
+                    if child.is_multi():
+                        self._cfgimpl_value_owners[child._name] = ['default' \
+                            for i in range(len(child.getdefault() ))]
+                    else:
+                        self._cfgimpl_value_owners[child._name] = 'default'
+            elif isinstance(child, OptionDescription):
+                self._validate_duplicates(child._children)
+                self._cfgimpl_values[child._name] = Config(child, parent=self)
+        self.override(overrides)
+
+    def cfgimpl_update(self):
+        "dynamically adds `Option()` or `OptionDescription()`"
+        # Nothing is static. Everything evolve.
+        # FIXME this is an update for new options in the schema only 
+        # see the update_child() method of the descr object 
+        for child in self._cfgimpl_descr._children:
+            if isinstance(child, Option):
+                if child._name not in self._cfgimpl_values:
+                    self._cfgimpl_values[child._name] = child.getdefault()
+                    # FIXME and ['default', ...] if is_multi() ?
+                    self._cfgimpl_value_owners[child._name] = 'default'
+            elif isinstance(child, OptionDescription):
+                if child._name not in self._cfgimpl_values:
+                    self._cfgimpl_values[child._name] = Config(child, parent=self)
+
+    def override(self, overrides):
+        for name, value in overrides.iteritems():
+            homeconfig, name = self._cfgimpl_get_home_by_path(name)
+            #  if there are special_owners, impossible to override
+            if homeconfig._cfgimpl_value_owners[name] in special_owners:
+                raise SpecialOwnersError("cannot override option: {0} because "
+                                            "of its special owner".format(name))
+            homeconfig.setoption(name, value, 'default')
+
+    def cfgimpl_set_owner(self, owner):
+        self._cfgimpl_owner = owner
+        for child in self._cfgimpl_descr._children:
+            if isinstance(child, OptionDescription):
+                self._cfgimpl_values[child._name].cfgimpl_set_owner(owner)
+    # ____________________________________________________________
+    def cfgimpl_hide(self):
+        if self._cfgimpl_parent != None:
+            raise MethodCallError("this method root_hide() shall not be"
+                                           "used with non-root Config() object") 
+        rootconfig = self._cfgimpl_get_toplevel()
+        rootconfig._cfgimpl_hidden = True
+
+    def cfgimpl_show(self):
+        if self._cfgimpl_parent != None:
+            raise MethodCallError("this method root_hide() shall not be"
+                                           "used with non-root Config() object") 
+        rootconfig = self._cfgimpl_get_toplevel()
+        rootconfig._cfgimpl_hidden = False
+    # ____________________________________________________________
+    def cfgimpl_disable(self):
+        if self._cfgimpl_parent != None:
+            raise MethodCallError("this method root_hide() shall not be"
+                                           "used with non-root Confit() object") 
+        rootconfig = self._cfgimpl_get_toplevel()
+        rootconfig._cfgimpl_disabled = True
+
+    def cfgimpl_enable(self):
+        if self._cfgimpl_parent != None:
+            raise MethodCallError("this method root_hide() shall not be"
+                                           "used with non-root Confit() object") 
+        rootconfig = self._cfgimpl_get_toplevel()
+        rootconfig._cfgimpl_disabled = False
+    # ____________________________________________________________
+    def __setattr__(self, name, value):
+        if '.' in name:
+            homeconfig, name = self._cfgimpl_get_home_by_path(name)
+            return setattr(homeconfig, name, value)
+
+        if name.startswith('_cfgimpl_'):
+            self.__dict__[name] = value
+            return
+        if self._cfgimpl_frozen and getattr(self, name) != value:
+            raise TypeError("trying to change a value in a frozen config"
+                                                ": {0} {1}".format(name, value))
+        if type(getattr(self._cfgimpl_descr, name)) != SymLinkOption:
+            self._validate(name, getattr(self._cfgimpl_descr, name))
+        self.setoption(name, value, self._cfgimpl_owner)
+        
+    def _validate(self, name, opt_or_descr):
+        apply_requires(opt_or_descr, self) 
+        if not type(opt_or_descr) == OptionDescription:
+            # hidden options
+            if self._cfgimpl_toplevel._cfgimpl_hidden and \
+                (opt_or_descr._is_hidden() or self._cfgimpl_descr._is_hidden()):
+                raise HiddenOptionError("trying to access to a hidden option:"
+                                                           " {0}".format(name))
+            # disabled options
+            if self._cfgimpl_toplevel._cfgimpl_disabled and \
+            (opt_or_descr._is_disabled() or self._cfgimpl_descr._is_disabled()):
+                raise DisabledOptionError("this option is disabled:"
+                                                            " {0}".format(name))
+            # expert options 
+            # XXX currently doesn't look at the group, is it really necessary ?
+            if self._cfgimpl_toplevel._cfgimpl_mode != 'normal':
+                if opt_or_descr.get_mode() != 'normal':
+                    raise ModeOptionError("this option's mode is not normal:"
+                                                            " {0}".format(name))
+
+    def __getattr__(self, name):
+        # attribute access by passing a path, 
+        # for instance getattr(self, "creole.general.family.adresse_ip_eth0") 
+        if '.' in name:
+            homeconfig, name = self._cfgimpl_get_home_by_path(name)
+            return getattr(homeconfig, name)
+        opt_or_descr = getattr(self._cfgimpl_descr, name)
+        # symlink options 
+        if type(opt_or_descr) == SymLinkOption:
+            return getattr(self, opt_or_descr.path)
+        self._validate(name, opt_or_descr)
+        # special attributes
+        if name.startswith('_cfgimpl_'):
+            # if it were in __dict__ it would have been found already
+            return self.__dict__[name]
+            raise AttributeError("%s object has no attribute %s" %
+                                 (self.__class__, name))
+        if name not in self._cfgimpl_values:
+            raise AttributeError("%s object has no attribute %s" %
+                                 (self.__class__, name))
+        if name in self._cfgimpl_value_owners:
+            owner = self._cfgimpl_value_owners[name]
+            if owner in special_owners:
+                value = self._cfgimpl_values[name]
+                if value != None:
+                    if opt_or_descr.is_multi():
+                        if owner == 'fill' and None not in value:
+                            return value
+                    else:
+                        if owner == 'fill' and value != None:
+                            return value
+                result = special_owner_factory(name, owner, 
+                            value=value,
+                            callback=opt_or_descr.getcallback(),
+                            callback_params=opt_or_descr.getcallback_params(),
+                            config=self._cfgimpl_get_toplevel())
+                # this result **shall not** be a list 
+                # for example, [1, 2, 3, None] -> [1, 2, 3, result]
+                if type(result) == list:
+                    raise ConfigError('invalid calculated value returned'
+                        ' for option {0} : shall not be a list'.format(name))
+                if result != None and not opt_or_descr._validate(result):
+                    raise ConfigError('invalid calculated value returned'
+                        ' for option {0}'.format(name))
+                if opt_or_descr.is_multi():
+                    if value == []:
+                        _result = [result]
+                    else:
+                        _result = []
+                        for val in value:
+                            if val == None:
+                                val = result
+                            _result.append(val)
+                else:
+                    _result = result
+                return _result
+        # mandatory options
+        if not isinstance(opt_or_descr, OptionDescription):
+            homeconfig = self._cfgimpl_get_toplevel()
+            mandatory = homeconfig._cfgimpl_mandatory
+            if opt_or_descr.is_mandatory() and mandatory:
+                if self._cfgimpl_values[name] == None\
+                  and opt_or_descr.getdefault() == None:
+                    raise MandatoryError("option: {0} is mandatory " 
+                                          "and shall have a value".format(name))
+        # for multi types with None in the value (ex: ["egg", None, "spam"])
+        # None is replaced by default_multi
+        if not isinstance(opt_or_descr, OptionDescription):
+            if opt_or_descr.is_multi() and None in self._cfgimpl_values[name]:
+                newvalue = []
+                for val in self._cfgimpl_values[name]:
+                    if val is None:
+                        newvalue.append(opt_or_descr.default_multi)
+                    else:
+                        newvalue.append(val)
+                return newvalue
+        return self._cfgimpl_values[name]
+        
+    def __dir__(self):
+        #from_type = dir(type(self))
+        from_dict = list(self.__dict__)
+        extras = list(self._cfgimpl_values)
+        return sorted(set(extras + from_dict))
+
+    def unwrap_from_name(self, name):
+        # didn't have to stoop so low: `self.get()` must be the proper method
+        # **and it is slow**: it recursively searches into the namespaces
+        paths = self.getpaths(allpaths=True)
+        opts = dict([(path, self.unwrap_from_path(path)) for path in paths])
+        all_paths = [p.split(".") for p in self.getpaths()]
+        for pth in all_paths:
+            if name in pth:
+                return opts[".".join(pth)]
+        raise NotFoundError("name: {0} not found".format(name))
+        
+    def unwrap_from_path(self, path):
+        # didn't have to stoop so low, `geattr(self, path)` is much better
+        # **fast**: finds the option directly in the appropriate namespace
+        if '.' in path:
+            homeconfig, path = self._cfgimpl_get_home_by_path(path)
+            return getattr(homeconfig._cfgimpl_descr, path)
+        return getattr(self._cfgimpl_descr, path)
+                                            
+    def __delattr__(self, name):
+        # if you use delattr you are responsible for all bad things happening
+        if name.startswith('_cfgimpl_'):
+            del self.__dict__[name]
+            return
+        self._cfgimpl_value_owners[name] = 'default'
+        opt = getattr(self._cfgimpl_descr, name)
+        if isinstance(opt, OptionDescription):
+            raise AttributeError("can't option subgroup")
+        self._cfgimpl_values[name] = getattr(opt, 'default', None)
+
+    def setoption(self, name, value, who=None):
+        #who is **not necessarily** a owner, because it cannot be a list
+        child = getattr(self._cfgimpl_descr, name)
+        if who == None:
+            if child.is_multi():
+                newowner = [self._cfgimpl_owner for i in range(len(value))] 
+            else:
+                newowner = self._cfgimpl_owner
+        else:
+            if type(child) != SymLinkOption:
+                if child.is_multi():
+                    if type(value) != list:
+                        raise ConfigError("invalid value for option:"
+                                       " {0} that is set to multi".format(name))
+                    newowner = [who for i in range(len(value))]
+                else:
+                    newowner = who 
+        if type(child) != SymLinkOption:
+            if name not in self._cfgimpl_values:
+                raise AttributeError('unknown option %s' % (name,))
+            # special owners, a value with a owner *auto* cannot be changed
+            oldowner = self._cfgimpl_value_owners[child._name]
+            if oldowner == 'auto':
+                if who == 'auto':
+                    raise ConflictConfigError('cannot override value to %s for '
+                                          'option %s' % (value, name))
+            if oldowner == who:
+                oldvalue = getattr(self, name)
+                if oldvalue == value: #or who in ("default",):
+                    return
+            child.setoption(self, value, who)
+            # if the value owner is 'auto', set the option to hidden 
+            if who == 'auto':
+                if not child._is_hidden():
+                    child.hide()
+            if (value is None and who != 'default' and not child.is_multi()):
+                child.setowner(self, 'default')
+                self._cfgimpl_values[name] = child.getdefault()
+            elif (value == [] and who != 'default' and child.is_multi()):
+                child.setowner(self, ['default' for i in range(len(child.getdefault()))])
+                self._cfgimpl_values[name] = child.getdefault()
+            else:         
+                child.setowner(self, newowner)
+        else:
+            homeconfig = self._cfgimpl_get_toplevel()
+            child.setoption(homeconfig, value, who)
+
+    def set(self, **kwargs):
+        all_paths = [p.split(".") for p in self.getpaths(allpaths=True)]
+        for key, value in kwargs.iteritems():
+            key_p = key.split('.')
+            candidates = [p for p in all_paths if p[-len(key_p):] == key_p]
+            if len(candidates) == 1:
+                name = '.'.join(candidates[0])
+                homeconfig, name = self._cfgimpl_get_home_by_path(name)
+                try:
+                    getattr(homeconfig, name)
+                except MandatoryError:
+                    pass
+                except Exception, e:
+                    raise e # HiddenOptionError or DisabledOptionError
+                homeconfig.setoption(name, value, self._cfgimpl_owner)
+            elif len(candidates) > 1:
+                raise AmbigousOptionError(
+                    'more than one option that ends with %s' % (key, ))
+            else:
+                raise NoMatchingOptionFound(
+                    'there is no option that matches %s' 
+                    ' or the option is hidden or disabled'% (key, ))
+
+    def get(self, name):
+        paths = self.getpaths(allpaths=True)
+        pathsvalues = []
+        for path in paths:
+            pathname = path.split('.')[-1]
+            if pathname == name:
+                try:
+                    value = getattr(self, path)            
+                    return value 
+                except Exception, e:
+                    raise e
+        raise NotFoundError("option {0} not found in config".format(name))                    
+
+    def _cfgimpl_get_home_by_path(self, path):
+        """returns tuple (config, name)"""
+        path = path.split('.')
+        
+        for step in path[:-1]:
+            self = getattr(self, step)
+        return self, path[-1]
+
+    def _cfgimpl_get_toplevel(self):
+        while self._cfgimpl_parent is not None:
+            self = self._cfgimpl_parent
+        return self
+
+    def cfgimpl_previous_value(self, path):
+        home, name = self._cfgimpl_get_home_by_path(path)
+        return home._cfgimpl_previous_values[name]
+    
+    def get_previous_value(self, name):
+        return self._cfgimpl_previous_values[name]
+             
+    def add_warning(self, warning):
+        self._cfgimpl_get_toplevel()._cfgimpl_warnings.append(warning)
+
+    def get_warnings(self):
+        return self._cfgimpl_get_toplevel()._cfgimpl_warnings
+    # ____________________________________________________________
+    # freeze and read-write statuses
+    def cfgimpl_freeze(self):
+        rootconfig = self._cfgimpl_get_toplevel()
+        rootconfig._cfgimpl_frozen = True
+        self._cfgimpl_frozen = True
+
+    def cfgimpl_unfreeze(self):
+        rootconfig = self._cfgimpl_get_toplevel()
+        rootconfig._cfgimpl_frozen = False
+        self._cfgimpl_frozen = False
+
+    def is_frozen(self):
+        # it should be the same value as self._cfgimpl_frozen...
+        rootconfig = self._cfgimpl_get_toplevel()
+        return rootconfig.__dict__['_cfgimpl_frozen']
+
+    def cfgimpl_read_only(self):
+        # hung up on freeze, hidden and disabled concepts 
+        self.cfgimpl_freeze()
+        rootconfig = self._cfgimpl_get_toplevel()
+        rootconfig._cfgimpl_hidden = False
+        rootconfig._cfgimpl_disabled = True
+        rootconfig._cfgimpl_mandatory = True
+
+    def cfgimpl_set_mode(self, mode):
+        # normal or expert mode
+        rootconfig = self._cfgimpl_get_toplevel()
+        if mode not in modes:
+            raise ConfigError("mode {0} not available".format(mode))
+        rootconfig._cfgimpl_mode = mode
+    
+    def cfgimpl_read_write(self):
+        # hung up on freeze, hidden and disabled concepts
+        self.cfgimpl_unfreeze()
+        rootconfig = self._cfgimpl_get_toplevel()
+        rootconfig._cfgimpl_hidden = True
+        rootconfig._cfgimpl_disabled = False
+        rootconfig._cfgimpl_mandatory = False
+    # ____________________________________________________________
+    def getkey(self):
+        return self._cfgimpl_descr.getkey(self)
+
+    def __hash__(self):
+        return hash(self.getkey())
+
+    def __eq__(self, other):
+        return self.getkey() == other.getkey()
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __iter__(self):
+        # iteration only on Options (not OptionDescriptions)
+        for child in self._cfgimpl_descr._children:
+            if isinstance(child, Option):
+                try:
+                    yield child._name, getattr(self, child._name)
+                except:
+                    pass # hidden, disabled option group
+
+    def iter_groups(self, group_type=None):
+        "iteration on OptionDescriptions"
+        if group_type == None:
+            groups = group_types
+        else:
+            if group_type not in group_types:
+                raise TypeError("Unknown group_type: {0}".format(group_type))
+            groups = [group_type]
+        for child in self._cfgimpl_descr._children:
+            if isinstance(child, OptionDescription):
+                    try:
+                        if child.get_group_type() in groups: 
+                            yield child._name, getattr(self, child._name)
+                    except:
+                        pass # hidden, disabled option
+                    
+    def __str__(self, indent=""):
+        lines = []
+        children = [(child._name, child)
+                    for child in self._cfgimpl_descr._children]
+        children.sort()
+        for name, child in children:
+            if self._cfgimpl_value_owners.get(name, None) == 'default':
+                continue
+            value = getattr(self, name)
+            if isinstance(value, Config):
+                substr = value.__str__(indent + "    ")
+            else:
+                substr = "%s    %s = %s" % (indent, name, value)
+            if substr:
+                lines.append(substr)
+        if indent and not lines:
+            return ''   # hide subgroups with all default values
+        lines.insert(0, "%s[%s]" % (indent, self._cfgimpl_descr._name,))
+        return '\n'.join(lines)
+
+    def getpaths(self, include_groups=False, allpaths=False):
+        """returns a list of all paths in self, recursively, taking care of 
+        the context (hidden/disabled)
+        """
+        paths = []
+        for path in self._cfgimpl_descr.getpaths(include_groups=include_groups):
+            try: 
+                value = getattr(self, path)
+            except Exception, e:
+                if not allpaths:
+                    pass # hidden or disabled option
+                else:
+                    paths.append(path) # hidden or disabled option added
+            else:
+                paths.append(path)
+        return paths 
+        
+def make_dict(config, flatten=False):
+    paths = config.getpaths()
+    pathsvalues = []
+    for path in paths:
+        if flatten:
+            pathname = path.split('.')[-1]
+        else:
+            pathname = path
+        try:
+            value = getattr(config, path)            
+            pathsvalues.append((pathname, value))      
+        except:
+            pass # this just a hidden or disabled option  
+    options = dict(pathsvalues)
+    return options
+# ____________________________________________________________
+
diff --git a/src/doc/Makefile b/src/doc/Makefile
new file mode 100644 (file)
index 0000000..f8c7cfe
--- /dev/null
@@ -0,0 +1,26 @@
+SRC=$(wildcard *.txt)
+HTMLFRAGMENT=$(addsuffix .html, $(basename $(SRC)))
+
+.SUFFIXES:
+
+.PHONY: all clean
+
+all: html code epydoc
+#      make -C ./build/code all
+#      make -C ./build/test all
+#      make -C ./build all
+               
+html: $(HTMLFRAGMENT)
+
+%.html: %.txt    
+       ./rst2html.py --stylesheet ./build/style.css $< > ./build/$@
+
+code:
+       ./code2html
+
+epydoc:
+       ./epydoc.sh
+
+clean:
+       make -C ./build clean
+       
diff --git a/src/doc/build/Makefile b/src/doc/build/Makefile
new file mode 100644 (file)
index 0000000..a825b9e
--- /dev/null
@@ -0,0 +1,7 @@
+.PHONY: clean
+.SUFFIXES:
+
+clean:
+       rm -f *.html
+       rm -f api/*.html
+       make -C ./pydoc/ clean
diff --git a/src/doc/build/api/Readme b/src/doc/build/api/Readme
new file mode 100644 (file)
index 0000000..8623c0e
--- /dev/null
@@ -0,0 +1 @@
+API's directory
diff --git a/src/doc/build/architecture.dia b/src/doc/build/architecture.dia
new file mode 100644 (file)
index 0000000..35adb7e
Binary files /dev/null and b/src/doc/build/architecture.dia differ
diff --git a/src/doc/build/architecture.png b/src/doc/build/architecture.png
new file mode 100644 (file)
index 0000000..fecefa0
Binary files /dev/null and b/src/doc/build/architecture.png differ
diff --git a/src/doc/build/default.css b/src/doc/build/default.css
new file mode 100644 (file)
index 0000000..8625c0e
--- /dev/null
@@ -0,0 +1,1080 @@
+body,body.editor,body.body {
+    font: 110% "Times New Roman", Arial, Verdana, Helvetica, serif;
+    background: White;
+    color: Black;
+}
+
+a, a.reference {
+       text-decoration: none; 
+}
+a[href]:hover { text-decoration: underline; }
+
+img {
+    border: none;
+       vertical-align: middle;
+}
+
+p, div.text {
+    text-align: left;
+    line-height: 1.5em;
+    margin: 0.5em 0em 0em 0em;
+}
+
+
+
+p a:active {
+       color: Red;
+    background-color: transparent;
+}
+
+p img {
+    border: 0;
+    margin: 0;
+}
+
+img.inlinephoto {
+    padding: 0;
+    padding-right: 1em;
+    padding-top: 0.7em;
+    float: left;
+}
+
+hr {
+    clear: both;
+    height: 1px;
+    color: #8CACBB;
+    background-color: transparent;
+}
+
+
+ul { 
+    line-height: 1.5em;
+    /*list-style-image: url("bullet.gif"); */
+    margin-left: 1.5em;
+    padding:0;
+}
+
+ol {
+    line-height: 1.5em;
+    margin-left: 1.5em;
+    padding:0;
+}
+
+ul a, ol a {
+    text-decoration: underline;
+}
+
+dl {
+}
+
+dt {
+    font-weight: bold;    
+}
+
+dd {
+    line-height: 1.5em;
+    margin-bottom: 1em;
+}
+
+blockquote {
+    font-family: Times, "Times New Roman", serif;
+    font-style: italic;
+    font-size: 120%;
+}
+
+code {
+    color: Black;
+    /*background-color: #dee7ec;*/
+    background-color: #cccccc;
+}
+
+pre {
+    padding: 1em;
+    border: 1px solid #8cacbb;
+    color: Black;
+    background-color: #dee7ec;
+    background-color: #cccccc;
+    overflow: auto;
+}
+
+
+.netscape4 {
+    display: none;
+}
+
+/* main page styles */
+
+/*a[href]:hover { color: black; text-decoration: underline; }
+a[href]:link { color: black; text-decoration: underline; }
+a[href] { color: black; text-decoration: underline; }
+*/
+
+span.menu_selected {
+       color: black;
+       font: 140% Verdana, Helvetica, Arial, sans-serif;
+       text-decoration: none;
+    padding-right: 0.3em;
+    background-color: #cccccc;
+}
+
+
+a.menu {
+       /*color: #3ba6ec; */
+       font: 140% Verdana, Helvetica, Arial, sans-serif;
+       text-decoration: none;
+    padding-right: 0.3em;
+}
+
+a.menu[href]:visited, a.menu[href]:link{
+       /*color: #3ba6ec; */
+       font: 140% Verdana, Helvetica, Arial, sans-serif;
+       text-decoration: none;
+}
+
+a.menu[href]:hover {
+       /*color: black;*/
+}
+
+div.project_title{
+  /*border-spacing: 20px;*/
+  font: 160% Verdana, Helvetica, Arial, sans-serif;
+  color: #3ba6ec; 
+  vertical-align: middle;
+  padding-bottom: 0.3em;
+}
+
+a.wikicurrent {
+  font: 100% Verdana, Helvetica, Arial, sans-serif;
+  color: #3ba6ec; 
+  vertical-align: middle;
+}
+
+
+table.body {
+  border: 0;
+  /*padding: 0;
+  border-spacing: 0px;
+  border-collapse: separate;
+  */
+}
+
+td.page-header-left {
+  padding: 5px;
+  /*border-bottom: 1px solid #444444;*/
+}
+
+td.page-header-top {
+  padding: 0;
+    
+  /*border-bottom: 1px solid #444444;*/
+}
+
+td.sidebar {
+  padding: 1 0 0 1;
+}
+
+td.sidebar p.classblock {
+  padding: 0 5 0 5;
+  margin: 1 1 1 1;
+  border: 1px solid #444444;
+  background-color: #eeeeee;
+}
+
+td.sidebar p.userblock {
+  padding: 0 5 0 5;
+  margin: 1 1 1 1;
+  border: 1px solid #444444;
+  background-color: #eeeeff;
+}
+
+td.content {
+  padding: 1 5 1 5;
+  vertical-align: top;
+  width: 100%;
+}
+
+p.ok-message {
+  background-color: #22bb22;
+  padding: 5 5 5 5;
+  color: white;
+  font-weight: bold;
+}
+p.error-message {
+  background-color: #bb2222;
+  padding: 5 5 5 5;
+  color: white;
+  font-weight: bold;
+}
+
+p:first-child { 
+  margin: 0 ;
+  padding: 0;
+}
+
+/* style for forms */
+table.form {
+  padding: 2;
+  border-spacing: 0px;
+  border-collapse: separate;
+}
+
+table.form th {
+  color: #333388;
+  text-align: right;
+  vertical-align: top;
+  font-weight: normal;
+}
+table.form th.header {
+  font-weight: bold;
+  background-color: #eeeeff;
+  text-align: left;
+}
+
+table.form th.required {
+  font-weight: bold;
+}
+
+table.form td {
+  color: #333333;
+  empty-cells: show;
+  vertical-align: top;
+}
+
+table.form td.optional {
+  font-weight: bold;
+  font-style: italic;
+}
+
+table.form td.html {
+  color: #777777;
+}
+
+/* style for lists */
+table.list {
+  border-spacing: 0px;
+  border-collapse: separate;
+  vertical-align: top;
+  padding-top: 0;
+  width: 100%;
+}
+
+table.list th {
+  padding: 0 4 0 4;
+  color: #404070;
+  background-color: #eeeeff;
+  border-right: 1px solid #404070;
+  border-top: 1px solid #404070;
+  border-bottom: 1px solid #404070;
+  vertical-align: top;
+  empty-cells: show;
+}
+table.list th a[href]:hover { color: #404070 }
+table.list th a[href]:link { color: #404070 }
+table.list th a[href] { color: #404070 }
+table.list th.group {
+  background-color: #f4f4ff;
+  text-align: center;
+  font-size: 120%;
+}
+
+table.list td {
+  padding: 0 4 0 4;
+  border: 0 2 0 2;
+  border-right: 1px solid #404070;
+  color: #404070;
+  background-color: white;
+  vertical-align: top;
+  empty-cells: show;
+}
+
+table.list tr.normal td {
+  background-color: white;
+  white-space: nowrap;
+}
+
+table.list tr.alt td {
+  background-color: #efefef;
+  white-space: nowrap;
+}
+
+table.list td:first-child {
+  border-left: 1px solid #404070;
+  border-right: 1px solid #404070;
+}
+
+table.list th:first-child {
+  border-left: 1px solid #404070;
+  border-right: 1px solid #404070;
+}
+
+table.list tr.navigation th {
+  text-align: right;
+}
+table.list tr.navigation th:first-child {
+  border-right: none;
+  text-align: left;
+}
+
+
+/* style for message displays */
+table.messages {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.messages th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.messages th {
+  font-weight: bold;
+  color: black;
+  text-align: left;
+  border-bottom: 1px solid #afafaf;
+}
+
+table.messages td {
+  font-family: monospace;
+  background-color: #efefef;
+  border-bottom: 1px solid #afafaf;
+  color: black;
+  empty-cells: show;
+  border-right: 1px solid #afafaf;
+  vertical-align: top;
+  padding: 2 5 2 5;
+}
+
+table.messages td:first-child {
+  border-left: 1px solid #afafaf;
+  border-right: 1px solid #afafaf;
+}
+
+/* style for file displays */
+table.files {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.files th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.files th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+}
+
+table.files td {
+  font-family: monospace;
+  empty-cells: show;
+}
+
+/* style for history displays */
+table.history {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.history th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+  font-size: 100%;
+}
+
+table.history th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+  font-size: 90%;
+}
+
+table.history td {
+  font-size: 90%;
+  vertical-align: top;
+  empty-cells: show;
+}
+
+
+/* style for class list */
+table.classlist {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.classlist th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.classlist th {
+  font-weight: bold;
+  text-align: left;
+}
+
+
+/* style for class help display */
+table.classhelp {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.classhelp th {
+  font-weight: bold;
+  text-align: left;
+  color: #707040;
+}
+
+table.classhelp td {
+  padding: 2 2 2 2;
+  border: 1px solid black;
+  text-align: left;
+  vertical-align: top;
+  empty-cells: show;
+}
+
+
+/* style for "other" displays */
+table.otherinfo {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.otherinfo th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.otherinfo th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+}
+
+input {
+    border: 1px solid #8cacbb;
+    color: Black;
+    background-color: white;
+    vertical-align: middle;
+    margin-bottom: 1px; /* IE bug fix */
+    padding: 0.1em;
+}
+
+select {
+    border: 1px solid #8cacbb;
+    color: Black;
+    background-color: white;
+    vertical-align: middle;
+    margin-bottom: 1px; /* IE bug fix */
+    padding: 0.1em;
+}
+
+
+a.nonexistent {
+    color: #FF2222;
+}
+a.nonexistent:visited {
+    color: #FF2222;
+}
+a.external {
+    color: #AA6600;
+}
+
+/*
+dl,ul,ol {
+    margin-top: 1pt;
+}
+tt,pre {
+    font-family: Lucida Console,Courier New,Courier,monotype;
+    font-size: 12pt;
+}
+pre.code {
+    margin-top: 8pt;
+    margin-bottom: 8pt;
+    background-color: #FFFFEE;
+    white-space:pre;
+    border-style:solid;
+    border-width:1pt;
+    border-color:#999999;
+    color:#111111;
+    padding:5px;
+    width:100%;
+}
+*/
+div.diffold {
+    background-color: #FFFF80;
+    border-style:none;
+    border-width:thin;
+    width:100%;
+}
+div.diffnew {
+    background-color: #80FF80;
+    border-style:none;
+    border-width:thin;
+    width:100%;
+}
+div.message {
+    margin-top: 6pt;
+    background-color: #E8FFE8;
+    border-style:solid;
+    border-width:1pt;
+    border-color:#999999;
+    color:#440000;
+    padding:5px;
+    width:100%;
+}
+strong.highlight {
+    background-color: #FFBBBB;
+/* as usual, NetScape fucks up with innocent CSS
+    border-color: #FFAAAA;
+    border-style: solid;
+    border-width: 1pt;
+*/
+}
+
+table.navibar {
+    background-color: #C8C8C8;
+    border-spacing: 3px;
+}
+td.navibar {
+    background-color: #E8E8E8;
+    vertical-align: top;
+    text-align: right;
+    padding: 0px;
+}
+
+div.pagename {
+    font-size: 140%;
+    color: blue;
+    text-align: center;
+    font-weight: bold;
+    background-color: white;
+    padding: 0 ;
+}
+
+a.wikiaction, input.wikiaction {
+    color: black; 
+    text-decoration: None;
+    text-align: center;
+    color: black;
+    /*border: 1px solid #3ba6ec; */
+    margin: 4px;
+    padding: 5;
+    padding-bottom: 0;
+    white-space: nowrap;
+}
+
+a.wikiaction[href]:hover { 
+       color: black; 
+       text-decoration: none; 
+       /*background-color: #dddddd; */
+}
+
+span.wikiuserpref {
+    padding-top: 1em;
+    font-size: 120%;
+}
+
+div.wikitrail {
+    vertical-align: bottom;
+    /*font-size: -1;*/
+    padding-top: 1em;
+    display: none;
+}
+
+div.wikiaction {
+    vertical-align: middle;
+    /*border-bottom: 1px solid #8cacbb;*/
+    padding-bottom:1em;
+    text-align: left;
+    width: 100%;
+}
+
+div.wikieditmenu {
+    text-align: right;
+}
+
+form.wikiedit {
+    border: 1px solid #8cacbb;
+    background-color: #f0f0f0;
+    background-color: #fabf00;
+    padding: 1em;
+    padding-right: 0em;
+}
+
+div.legenditem {
+    padding-top: 0.5em;
+    padding-left: 0.3em;
+}
+
+span.wikitoken {
+   background-color: #eeeeee;
+}
+    
+
+div#contentspace h1:first-child, div.heading:first-child { 
+  padding-top: 0;
+  margin-top: 0;
+}
+div#contentspace h2:first-child { 
+  padding-top: 0;
+  margin-top: 0;
+}
+
+/* heading and paragraph text */
+
+div.heading, h1 {
+    font-family: Verdana, Helvetica, Arial, sans-serif;
+    background-color: #58b3ef;
+    background-color: #FFFFFF; 
+    /*color: #4893cf;*/
+    color: black;
+    padding-top: 1.0em;
+    padding-bottom:0.2em;
+    text-align: left;
+    margin-top: 0em; 
+    /*margin-bottom:8pt;*/
+    font-weight: bold;
+    font-size: 115%;
+    border-bottom: 1px solid #8CACBB;
+}
+
+
+h1, h2, h3, h4, h5, h6 {
+    color: orange;
+    clear: left;
+    font: 100% Verdana, Helvetica, Arial, sans-serif;
+    margin: 0;
+    padding-left: 0em;
+    padding-top: 1em;
+    padding-bottom: 0.2em;
+    /*border-bottom: 1px solid #8CACBB;*/
+}
+/* h1,h2 { padding-top: 0; }*/
+
+
+h1 { font-size: 145%; }
+h2 { font-size: 135%; }
+h3 { font-size: 125%; }
+h4 { font-size: 120%; }
+h5 { font-size: 110%; }
+h6 { font-size: 80%; }
+
+h1 a { text-decoration: None;}
+
+div.exception {
+  background-color: #bb2222;
+  padding: 5 5 5 5;
+  color: white;
+  font-weight: bold;
+}
+pre.exception {
+    font-size: 110%;
+    padding: 1em;
+    border: 1px solid #8cacbb;
+    color: Black;
+    background-color: #dee7ec;
+    background-color: #cccccc;
+}
+
+/* defines for navgiation bar (documentation) */
+
+
+div.direntry {
+    padding-top: 0.3em;
+    padding-bottom: 0.3em;
+    margin-right: 1em;
+    font-weight: bold;
+    background-color: #dee7ec;
+    font-size: 110%;
+}
+
+div.fileentry {
+    font-family: Verdana, Helvetica, Arial, sans-serif;
+    padding-bottom: 0.3em;
+    white-space: nowrap;
+    line-height: 150%;
+}
+
+a.fileentry {
+    white-space: nowrap;
+}
+
+
+span.left {
+    text-align: left;
+}
+span.right {
+    text-align: right;
+}
+
+div.navbar {
+  /*margin: 0;*/
+  font-size: 80% /*smaller*/;
+  font-weight: bold;
+  text-align: left;
+  /* position: fixed; */
+  top: 100pt;
+  left: 0pt; /*  auto; */
+  width: 120pt;
+  /* right: auto;
+  right: 0pt;  2em; */
+}
+
+
+div.history a {
+    /* font-size: 70%; */
+}
+
+div.wikiactiontitle { 
+  font-weight: bold;
+}
+
+/*  REST  defines */
+
+div.document {
+    margin: 0;
+}
+
+h1.title {
+    margin: 0;
+    margin-bottom: 0.5em;
+}
+
+td.toplist {
+    vertical-align: top;
+}
+
+img#pyimg {
+    position: absolute;
+    top: 4px;
+    left: 4px;
+}
+    
+div#navspace {
+    position: absolute;
+    top: 130px;
+    left: 11px;
+    font-size: 100%;
+    width: 150px;
+    overflow: hidden; /* scroll;  */
+}
+
+div#metaspace {
+    position: absolute;
+    top: 40px;
+    left: 170px;
+}
+
+div#errorline {
+    position: relative;
+    top: 5px; 
+    float: right; 
+}
+
+div#contentspace {
+    position: absolute;
+       /* font: 120% "Times New Roman", serif;*/
+    font: 110% Verdana, Helvetica, Arial, sans-serif;
+    top: 130px;
+    left: 170px;
+    margin-right: 5px;
+}
+
+div#menubar {
+/*    width: 400px; */
+    float: left;
+}
+
+/* for the documentation page */
+div#docinfoline {
+  position: relative;
+  top: 5px; 
+  left: 0px;
+
+  /*background-color: #dee7ec; */
+  padding: 5pt; 
+  padding-bottom: 1em; 
+  color: black;
+  /*border-width: 1pt;
+  border-style: solid;*/
+
+}
+
+div#docnavlist {
+  /*background-color: #dee7ec; */
+  padding: 5pt; 
+  padding-bottom: 2em; 
+  color: black;
+  border-width: 1pt;
+  /*border-style: solid;*/
+}
+
+
+/* text markup */
+
+div.listtitle {
+    color: Black;
+    clear: left;
+    font: 120% Verdana, Helvetica, Arial, sans-serif;
+    margin: 0;
+    padding-left: 0em;
+    padding-top: 0em;
+    padding-bottom: 0.2em;
+    margin-right: 0.5em;
+    border-bottom: 1px solid #8CACBB;
+}
+
+div.actionbox h3 { 
+  padding-top: 0;
+  padding-right: 0.5em;
+  padding-left: 0.5em;
+  background-color: #fabf00;
+  text-align: center;
+  border: 1px solid black; /* 8cacbb; */
+}
+
+div.actionbox a { 
+  display: block;
+  padding-bottom: 0.5em;
+  padding-top: 0.5em;
+  margin-left: 0.5em;
+}
+
+div.actionbox a.history { 
+  display: block;
+  padding-bottom: 0.5em;
+  padding-top: 0.5em;
+  margin-left: 0.5em;
+  font-size: 90%; 
+}
+
+div.actionbox { 
+  margin-bottom: 2em;
+  padding-bottom: 1em;
+  overflow: hidden; /* scroll;  */
+}
+
+/* taken from docutils (oh dear, a bit senseless) */
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:date: $Date: 2003/01/22 22:26:48 $
+:version: $Revision: 1.29 $
+:copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+*/
+/*
+.first {
+  margin-top: 0 }
+
+.last {
+  margin-bottom: 0 }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+dd {
+  margin-bottom: 0.5em }
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.attention, div.caution, div.danger, div.error, div.hint,
+div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.hint p.admonition-title, div.important p.admonition-title,
+div.note p.admonition-title, div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  font-size: smaller }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.title {
+  text-align: center ;
+  color: orange}
+
+h2.subtitle {
+  color: orange;
+  text-align: center }
+
+hr {
+  width: 75% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.option-argument {
+  font-style: italic }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+table {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.citation {
+  border-left: solid thin gray ;
+  padding-left: 0.5ex }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.footnote {
+  border-left: solid thin black ;
+  padding-left: 0.5ex }
+
+td, th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+th.docinfo-name, th.field-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap }
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+  font-size: 100% }
+
+tt {
+  background-color: #eeeeee }
+
+ul.auto-toc {
+  list-style-type: none }
+*/
+
+div.section {
+  margin-top: 1.0em ;
+}    
diff --git a/src/doc/build/docutils.css b/src/doc/build/docutils.css
new file mode 100644 (file)
index 0000000..f03e03d
--- /dev/null
@@ -0,0 +1,255 @@
+.first {
+  margin-top: 0 ! important }
+
+.last {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: inherit }
+
+blockquote.epigraph {
+  margin: 2em 5em }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+dl.docutils dt {
+  font-weight: bold }
+
+dl dt { line-height: 150% }
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.document {
+  width: 600px ;
+  margin-left: 5em ;
+  margin-right: 5em }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin-left: 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1, h2, h3, h4, h5 {
+  font-family: sans-serif ;
+  line-height: 150% ;
+  color: orange} /* #666 } */
+
+h1.title {
+  text-align: center
+  }
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  font-size: small ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.option-argument {
+  font-style: italic }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+table.citation {
+  border-left: solid thin gray }
+
+table.docinfo {
+  /* float: right ; */
+  margin: 2em 4em ;
+  color: #666 }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+th.docinfo-name, th.field-name {
+  font-weight: bold ;
+  text-align: right ;
+  white-space: nowrap }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+tt.docutils {
+  background-color: #eeeeee }
+
+ul.auto-toc {
+  list-style-type: none }
+
diff --git a/src/doc/build/pydoc/Makefile b/src/doc/build/pydoc/Makefile
new file mode 100644 (file)
index 0000000..612cb8f
--- /dev/null
@@ -0,0 +1,5 @@
+.PHONY: clean
+.SUFFIXES:
+
+clean:
+       rm -f *.html
diff --git a/src/doc/build/pydoc/api-objects.txt b/src/doc/build/pydoc/api-objects.txt
new file mode 100644 (file)
index 0000000..c9ed6ab
--- /dev/null
@@ -0,0 +1,377 @@
+tiramisu       tiramisu-module.html
+tiramisu.__package__   tiramisu-module.html#__package__
+tiramisu.autolib       tiramisu.autolib-module.html
+tiramisu.autolib.calculate     tiramisu.autolib-module.html#calculate
+tiramisu.autolib.special_owners        tiramisu.autolib-module.html#special_owners
+tiramisu.autolib.__package__   tiramisu.autolib-module.html#__package__
+tiramisu.autolib.calc_factory  tiramisu.autolib-module.html#calc_factory
+tiramisu.autolib.special_owner_factory tiramisu.autolib-module.html#special_owner_factory
+tiramisu.basetype      tiramisu.basetype-module.html
+tiramisu.basetype.modes        tiramisu.basetype-module.html#modes
+tiramisu.basetype.__package__  tiramisu.basetype-module.html#__package__
+tiramisu.config        tiramisu.config-module.html
+tiramisu.config.__package__    tiramisu.config-module.html#__package__
+tiramisu.config.special_owner_factory  tiramisu.autolib-module.html#special_owner_factory
+tiramisu.config.make_dict      tiramisu.config-module.html#make_dict
+tiramisu.config.apply_requires tiramisu.option-module.html#apply_requires
+tiramisu.error tiramisu.error-module.html
+tiramisu.error.__package__     tiramisu.error-module.html#__package__
+tiramisu.option        tiramisu.option-module.html
+tiramisu.option.__package__    tiramisu.option-module.html#__package__
+tiramisu.option.reverse_actions        tiramisu.option-module.html#reverse_actions
+tiramisu.option.group_types    tiramisu.option-module.html#group_types
+tiramisu.option.apply_requires tiramisu.option-module.html#apply_requires
+tiramisu.option.available_actions      tiramisu.option-module.html#available_actions
+tiramisu.tool  tiramisu.tool-module.html
+tiramisu.tool.apply_requires   tiramisu.option-module.html#apply_requires
+tiramisu.tool.__package__      tiramisu.tool-module.html#__package__
+tiramisu.tool.reverse_from_paths       tiramisu.tool-module.html#reverse_from_paths
+tiramisu.basetype.DisabledBaseType     tiramisu.basetype.DisabledBaseType-class.html
+tiramisu.basetype.DisabledBaseType.enable      tiramisu.basetype.DisabledBaseType-class.html#enable
+tiramisu.basetype.DisabledBaseType.disable     tiramisu.basetype.DisabledBaseType-class.html#disable
+tiramisu.basetype.DisabledBaseType.disabled    tiramisu.basetype.DisabledBaseType-class.html#disabled
+tiramisu.basetype.DisabledBaseType._is_disabled        tiramisu.basetype.DisabledBaseType-class.html#_is_disabled
+tiramisu.basetype.HiddenBaseType       tiramisu.basetype.HiddenBaseType-class.html
+tiramisu.basetype.HiddenBaseType.hide  tiramisu.basetype.HiddenBaseType-class.html#hide
+tiramisu.basetype.HiddenBaseType.show  tiramisu.basetype.HiddenBaseType-class.html#show
+tiramisu.basetype.HiddenBaseType._is_hidden    tiramisu.basetype.HiddenBaseType-class.html#_is_hidden
+tiramisu.basetype.HiddenBaseType.hidden        tiramisu.basetype.HiddenBaseType-class.html#hidden
+tiramisu.basetype.ModeBaseType tiramisu.basetype.ModeBaseType-class.html
+tiramisu.basetype.ModeBaseType.set_mode        tiramisu.basetype.ModeBaseType-class.html#set_mode
+tiramisu.basetype.ModeBaseType.mode    tiramisu.basetype.ModeBaseType-class.html#mode
+tiramisu.basetype.ModeBaseType.get_mode        tiramisu.basetype.ModeBaseType-class.html#get_mode
+tiramisu.config.Config tiramisu.config.Config-class.html
+tiramisu.config.Config.set     tiramisu.config.Config-class.html#set
+tiramisu.config.Config.unwrap_from_name        tiramisu.config.Config-class.html#unwrap_from_name
+tiramisu.config.Config.cfgimpl_unfreeze        tiramisu.config.Config-class.html#cfgimpl_unfreeze
+tiramisu.config.Config._validate       tiramisu.config.Config-class.html#_validate
+tiramisu.config.Config.__str__ tiramisu.config.Config-class.html#__str__
+tiramisu.config.Config.cfgimpl_set_owner       tiramisu.config.Config-class.html#cfgimpl_set_owner
+tiramisu.config.Config.getkey  tiramisu.config.Config-class.html#getkey
+tiramisu.config.Config._cfgimpl_mandatory      tiramisu.config.Config-class.html#_cfgimpl_mandatory
+tiramisu.config.Config.unwrap_from_path        tiramisu.config.Config-class.html#unwrap_from_path
+tiramisu.config.Config.__init__        tiramisu.config.Config-class.html#__init__
+tiramisu.config.Config._validate_duplicates    tiramisu.config.Config-class.html#_validate_duplicates
+tiramisu.config.Config._cfgimpl_owner  tiramisu.config.Config-class.html#_cfgimpl_owner
+tiramisu.config.Config.__getattr__     tiramisu.config.Config-class.html#__getattr__
+tiramisu.config.Config._cfgimpl_hidden tiramisu.config.Config-class.html#_cfgimpl_hidden
+tiramisu.config.Config.iter_groups     tiramisu.config.Config-class.html#iter_groups
+tiramisu.config.Config.get_warnings    tiramisu.config.Config-class.html#get_warnings
+tiramisu.config.Config.cfgimpl_update  tiramisu.config.Config-class.html#cfgimpl_update
+tiramisu.config.Config.override        tiramisu.config.Config-class.html#override
+tiramisu.config.Config.setoption       tiramisu.config.Config-class.html#setoption
+tiramisu.config.Config.__ne__  tiramisu.config.Config-class.html#__ne__
+tiramisu.config.Config.cfgimpl_disable tiramisu.config.Config-class.html#cfgimpl_disable
+tiramisu.config.Config.__hash__        tiramisu.config.Config-class.html#__hash__
+tiramisu.config.Config.get     tiramisu.config.Config-class.html#get
+tiramisu.config.Config._cfgimpl_get_toplevel   tiramisu.config.Config-class.html#_cfgimpl_get_toplevel
+tiramisu.config.Config._cfgimpl_build  tiramisu.config.Config-class.html#_cfgimpl_build
+tiramisu.config.Config.__setattr__     tiramisu.config.Config-class.html#__setattr__
+tiramisu.config.Config.is_frozen       tiramisu.config.Config-class.html#is_frozen
+tiramisu.config.Config.__iter__        tiramisu.config.Config-class.html#__iter__
+tiramisu.config.Config._cfgimpl_toplevel       tiramisu.config.Config-class.html#_cfgimpl_toplevel
+tiramisu.config.Config._cfgimpl_get_home_by_path       tiramisu.config.Config-class.html#_cfgimpl_get_home_by_path
+tiramisu.config.Config._cfgimpl_mode   tiramisu.config.Config-class.html#_cfgimpl_mode
+tiramisu.config.Config.cfgimpl_read_write      tiramisu.config.Config-class.html#cfgimpl_read_write
+tiramisu.config.Config.__eq__  tiramisu.config.Config-class.html#__eq__
+tiramisu.config.Config.__dir__ tiramisu.config.Config-class.html#__dir__
+tiramisu.config.Config.getpaths        tiramisu.config.Config-class.html#getpaths
+tiramisu.config.Config.cfgimpl_set_mode        tiramisu.config.Config-class.html#cfgimpl_set_mode
+tiramisu.config.Config.cfgimpl_hide    tiramisu.config.Config-class.html#cfgimpl_hide
+tiramisu.config.Config.cfgimpl_show    tiramisu.config.Config-class.html#cfgimpl_show
+tiramisu.config.Config._cfgimpl_frozen tiramisu.config.Config-class.html#_cfgimpl_frozen
+tiramisu.config.Config._cfgimpl_disabled       tiramisu.config.Config-class.html#_cfgimpl_disabled
+tiramisu.config.Config.__delattr__     tiramisu.config.Config-class.html#__delattr__
+tiramisu.config.Config.add_warning     tiramisu.config.Config-class.html#add_warning
+tiramisu.config.Config.cfgimpl_enable  tiramisu.config.Config-class.html#cfgimpl_enable
+tiramisu.config.Config.cfgimpl_freeze  tiramisu.config.Config-class.html#cfgimpl_freeze
+tiramisu.config.Config.cfgimpl_read_only       tiramisu.config.Config-class.html#cfgimpl_read_only
+tiramisu.error.AmbigousOptionError     tiramisu.error.AmbigousOptionError-class.html
+tiramisu.error.ConfigError     tiramisu.error.ConfigError-class.html
+tiramisu.error.ConflictConfigError     tiramisu.error.ConflictConfigError-class.html
+tiramisu.error.DisabledOptionError     tiramisu.error.DisabledOptionError-class.html
+tiramisu.error.HiddenOptionError       tiramisu.error.HiddenOptionError-class.html
+tiramisu.error.MandatoryError  tiramisu.error.MandatoryError-class.html
+tiramisu.error.MethodCallError tiramisu.error.MethodCallError-class.html
+tiramisu.error.ModeOptionError tiramisu.error.ModeOptionError-class.html
+tiramisu.error.NoMatchingOptionFound   tiramisu.error.NoMatchingOptionFound-class.html
+tiramisu.error.NotFoundError   tiramisu.error.NotFoundError-class.html
+tiramisu.error.RequiresError   tiramisu.error.RequiresError-class.html
+tiramisu.error.SpecialOwnersError      tiramisu.error.SpecialOwnersError-class.html
+tiramisu.option.ArbitraryOption        tiramisu.option.ArbitraryOption-class.html
+tiramisu.basetype.HiddenBaseType.show  tiramisu.basetype.HiddenBaseType-class.html#show
+tiramisu.option.ArbitraryOption._validate      tiramisu.option.ArbitraryOption-class.html#_validate
+tiramisu.option.Option.getkey  tiramisu.option.Option-class.html#getkey
+tiramisu.basetype.DisabledBaseType.disabled    tiramisu.basetype.DisabledBaseType-class.html#disabled
+tiramisu.option.Option.setowner        tiramisu.option.Option-class.html#setowner
+tiramisu.basetype.DisabledBaseType._is_disabled        tiramisu.basetype.DisabledBaseType-class.html#_is_disabled
+tiramisu.option.ArbitraryOption.__init__       tiramisu.option.ArbitraryOption-class.html#__init__
+tiramisu.option.Option.is_mandatory    tiramisu.option.Option-class.html#is_mandatory
+tiramisu.basetype.ModeBaseType.set_mode        tiramisu.basetype.ModeBaseType-class.html#set_mode
+tiramisu.basetype.HiddenBaseType._is_hidden    tiramisu.basetype.HiddenBaseType-class.html#_is_hidden
+tiramisu.basetype.HiddenBaseType.hidden        tiramisu.basetype.HiddenBaseType-class.html#hidden
+tiramisu.basetype.DisabledBaseType.enable      tiramisu.basetype.DisabledBaseType-class.html#enable
+tiramisu.option.Option.setoption       tiramisu.option.Option-class.html#setoption
+tiramisu.basetype.DisabledBaseType.disable     tiramisu.basetype.DisabledBaseType-class.html#disable
+tiramisu.option.Option.getcallback     tiramisu.option.Option-class.html#getcallback
+tiramisu.basetype.HiddenBaseType.hide  tiramisu.basetype.HiddenBaseType-class.html#hide
+tiramisu.option.Option.validate        tiramisu.option.Option-class.html#validate
+tiramisu.option.Option.freeze  tiramisu.option.Option-class.html#freeze
+tiramisu.basetype.ModeBaseType.get_mode        tiramisu.basetype.ModeBaseType-class.html#get_mode
+tiramisu.option.Option._frozen tiramisu.option.Option-class.html#_frozen
+tiramisu.option.Option.getdoc  tiramisu.option.Option-class.html#getdoc
+tiramisu.option.Option.is_multi        tiramisu.option.Option-class.html#is_multi
+tiramisu.option.ArbitraryOption.getdefault     tiramisu.option.ArbitraryOption-class.html#getdefault
+tiramisu.option.Option.unfreeze        tiramisu.option.Option-class.html#unfreeze
+tiramisu.basetype.ModeBaseType.mode    tiramisu.basetype.ModeBaseType-class.html#mode
+tiramisu.option.Option.getcallback_params      tiramisu.option.Option-class.html#getcallback_params
+tiramisu.option.BoolOption     tiramisu.option.BoolOption-class.html
+tiramisu.basetype.HiddenBaseType.show  tiramisu.basetype.HiddenBaseType-class.html#show
+tiramisu.option.BoolOption._validate   tiramisu.option.BoolOption-class.html#_validate
+tiramisu.option.BoolOption.opt_type    tiramisu.option.BoolOption-class.html#opt_type
+tiramisu.option.Option.getkey  tiramisu.option.Option-class.html#getkey
+tiramisu.basetype.DisabledBaseType.disabled    tiramisu.basetype.DisabledBaseType-class.html#disabled
+tiramisu.option.Option.setowner        tiramisu.option.Option-class.html#setowner
+tiramisu.basetype.DisabledBaseType._is_disabled        tiramisu.basetype.DisabledBaseType-class.html#_is_disabled
+tiramisu.option.Option.__init__        tiramisu.option.Option-class.html#__init__
+tiramisu.option.Option.is_mandatory    tiramisu.option.Option-class.html#is_mandatory
+tiramisu.basetype.ModeBaseType.set_mode        tiramisu.basetype.ModeBaseType-class.html#set_mode
+tiramisu.basetype.HiddenBaseType._is_hidden    tiramisu.basetype.HiddenBaseType-class.html#_is_hidden
+tiramisu.basetype.HiddenBaseType.hidden        tiramisu.basetype.HiddenBaseType-class.html#hidden
+tiramisu.basetype.DisabledBaseType.enable      tiramisu.basetype.DisabledBaseType-class.html#enable
+tiramisu.option.Option.setoption       tiramisu.option.Option-class.html#setoption
+tiramisu.basetype.DisabledBaseType.disable     tiramisu.basetype.DisabledBaseType-class.html#disable
+tiramisu.option.Option.getcallback     tiramisu.option.Option-class.html#getcallback
+tiramisu.basetype.HiddenBaseType.hide  tiramisu.basetype.HiddenBaseType-class.html#hide
+tiramisu.option.Option.validate        tiramisu.option.Option-class.html#validate
+tiramisu.option.Option.freeze  tiramisu.option.Option-class.html#freeze
+tiramisu.basetype.ModeBaseType.get_mode        tiramisu.basetype.ModeBaseType-class.html#get_mode
+tiramisu.option.Option._frozen tiramisu.option.Option-class.html#_frozen
+tiramisu.option.Option.getdoc  tiramisu.option.Option-class.html#getdoc
+tiramisu.option.Option.is_multi        tiramisu.option.Option-class.html#is_multi
+tiramisu.option.Option.getdefault      tiramisu.option.Option-class.html#getdefault
+tiramisu.option.Option.unfreeze        tiramisu.option.Option-class.html#unfreeze
+tiramisu.basetype.ModeBaseType.mode    tiramisu.basetype.ModeBaseType-class.html#mode
+tiramisu.option.Option.getcallback_params      tiramisu.option.Option-class.html#getcallback_params
+tiramisu.option.ChoiceOption   tiramisu.option.ChoiceOption-class.html
+tiramisu.basetype.HiddenBaseType.show  tiramisu.basetype.HiddenBaseType-class.html#show
+tiramisu.option.ChoiceOption._validate tiramisu.option.ChoiceOption-class.html#_validate
+tiramisu.option.ChoiceOption.opt_type  tiramisu.option.ChoiceOption-class.html#opt_type
+tiramisu.option.Option.getkey  tiramisu.option.Option-class.html#getkey
+tiramisu.basetype.DisabledBaseType.disabled    tiramisu.basetype.DisabledBaseType-class.html#disabled
+tiramisu.option.Option.setowner        tiramisu.option.Option-class.html#setowner
+tiramisu.basetype.DisabledBaseType._is_disabled        tiramisu.basetype.DisabledBaseType-class.html#_is_disabled
+tiramisu.option.ChoiceOption.__init__  tiramisu.option.ChoiceOption-class.html#__init__
+tiramisu.option.Option.is_mandatory    tiramisu.option.Option-class.html#is_mandatory
+tiramisu.basetype.ModeBaseType.set_mode        tiramisu.basetype.ModeBaseType-class.html#set_mode
+tiramisu.basetype.HiddenBaseType._is_hidden    tiramisu.basetype.HiddenBaseType-class.html#_is_hidden
+tiramisu.basetype.HiddenBaseType.hidden        tiramisu.basetype.HiddenBaseType-class.html#hidden
+tiramisu.basetype.DisabledBaseType.enable      tiramisu.basetype.DisabledBaseType-class.html#enable
+tiramisu.option.ChoiceOption.setoption tiramisu.option.ChoiceOption-class.html#setoption
+tiramisu.basetype.DisabledBaseType.disable     tiramisu.basetype.DisabledBaseType-class.html#disable
+tiramisu.option.Option.getcallback     tiramisu.option.Option-class.html#getcallback
+tiramisu.basetype.HiddenBaseType.hide  tiramisu.basetype.HiddenBaseType-class.html#hide
+tiramisu.option.Option.validate        tiramisu.option.Option-class.html#validate
+tiramisu.option.Option.freeze  tiramisu.option.Option-class.html#freeze
+tiramisu.basetype.ModeBaseType.get_mode        tiramisu.basetype.ModeBaseType-class.html#get_mode
+tiramisu.option.Option._frozen tiramisu.option.Option-class.html#_frozen
+tiramisu.option.Option.getdoc  tiramisu.option.Option-class.html#getdoc
+tiramisu.option.Option.is_multi        tiramisu.option.Option-class.html#is_multi
+tiramisu.option.Option.getdefault      tiramisu.option.Option-class.html#getdefault
+tiramisu.option.Option.unfreeze        tiramisu.option.Option-class.html#unfreeze
+tiramisu.basetype.ModeBaseType.mode    tiramisu.basetype.ModeBaseType-class.html#mode
+tiramisu.option.Option.getcallback_params      tiramisu.option.Option-class.html#getcallback_params
+tiramisu.option.FloatOption    tiramisu.option.FloatOption-class.html
+tiramisu.basetype.HiddenBaseType.show  tiramisu.basetype.HiddenBaseType-class.html#show
+tiramisu.option.FloatOption._validate  tiramisu.option.FloatOption-class.html#_validate
+tiramisu.option.FloatOption.opt_type   tiramisu.option.FloatOption-class.html#opt_type
+tiramisu.option.Option.getkey  tiramisu.option.Option-class.html#getkey
+tiramisu.basetype.DisabledBaseType.disabled    tiramisu.basetype.DisabledBaseType-class.html#disabled
+tiramisu.option.Option.setowner        tiramisu.option.Option-class.html#setowner
+tiramisu.basetype.DisabledBaseType._is_disabled        tiramisu.basetype.DisabledBaseType-class.html#_is_disabled
+tiramisu.option.Option.__init__        tiramisu.option.Option-class.html#__init__
+tiramisu.option.Option.is_mandatory    tiramisu.option.Option-class.html#is_mandatory
+tiramisu.basetype.ModeBaseType.set_mode        tiramisu.basetype.ModeBaseType-class.html#set_mode
+tiramisu.basetype.HiddenBaseType._is_hidden    tiramisu.basetype.HiddenBaseType-class.html#_is_hidden
+tiramisu.basetype.HiddenBaseType.hidden        tiramisu.basetype.HiddenBaseType-class.html#hidden
+tiramisu.basetype.DisabledBaseType.enable      tiramisu.basetype.DisabledBaseType-class.html#enable
+tiramisu.option.FloatOption.setoption  tiramisu.option.FloatOption-class.html#setoption
+tiramisu.basetype.DisabledBaseType.disable     tiramisu.basetype.DisabledBaseType-class.html#disable
+tiramisu.option.Option.getcallback     tiramisu.option.Option-class.html#getcallback
+tiramisu.basetype.HiddenBaseType.hide  tiramisu.basetype.HiddenBaseType-class.html#hide
+tiramisu.option.Option.validate        tiramisu.option.Option-class.html#validate
+tiramisu.option.Option.freeze  tiramisu.option.Option-class.html#freeze
+tiramisu.basetype.ModeBaseType.get_mode        tiramisu.basetype.ModeBaseType-class.html#get_mode
+tiramisu.option.Option._frozen tiramisu.option.Option-class.html#_frozen
+tiramisu.option.Option.getdoc  tiramisu.option.Option-class.html#getdoc
+tiramisu.option.Option.is_multi        tiramisu.option.Option-class.html#is_multi
+tiramisu.option.Option.getdefault      tiramisu.option.Option-class.html#getdefault
+tiramisu.option.Option.unfreeze        tiramisu.option.Option-class.html#unfreeze
+tiramisu.basetype.ModeBaseType.mode    tiramisu.basetype.ModeBaseType-class.html#mode
+tiramisu.option.Option.getcallback_params      tiramisu.option.Option-class.html#getcallback_params
+tiramisu.option.IPOption       tiramisu.option.IPOption-class.html
+tiramisu.basetype.HiddenBaseType.show  tiramisu.basetype.HiddenBaseType-class.html#show
+tiramisu.option.IPOption._validate     tiramisu.option.IPOption-class.html#_validate
+tiramisu.option.IPOption.opt_type      tiramisu.option.IPOption-class.html#opt_type
+tiramisu.option.Option.getkey  tiramisu.option.Option-class.html#getkey
+tiramisu.basetype.DisabledBaseType.disabled    tiramisu.basetype.DisabledBaseType-class.html#disabled
+tiramisu.option.Option.setowner        tiramisu.option.Option-class.html#setowner
+tiramisu.basetype.DisabledBaseType._is_disabled        tiramisu.basetype.DisabledBaseType-class.html#_is_disabled
+tiramisu.option.Option.__init__        tiramisu.option.Option-class.html#__init__
+tiramisu.option.Option.is_mandatory    tiramisu.option.Option-class.html#is_mandatory
+tiramisu.basetype.ModeBaseType.set_mode        tiramisu.basetype.ModeBaseType-class.html#set_mode
+tiramisu.basetype.HiddenBaseType._is_hidden    tiramisu.basetype.HiddenBaseType-class.html#_is_hidden
+tiramisu.basetype.HiddenBaseType.hidden        tiramisu.basetype.HiddenBaseType-class.html#hidden
+tiramisu.basetype.DisabledBaseType.enable      tiramisu.basetype.DisabledBaseType-class.html#enable
+tiramisu.option.IPOption.setoption     tiramisu.option.IPOption-class.html#setoption
+tiramisu.basetype.DisabledBaseType.disable     tiramisu.basetype.DisabledBaseType-class.html#disable
+tiramisu.option.Option.getcallback     tiramisu.option.Option-class.html#getcallback
+tiramisu.basetype.HiddenBaseType.hide  tiramisu.basetype.HiddenBaseType-class.html#hide
+tiramisu.option.Option.validate        tiramisu.option.Option-class.html#validate
+tiramisu.option.Option.freeze  tiramisu.option.Option-class.html#freeze
+tiramisu.basetype.ModeBaseType.get_mode        tiramisu.basetype.ModeBaseType-class.html#get_mode
+tiramisu.option.Option._frozen tiramisu.option.Option-class.html#_frozen
+tiramisu.option.Option.getdoc  tiramisu.option.Option-class.html#getdoc
+tiramisu.option.Option.is_multi        tiramisu.option.Option-class.html#is_multi
+tiramisu.option.Option.getdefault      tiramisu.option.Option-class.html#getdefault
+tiramisu.option.Option.unfreeze        tiramisu.option.Option-class.html#unfreeze
+tiramisu.basetype.ModeBaseType.mode    tiramisu.basetype.ModeBaseType-class.html#mode
+tiramisu.option.Option.getcallback_params      tiramisu.option.Option-class.html#getcallback_params
+tiramisu.option.IntOption      tiramisu.option.IntOption-class.html
+tiramisu.basetype.HiddenBaseType.show  tiramisu.basetype.HiddenBaseType-class.html#show
+tiramisu.option.IntOption._validate    tiramisu.option.IntOption-class.html#_validate
+tiramisu.option.IntOption.opt_type     tiramisu.option.IntOption-class.html#opt_type
+tiramisu.option.Option.getkey  tiramisu.option.Option-class.html#getkey
+tiramisu.basetype.DisabledBaseType.disabled    tiramisu.basetype.DisabledBaseType-class.html#disabled
+tiramisu.option.Option.setowner        tiramisu.option.Option-class.html#setowner
+tiramisu.basetype.DisabledBaseType._is_disabled        tiramisu.basetype.DisabledBaseType-class.html#_is_disabled
+tiramisu.option.Option.__init__        tiramisu.option.Option-class.html#__init__
+tiramisu.option.Option.is_mandatory    tiramisu.option.Option-class.html#is_mandatory
+tiramisu.basetype.ModeBaseType.set_mode        tiramisu.basetype.ModeBaseType-class.html#set_mode
+tiramisu.basetype.HiddenBaseType._is_hidden    tiramisu.basetype.HiddenBaseType-class.html#_is_hidden
+tiramisu.basetype.HiddenBaseType.hidden        tiramisu.basetype.HiddenBaseType-class.html#hidden
+tiramisu.basetype.DisabledBaseType.enable      tiramisu.basetype.DisabledBaseType-class.html#enable
+tiramisu.option.IntOption.setoption    tiramisu.option.IntOption-class.html#setoption
+tiramisu.basetype.DisabledBaseType.disable     tiramisu.basetype.DisabledBaseType-class.html#disable
+tiramisu.option.Option.getcallback     tiramisu.option.Option-class.html#getcallback
+tiramisu.basetype.HiddenBaseType.hide  tiramisu.basetype.HiddenBaseType-class.html#hide
+tiramisu.option.Option.validate        tiramisu.option.Option-class.html#validate
+tiramisu.option.Option.freeze  tiramisu.option.Option-class.html#freeze
+tiramisu.basetype.ModeBaseType.get_mode        tiramisu.basetype.ModeBaseType-class.html#get_mode
+tiramisu.option.Option._frozen tiramisu.option.Option-class.html#_frozen
+tiramisu.option.Option.getdoc  tiramisu.option.Option-class.html#getdoc
+tiramisu.option.Option.is_multi        tiramisu.option.Option-class.html#is_multi
+tiramisu.option.Option.getdefault      tiramisu.option.Option-class.html#getdefault
+tiramisu.option.Option.unfreeze        tiramisu.option.Option-class.html#unfreeze
+tiramisu.basetype.ModeBaseType.mode    tiramisu.basetype.ModeBaseType-class.html#mode
+tiramisu.option.Option.getcallback_params      tiramisu.option.Option-class.html#getcallback_params
+tiramisu.option.NetmaskOption  tiramisu.option.NetmaskOption-class.html
+tiramisu.basetype.HiddenBaseType.show  tiramisu.basetype.HiddenBaseType-class.html#show
+tiramisu.option.NetmaskOption._validate        tiramisu.option.NetmaskOption-class.html#_validate
+tiramisu.option.NetmaskOption.opt_type tiramisu.option.NetmaskOption-class.html#opt_type
+tiramisu.option.Option.getkey  tiramisu.option.Option-class.html#getkey
+tiramisu.basetype.DisabledBaseType.disabled    tiramisu.basetype.DisabledBaseType-class.html#disabled
+tiramisu.option.Option.setowner        tiramisu.option.Option-class.html#setowner
+tiramisu.basetype.DisabledBaseType._is_disabled        tiramisu.basetype.DisabledBaseType-class.html#_is_disabled
+tiramisu.option.Option.__init__        tiramisu.option.Option-class.html#__init__
+tiramisu.option.Option.is_mandatory    tiramisu.option.Option-class.html#is_mandatory
+tiramisu.basetype.ModeBaseType.set_mode        tiramisu.basetype.ModeBaseType-class.html#set_mode
+tiramisu.basetype.HiddenBaseType._is_hidden    tiramisu.basetype.HiddenBaseType-class.html#_is_hidden
+tiramisu.basetype.HiddenBaseType.hidden        tiramisu.basetype.HiddenBaseType-class.html#hidden
+tiramisu.basetype.DisabledBaseType.enable      tiramisu.basetype.DisabledBaseType-class.html#enable
+tiramisu.option.NetmaskOption.setoption        tiramisu.option.NetmaskOption-class.html#setoption
+tiramisu.basetype.DisabledBaseType.disable     tiramisu.basetype.DisabledBaseType-class.html#disable
+tiramisu.option.Option.getcallback     tiramisu.option.Option-class.html#getcallback
+tiramisu.basetype.HiddenBaseType.hide  tiramisu.basetype.HiddenBaseType-class.html#hide
+tiramisu.option.Option.validate        tiramisu.option.Option-class.html#validate
+tiramisu.option.Option.freeze  tiramisu.option.Option-class.html#freeze
+tiramisu.basetype.ModeBaseType.get_mode        tiramisu.basetype.ModeBaseType-class.html#get_mode
+tiramisu.option.Option._frozen tiramisu.option.Option-class.html#_frozen
+tiramisu.option.Option.getdoc  tiramisu.option.Option-class.html#getdoc
+tiramisu.option.Option.is_multi        tiramisu.option.Option-class.html#is_multi
+tiramisu.option.Option.getdefault      tiramisu.option.Option-class.html#getdefault
+tiramisu.option.Option.unfreeze        tiramisu.option.Option-class.html#unfreeze
+tiramisu.basetype.ModeBaseType.mode    tiramisu.basetype.ModeBaseType-class.html#mode
+tiramisu.option.Option.getcallback_params      tiramisu.option.Option-class.html#getcallback_params
+tiramisu.option.Option tiramisu.option.Option-class.html
+tiramisu.basetype.HiddenBaseType.show  tiramisu.basetype.HiddenBaseType-class.html#show
+tiramisu.option.Option.getkey  tiramisu.option.Option-class.html#getkey
+tiramisu.basetype.DisabledBaseType.disabled    tiramisu.basetype.DisabledBaseType-class.html#disabled
+tiramisu.option.Option.setowner        tiramisu.option.Option-class.html#setowner
+tiramisu.basetype.DisabledBaseType._is_disabled        tiramisu.basetype.DisabledBaseType-class.html#_is_disabled
+tiramisu.option.Option.__init__        tiramisu.option.Option-class.html#__init__
+tiramisu.option.Option.is_mandatory    tiramisu.option.Option-class.html#is_mandatory
+tiramisu.basetype.ModeBaseType.set_mode        tiramisu.basetype.ModeBaseType-class.html#set_mode
+tiramisu.basetype.HiddenBaseType._is_hidden    tiramisu.basetype.HiddenBaseType-class.html#_is_hidden
+tiramisu.basetype.HiddenBaseType.hidden        tiramisu.basetype.HiddenBaseType-class.html#hidden
+tiramisu.basetype.DisabledBaseType.enable      tiramisu.basetype.DisabledBaseType-class.html#enable
+tiramisu.option.Option.setoption       tiramisu.option.Option-class.html#setoption
+tiramisu.basetype.DisabledBaseType.disable     tiramisu.basetype.DisabledBaseType-class.html#disable
+tiramisu.option.Option.getcallback     tiramisu.option.Option-class.html#getcallback
+tiramisu.basetype.HiddenBaseType.hide  tiramisu.basetype.HiddenBaseType-class.html#hide
+tiramisu.option.Option.validate        tiramisu.option.Option-class.html#validate
+tiramisu.option.Option.freeze  tiramisu.option.Option-class.html#freeze
+tiramisu.basetype.ModeBaseType.get_mode        tiramisu.basetype.ModeBaseType-class.html#get_mode
+tiramisu.option.Option._frozen tiramisu.option.Option-class.html#_frozen
+tiramisu.option.Option.getdoc  tiramisu.option.Option-class.html#getdoc
+tiramisu.option.Option.is_multi        tiramisu.option.Option-class.html#is_multi
+tiramisu.option.Option.getdefault      tiramisu.option.Option-class.html#getdefault
+tiramisu.option.Option.unfreeze        tiramisu.option.Option-class.html#unfreeze
+tiramisu.basetype.ModeBaseType.mode    tiramisu.basetype.ModeBaseType-class.html#mode
+tiramisu.option.Option.getcallback_params      tiramisu.option.Option-class.html#getcallback_params
+tiramisu.option.OptionDescription      tiramisu.option.OptionDescription-class.html
+tiramisu.option.OptionDescription.show tiramisu.option.OptionDescription-class.html#show
+tiramisu.option.OptionDescription.add_child    tiramisu.option.OptionDescription-class.html#add_child
+tiramisu.basetype.DisabledBaseType.disabled    tiramisu.basetype.DisabledBaseType-class.html#disabled
+tiramisu.basetype.DisabledBaseType._is_disabled        tiramisu.basetype.DisabledBaseType-class.html#_is_disabled
+tiramisu.option.OptionDescription.__init__     tiramisu.option.OptionDescription-class.html#__init__
+tiramisu.option.OptionDescription.hide tiramisu.option.OptionDescription-class.html#hide
+tiramisu.basetype.ModeBaseType.set_mode        tiramisu.basetype.ModeBaseType-class.html#set_mode
+tiramisu.option.OptionDescription.get_group_type       tiramisu.option.OptionDescription-class.html#get_group_type
+tiramisu.option.OptionDescription.update_child tiramisu.option.OptionDescription-class.html#update_child
+tiramisu.option.OptionDescription.set_group_type       tiramisu.option.OptionDescription-class.html#set_group_type
+tiramisu.basetype.HiddenBaseType._is_hidden    tiramisu.basetype.HiddenBaseType-class.html#_is_hidden
+tiramisu.basetype.HiddenBaseType.hidden        tiramisu.basetype.HiddenBaseType-class.html#hidden
+tiramisu.option.OptionDescription.group_type   tiramisu.option.OptionDescription-class.html#group_type
+tiramisu.option.OptionDescription.getpaths     tiramisu.option.OptionDescription-class.html#getpaths
+tiramisu.option.OptionDescription.enable       tiramisu.option.OptionDescription-class.html#enable
+tiramisu.option.OptionDescription.disable      tiramisu.option.OptionDescription-class.html#disable
+tiramisu.option.OptionDescription.getkey       tiramisu.option.OptionDescription-class.html#getkey
+tiramisu.basetype.ModeBaseType.get_mode        tiramisu.basetype.ModeBaseType-class.html#get_mode
+tiramisu.option.OptionDescription._build       tiramisu.option.OptionDescription-class.html#_build
+tiramisu.option.OptionDescription.getdoc       tiramisu.option.OptionDescription-class.html#getdoc
+tiramisu.basetype.ModeBaseType.mode    tiramisu.basetype.ModeBaseType-class.html#mode
+tiramisu.option.StrOption      tiramisu.option.StrOption-class.html
+tiramisu.basetype.HiddenBaseType.show  tiramisu.basetype.HiddenBaseType-class.html#show
+tiramisu.option.StrOption._validate    tiramisu.option.StrOption-class.html#_validate
+tiramisu.option.StrOption.opt_type     tiramisu.option.StrOption-class.html#opt_type
+tiramisu.option.Option.getkey  tiramisu.option.Option-class.html#getkey
+tiramisu.basetype.DisabledBaseType.disabled    tiramisu.basetype.DisabledBaseType-class.html#disabled
+tiramisu.option.Option.setowner        tiramisu.option.Option-class.html#setowner
+tiramisu.basetype.DisabledBaseType._is_disabled        tiramisu.basetype.DisabledBaseType-class.html#_is_disabled
+tiramisu.option.Option.__init__        tiramisu.option.Option-class.html#__init__
+tiramisu.option.Option.is_mandatory    tiramisu.option.Option-class.html#is_mandatory
+tiramisu.basetype.ModeBaseType.set_mode        tiramisu.basetype.ModeBaseType-class.html#set_mode
+tiramisu.basetype.HiddenBaseType._is_hidden    tiramisu.basetype.HiddenBaseType-class.html#_is_hidden
+tiramisu.basetype.HiddenBaseType.hidden        tiramisu.basetype.HiddenBaseType-class.html#hidden
+tiramisu.basetype.DisabledBaseType.enable      tiramisu.basetype.DisabledBaseType-class.html#enable
+tiramisu.option.StrOption.setoption    tiramisu.option.StrOption-class.html#setoption
+tiramisu.basetype.DisabledBaseType.disable     tiramisu.basetype.DisabledBaseType-class.html#disable
+tiramisu.option.Option.getcallback     tiramisu.option.Option-class.html#getcallback
+tiramisu.basetype.HiddenBaseType.hide  tiramisu.basetype.HiddenBaseType-class.html#hide
+tiramisu.option.Option.validate        tiramisu.option.Option-class.html#validate
+tiramisu.option.Option.freeze  tiramisu.option.Option-class.html#freeze
+tiramisu.basetype.ModeBaseType.get_mode        tiramisu.basetype.ModeBaseType-class.html#get_mode
+tiramisu.option.Option._frozen tiramisu.option.Option-class.html#_frozen
+tiramisu.option.Option.getdoc  tiramisu.option.Option-class.html#getdoc
+tiramisu.option.Option.is_multi        tiramisu.option.Option-class.html#is_multi
+tiramisu.option.Option.getdefault      tiramisu.option.Option-class.html#getdefault
+tiramisu.option.Option.unfreeze        tiramisu.option.Option-class.html#unfreeze
+tiramisu.basetype.ModeBaseType.mode    tiramisu.basetype.ModeBaseType-class.html#mode
+tiramisu.option.Option.getcallback_params      tiramisu.option.Option-class.html#getcallback_params
+tiramisu.option.SymLinkOption  tiramisu.option.SymLinkOption-class.html
+tiramisu.option.SymLinkOption.setoption        tiramisu.option.SymLinkOption-class.html#setoption
+tiramisu.option.SymLinkOption.opt_type tiramisu.option.SymLinkOption-class.html#opt_type
+tiramisu.option.SymLinkOption.__init__ tiramisu.option.SymLinkOption-class.html#__init__
+tiramisu.tool.extend   tiramisu.tool.extend-class.html
+tiramisu.tool.extend.extend    tiramisu.tool.extend-class.html#extend
diff --git a/src/doc/build/pydoc/crarr.png b/src/doc/build/pydoc/crarr.png
new file mode 100644 (file)
index 0000000..26b43c5
Binary files /dev/null and b/src/doc/build/pydoc/crarr.png differ
diff --git a/src/doc/build/pydoc/epydoc.css b/src/doc/build/pydoc/epydoc.css
new file mode 100644 (file)
index 0000000..1c00695
--- /dev/null
@@ -0,0 +1,322 @@
+
+
+/* Epydoc CSS Stylesheet
+ *
+ * This stylesheet can be used to customize the appearance of epydoc's
+ * HTML output.
+ *
+ */
+
+/* Default Colors & Styles
+ *   - Set the default foreground & background color with 'body'; and 
+ *     link colors with 'a:link' and 'a:visited'.
+ *   - Use bold for decision list terms.
+ *   - The heading styles defined here are used for headings *within*
+ *     docstring descriptions.  All headings used by epydoc itself use
+ *     either class='epydoc' or class='toc' (CSS styles for both
+ *     defined below).
+ */
+body                        { background: #ffffff; color: #000000; }
+p                           { margin-top: 0.5em; margin-bottom: 0.5em; }
+a:link                      { color: #000000; }
+a:visited                   { color: #404040; }
+dt                          { font-weight: bold; }
+h1                          { font-size: +140%; font-style: italic;
+                              font-weight: bold; }
+h2                          { font-size: +125%; font-style: italic;
+                              font-weight: bold; }
+h3                          { font-size: +110%; font-style: italic;
+                              font-weight: normal; }
+code                        { font-size: 100%; }
+/* N.B.: class, not pseudoclass */
+a.link                      { font-family: monospace; }
+/* Page Header & Footer
+ *   - The standard page header consists of a navigation bar (with
+ *     pointers to standard pages such as 'home' and 'trees'); a
+ *     breadcrumbs list, which can be used to navigate to containing
+ *     classes or modules; options links, to show/hide private
+ *     variables and to show/hide frames; and a page title (using
+ *     <h1>).  The page title may be followed by a link to the
+ *     corresponding source code (using 'span.codelink').
+ *   - The footer consists of a navigation bar, a timestamp, and a
+ *     pointer to epydoc's homepage.
+ */ 
+h1.epydoc                   { margin: 0; font-size: +140%; font-weight: bold; }
+h2.epydoc                   { font-size: +130%; font-weight: bold; }
+h3.epydoc                   { font-size: +115%; font-weight: bold;
+                              margin-top: 0.2em; }
+td h3.epydoc                { font-size: +115%; font-weight: bold;
+                              margin-bottom: 0; }
+table.navbar                { background: #c0c0c0; color: #000000;
+                              border: 2px groove #d0d0d0; }
+table.navbar table          { color: #000000; }
+th.navbar-select            { background: #b0b0b0;
+                              color: #000000; } 
+table.navbar a              { text-decoration: none; }  
+table.navbar a:link         { color: #000000; }
+table.navbar a:visited      { color: #404040; }
+span.breadcrumbs            { font-size: 85%; font-weight: bold; }
+span.options                { font-size: 70%; }
+span.codelink               { font-size: 85%; }
+td.footer                   { font-size: 85%; }
+
+/* Table Headers
+ *   - Each summary table and details section begins with a 'header'
+ *     row.  This row contains a section title (marked by
+ *     'span.table-header') as well as a show/hide private link
+ *     (marked by 'span.options', defined above).
+ *   - Summary tables that contain user-defined groups mark those
+ *     groups using 'group header' rows.
+ */
+td.table-header             { background: #b0b0b0; color: #000000;
+                              border: 1px solid #808080; }
+td.table-header table       { color: #000000; }
+td.table-header table a:link      { color: #000000; }
+td.table-header table a:visited   { color: #404040; }
+span.table-header           { font-size: 120%; font-weight: bold; }
+th.group-header             { background: #e0e0e0; color: #000000;
+                              text-align: left; font-style: italic; 
+                              font-size: 115%; 
+                              border: 1px solid #808080; }
+
+/* Summary Tables (functions, variables, etc)
+ *   - Each object is described by a single row of the table with
+ *     two cells.  The left cell gives the object's type, and is
+ *     marked with 'code.summary-type'.  The right cell gives the
+ *     object's name and a summary description.
+ *   - CSS styles for the table's header and group headers are
+ *     defined above, under 'Table Headers'
+ */
+table.summary               { border-collapse: collapse;
+                              background: #f0f0f0; color: #000000;
+                              border: 1px solid #808080;
+                              margin-bottom: 0.5em; }
+td.summary                  { border: 1px solid #808080; }
+code.summary-type           { font-size: 85%; }
+table.summary a:link        { color: #000000; }
+table.summary a:visited     { color: #404040; }
+
+
+/* Details Tables (functions, variables, etc)
+ *   - Each object is described in its own div.
+ *   - A single-row summary table w/ table-header is used as
+ *     a header for each details section (CSS style for table-header
+ *     is defined above, under 'Table Headers').
+ */
+table.details               { border-collapse: collapse;
+                              background: #f0f0f0; color: #000000;
+                              border: 1px solid #808080;
+                              margin: .2em 0 0 0; }
+table.details table         { color: #000000; }
+table.details a:link        { color: #000000; }
+table.details a:visited     { color: #404040; }
+
+/* Fields */
+dl.fields                   { margin-left: 2em; margin-top: 1em;
+                              margin-bottom: 1em; }
+dl.fields dd ul             { margin-left: 0em; padding-left: 0em; }
+dl.fields dd ul li ul       { margin-left: 2em; padding-left: 0em; }
+div.fields                  { margin-left: 2em; }
+div.fields p                { margin-bottom: 0.5em; }
+
+/* Index tables (identifier index, term index, etc)
+ *   - link-index is used for indices containing lists of links
+ *     (namely, the identifier index & term index).
+ *   - index-where is used in link indices for the text indicating
+ *     the container/source for each link.
+ *   - metadata-index is used for indices containing metadata
+ *     extracted from fields (namely, the bug index & todo index).
+ */
+table.link-index            { border-collapse: collapse;
+                              background: #f0f0f0; color: #000000;
+                              border: 1px solid #808080; }
+td.link-index               { border-width: 0px; }
+table.link-index a:link     { color: #000000; }
+table.link-index a:visited  { color: #404040; }
+span.index-where            { font-size: 70%; }
+table.metadata-index        { border-collapse: collapse;
+                              background: #f0f0f0; color: #000000;
+                              border: 1px solid #808080; 
+                              margin: .2em 0 0 0; }
+td.metadata-index           { border-width: 1px; border-style: solid; }
+table.metadata-index a:link { color: #000000; }
+table.metadata-index a:visited  { color: #404040; }
+
+/* Function signatures
+ *   - sig* is used for the signature in the details section.
+ *   - .summary-sig* is used for the signature in the summary 
+ *     table, and when listing property accessor functions.
+ * */
+.sig-name                   { color: #606060; }
+.sig-arg                    { color: #808080; }
+.sig-default                { color: #202020; }
+.summary-sig                { font-family: monospace; }
+.summary-sig-name           { color: #606060; font-weight: bold; }
+table.summary a.summary-sig-name:link
+                            { color: #606060; font-weight: bold; }
+table.summary a.summary-sig-name:visited
+                            { color: #606060; font-weight: bold; }
+.summary-sig-arg            { color: #606060; }
+.summary-sig-default        { color: #181818; }
+
+/* Subclass list
+ */
+ul.subclass-list { display: inline; }
+ul.subclass-list li { display: inline; }
+
+/* To render variables, classes etc. like functions */
+table.summary .summary-name { color: #606060; font-weight: bold;
+                              font-family: monospace; }
+table.summary
+     a.summary-name:link    { color: #606060; font-weight: bold;
+                              font-family: monospace; }
+table.summary
+    a.summary-name:visited  { color: #606060; font-weight: bold;
+                              font-family: monospace; }
+
+/* Variable values
+ *   - In the 'variable details' sections, each varaible's value is
+ *     listed in a 'pre.variable' box.  The width of this box is
+ *     restricted to 80 chars; if the value's repr is longer than
+ *     this it will be wrapped, using a backslash marked with
+ *     class 'variable-linewrap'.  If the value's repr is longer
+ *     than 3 lines, the rest will be ellided; and an ellipsis
+ *     marker ('...' marked with 'variable-ellipsis') will be used.
+ *   - If the value is a string, its quote marks will be marked
+ *     with 'variable-quote'.
+ *   - If the variable is a regexp, it is syntax-highlighted using
+ *     the re* CSS classes.
+ */
+pre.variable                { padding: .5em; margin: 0;
+                              background: #e4e4e4; color: #000000;
+                              border: 1px solid #888888; }
+.variable-linewrap          { color: #404040; font-weight: bold; }
+.variable-ellipsis          { color: #404040; font-weight: bold; }
+.variable-quote             { color: #404040; font-weight: bold; }
+.variable-group             { color: #808080; font-weight: bold; }
+.variable-op                { color: #404040; font-weight: bold; }
+.variable-string            { color: #606060; }
+.variable-unknown           { color: #000000; font-weight: bold; }
+.re                         { color: #000000; }
+.re-char                    { color: #606060; }
+.re-op                      { color: #000000; }
+.re-group                   { color: #303030; }
+.re-ref                     { color: #404040; }
+
+/* Base tree
+ *   - Used by class pages to display the base class hierarchy.
+ */
+pre.base-tree               { font-size: 80%; margin: 0; }
+
+/* Frames-based table of contents headers
+ *   - Consists of two frames: one for selecting modules; and
+ *     the other listing the contents of the selected module.
+ *   - h1.toc is used for each frame's heading
+ *   - h2.toc is used for subheadings within each frame.
+ */
+h1.toc                      { text-align: center; font-size: 105%;
+                              margin: 0; font-weight: bold;
+                              padding: 0; }
+h2.toc                      { font-size: 100%; font-weight: bold; 
+                              margin: 0.5em 0 0 -0.3em; }
+
+/* Syntax Highlighting for Source Code
+ *   - doctest examples are displayed in a 'pre.py-doctest' block.
+ *     If the example is in a details table entry, then it will use
+ *     the colors specified by the 'table pre.py-doctest' line.
+ *   - Source code listings are displayed in a 'pre.py-src' block.
+ *     Each line is marked with 'span.py-line' (used to draw a line
+ *     down the left margin, separating the code from the line
+ *     numbers).  Line numbers are displayed with 'span.py-lineno'.
+ *     The expand/collapse block toggle button is displayed with
+ *     'a.py-toggle' (Note: the CSS style for 'a.py-toggle' should not
+ *     modify the font size of the text.)
+ *   - If a source code page is opened with an anchor, then the
+ *     corresponding code block will be highlighted.  The code
+ *     block's header is highlighted with 'py-highlight-hdr'; and
+ *     the code block's body is highlighted with 'py-highlight'.
+ *   - The remaining py-* classes are used to perform syntax
+ *     highlighting (py-string for string literals, py-name for names,
+ *     etc.)
+ */
+pre.py-doctest              { padding: .5em; margin: 1em;
+                              background: #f0f0f0; color: #000000;
+                              border: 1px solid #888888; }
+table pre.py-doctest        { background: #e4e4e4;
+                              color: #000000; }
+pre.py-src                  { border: 2px solid #000000; 
+                              background: #f0f0f0; color: #000000; }
+.py-line                    { border-left: 2px solid #000000; 
+                              margin-left: .2em; padding-left: .4em; }
+.py-lineno                  { font-style: italic; font-size: 90%;
+                              padding-left: .5em; }
+a.py-toggle                 { text-decoration: none; }
+div.py-highlight-hdr        { border-top: 2px solid #000000;
+                              border-bottom: 2px solid #000000;
+                              background: #e8e8e8; }
+div.py-highlight            { border-bottom: 2px solid #000000;
+                              background: #e0e0e0; }
+.py-prompt                  { color: #505050; font-weight: bold;}
+.py-more                    { color: #505050; font-weight: bold;}
+.py-string                  { color: #606060; }
+.py-comment                 { color: #303030; }
+.py-keyword                 { color: #000000; }
+.py-output                  { color: #404040; }
+.py-name                    { color: #000000; }
+.py-name:link               { color: #000000 !important; }
+.py-name:visited            { color: #000000 !important; }
+.py-number                  { color: #505050; }
+.py-defname                 { color: #000000; font-weight: bold; }
+.py-def-name                { color: #000000; font-weight: bold; }
+.py-base-class              { color: #000000; }
+.py-param                   { color: #000000; }
+.py-docstring               { color: #606060; }
+.py-decorator               { color: #404040; }
+/* Use this if you don't want links to names underlined: */
+/*a.py-name                   { text-decoration: none; }*/
+
+/* Graphs & Diagrams
+ *   - These CSS styles are used for graphs & diagrams generated using
+ *     Graphviz dot.  'img.graph-without-title' is used for bare
+ *     diagrams (to remove the border created by making the image
+ *     clickable).
+ */
+img.graph-without-title     { border: none; }
+img.graph-with-title        { border: 1px solid #000000; }
+span.graph-title            { font-weight: bold; }
+span.graph-caption          { }
+
+/* General-purpose classes
+ *   - 'p.indent-wrapped-lines' defines a paragraph whose first line
+ *     is not indented, but whose subsequent lines are.
+ *   - The 'nomargin-top' class is used to remove the top margin (e.g.
+ *     from lists).  The 'nomargin' class is used to remove both the
+ *     top and bottom margin (but not the left or right margin --
+ *     for lists, that would cause the bullets to disappear.)
+ */
+p.indent-wrapped-lines      { padding: 0 0 0 7em; text-indent: -7em; 
+                              margin: 0; }
+.nomargin-top               { margin-top: 0; }
+.nomargin                   { margin-top: 0; margin-bottom: 0; }
+
+/* HTML Log */
+div.log-block               { padding: 0; margin: .5em 0 .5em 0;
+                              background: #f0f0f0; color: #000000;
+                              border: 1px solid #000000; }
+div.log-error               { padding: .1em .3em .1em .3em; margin: 4px;
+                              background: #b0b0b0; color: #000000;
+                              border: 1px solid #000000; }
+div.log-warning             { padding: .1em .3em .1em .3em; margin: 4px;
+                              background: #ffffff; color: #000000;
+                              border: 1px solid #000000; }
+div.log-info               { padding: .1em .3em .1em .3em; margin: 4px;
+                              background: #ffffff; color: #000000;
+                              border: 1px solid #000000; }
+h2.log-hdr                  { background: #b0b0b0; color: #000000;
+                              margin: 0; padding: 0em 0.5em 0em 0.5em;
+                              border-bottom: 1px solid #000000; font-size: 110%; }
+p.log                       { font-weight: bold; margin: .5em 0 .5em 0; }
+tr.opt-changed              { color: #000000; font-weight: bold; }
+tr.opt-default              { color: #606060; }
+pre.log                     { margin: 0; padding: 0; padding-left: 1em; }
diff --git a/src/doc/build/pydoc/epydoc.js b/src/doc/build/pydoc/epydoc.js
new file mode 100644 (file)
index 0000000..e787dbc
--- /dev/null
@@ -0,0 +1,293 @@
+function toggle_private() {
+        // Search for any private/public links on this page.  Store
+        // their old text in "cmd," so we will know what action to
+        // take; and change their text to the opposite action.
+        var cmd = "?";
+        var elts = document.getElementsByTagName("a");
+        for(var i=0; i<elts.length; i++) {
+          if (elts[i].className == "privatelink") {
+            cmd = elts[i].innerHTML;
+            elts[i].innerHTML = ((cmd && cmd.substr(0,4)=="show")?
+                                    "hide&nbsp;private":"show&nbsp;private");
+          }
+        }
+        // Update all DIVs containing private objects.
+        var elts = document.getElementsByTagName("div");
+        for(var i=0; i<elts.length; i++) {
+          if (elts[i].className == "private") {
+            elts[i].style.display = ((cmd && cmd.substr(0,4)=="hide")?"none":"block");
+          }
+          else if (elts[i].className == "public") {
+            elts[i].style.display = ((cmd && cmd.substr(0,4)=="hide")?"block":"none");
+          }
+        }
+        // Update all table rows containing private objects.  Note, we
+        // use "" instead of "block" becaue IE & firefox disagree on what
+        // this should be (block vs table-row), and "" just gives the
+        // default for both browsers.
+        var elts = document.getElementsByTagName("tr");
+        for(var i=0; i<elts.length; i++) {
+          if (elts[i].className == "private") {
+            elts[i].style.display = ((cmd && cmd.substr(0,4)=="hide")?"none":"");
+          }
+        }
+        // Update all list items containing private objects.
+        var elts = document.getElementsByTagName("li");
+        for(var i=0; i<elts.length; i++) {
+          if (elts[i].className == "private") {
+            elts[i].style.display = ((cmd && cmd.substr(0,4)=="hide")?
+                                        "none":"");
+          }
+        }
+        // Update all list items containing private objects.
+        var elts = document.getElementsByTagName("ul");
+        for(var i=0; i<elts.length; i++) {
+          if (elts[i].className == "private") {
+            elts[i].style.display = ((cmd && cmd.substr(0,4)=="hide")?"none":"block");
+          }
+        }
+        // Set a cookie to remember the current option.
+        document.cookie = "EpydocPrivate="+cmd;
+      }
+function show_private() {
+        var elts = document.getElementsByTagName("a");
+        for(var i=0; i<elts.length; i++) {
+          if (elts[i].className == "privatelink") {
+            cmd = elts[i].innerHTML;
+            if (cmd && cmd.substr(0,4)=="show")
+                toggle_private();
+          }
+        }
+      }
+function getCookie(name) {
+        var dc = document.cookie;
+        var prefix = name + "=";
+        var begin = dc.indexOf("; " + prefix);
+        if (begin == -1) {
+          begin = dc.indexOf(prefix);
+          if (begin != 0) return null;
+        } else
+        { begin += 2; }
+        var end = document.cookie.indexOf(";", begin);
+        if (end == -1)
+        { end = dc.length; }
+        return unescape(dc.substring(begin + prefix.length, end));
+      }
+function setFrame(url1, url2) {
+          parent.frames[1].location.href = url1;
+          parent.frames[2].location.href = url2;
+      }
+function checkCookie() {
+        var cmd=getCookie("EpydocPrivate");
+        if (cmd && cmd.substr(0,4)!="show" && location.href.indexOf("#_") < 0)
+            toggle_private();
+      }
+function toggleCallGraph(id) {
+        var elt = document.getElementById(id);
+        if (elt.style.display == "none")
+            elt.style.display = "block";
+        else
+            elt.style.display = "none";
+      }
+function expand(id) {
+  var elt = document.getElementById(id+"-expanded");
+  if (elt) elt.style.display = "block";
+  var elt = document.getElementById(id+"-expanded-linenums");
+  if (elt) elt.style.display = "block";
+  var elt = document.getElementById(id+"-collapsed");
+  if (elt) { elt.innerHTML = ""; elt.style.display = "none"; }
+  var elt = document.getElementById(id+"-collapsed-linenums");
+  if (elt) { elt.innerHTML = ""; elt.style.display = "none"; }
+  var elt = document.getElementById(id+"-toggle");
+  if (elt) { elt.innerHTML = "-"; }
+}
+
+function collapse(id) {
+  var elt = document.getElementById(id+"-expanded");
+  if (elt) elt.style.display = "none";
+  var elt = document.getElementById(id+"-expanded-linenums");
+  if (elt) elt.style.display = "none";
+  var elt = document.getElementById(id+"-collapsed-linenums");
+  if (elt) { elt.innerHTML = "<br />"; elt.style.display="block"; }
+  var elt = document.getElementById(id+"-toggle");
+  if (elt) { elt.innerHTML = "+"; }
+  var elt = document.getElementById(id+"-collapsed");
+  if (elt) {
+    elt.style.display = "block";
+    
+    var indent = elt.getAttribute("indent");
+    var pad = elt.getAttribute("pad");
+    var s = "<tt class='py-lineno'>";
+    for (var i=0; i<pad.length; i++) { s += "&nbsp;" }
+    s += "</tt>";
+    s += "&nbsp;&nbsp;<tt class='py-line'>";
+    for (var i=0; i<indent.length; i++) { s += "&nbsp;" }
+    s += "<a href='#' onclick='expand(\"" + id;
+    s += "\");return false'>...</a></tt><br />";
+    elt.innerHTML = s;
+  }
+}
+
+function toggle(id) {
+  elt = document.getElementById(id+"-toggle");
+  if (elt.innerHTML == "-")
+      collapse(id); 
+  else
+      expand(id);
+  return false;
+}
+
+function highlight(id) {
+  var elt = document.getElementById(id+"-def");
+  if (elt) elt.className = "py-highlight-hdr";
+  var elt = document.getElementById(id+"-expanded");
+  if (elt) elt.className = "py-highlight";
+  var elt = document.getElementById(id+"-collapsed");
+  if (elt) elt.className = "py-highlight";
+}
+
+function num_lines(s) {
+  var n = 1;
+  var pos = s.indexOf("\n");
+  while ( pos > 0) {
+    n += 1;
+    pos = s.indexOf("\n", pos+1);
+  }
+  return n;
+}
+
+// Collapse all blocks that mave more than `min_lines` lines.
+function collapse_all(min_lines) {
+  var elts = document.getElementsByTagName("div");
+  for (var i=0; i<elts.length; i++) {
+    var elt = elts[i];
+    var split = elt.id.indexOf("-");
+    if (split > 0)
+      if (elt.id.substring(split, elt.id.length) == "-expanded")
+        if (num_lines(elt.innerHTML) > min_lines)
+          collapse(elt.id.substring(0, split));
+  }
+}
+
+function expandto(href) {
+  var start = href.indexOf("#")+1;
+  if (start != 0 && start != href.length) {
+    if (href.substring(start, href.length) != "-") {
+      collapse_all(4);
+      pos = href.indexOf(".", start);
+      while (pos != -1) {
+        var id = href.substring(start, pos);
+        expand(id);
+        pos = href.indexOf(".", pos+1);
+      }
+      var id = href.substring(start, href.length);
+      expand(id);
+      highlight(id);
+    }
+  }
+}
+
+function kill_doclink(id) {
+  var parent = document.getElementById(id);
+  parent.removeChild(parent.childNodes.item(0));
+}
+function auto_kill_doclink(ev) {
+  if (!ev) var ev = window.event;
+  if (!this.contains(ev.toElement)) {
+    var parent = document.getElementById(this.parentID);
+    parent.removeChild(parent.childNodes.item(0));
+  }
+}
+
+function doclink(id, name, targets_id) {
+  var elt = document.getElementById(id);
+
+  // If we already opened the box, then destroy it.
+  // (This case should never occur, but leave it in just in case.)
+  if (elt.childNodes.length > 1) {
+    elt.removeChild(elt.childNodes.item(0));
+  }
+  else {
+    // The outer box: relative + inline positioning.
+    var box1 = document.createElement("div");
+    box1.style.position = "relative";
+    box1.style.display = "inline";
+    box1.style.top = 0;
+    box1.style.left = 0;
+  
+    // A shadow for fun
+    var shadow = document.createElement("div");
+    shadow.style.position = "absolute";
+    shadow.style.left = "-1.3em";
+    shadow.style.top = "-1.3em";
+    shadow.style.background = "#404040";
+    
+    // The inner box: absolute positioning.
+    var box2 = document.createElement("div");
+    box2.style.position = "relative";
+    box2.style.border = "1px solid #a0a0a0";
+    box2.style.left = "-.2em";
+    box2.style.top = "-.2em";
+    box2.style.background = "white";
+    box2.style.padding = ".3em .4em .3em .4em";
+    box2.style.fontStyle = "normal";
+    box2.onmouseout=auto_kill_doclink;
+    box2.parentID = id;
+
+    // Get the targets
+    var targets_elt = document.getElementById(targets_id);
+    var targets = targets_elt.getAttribute("targets");
+    var links = "";
+    target_list = targets.split(",");
+    for (var i=0; i<target_list.length; i++) {
+        var target = target_list[i].split("=");
+        links += "<li><a href='" + target[1] + 
+               "' style='text-decoration:none'>" +
+               target[0] + "</a></li>";
+    }
+  
+    // Put it all together.
+    elt.insertBefore(box1, elt.childNodes.item(0));
+    //box1.appendChild(box2);
+    box1.appendChild(shadow);
+    shadow.appendChild(box2);
+    box2.innerHTML =
+        "Which <b>"+name+"</b> do you want to see documentation for?" +
+        "<ul style='margin-bottom: 0;'>" +
+        links + 
+        "<li><a href='#' style='text-decoration:none' " +
+        "onclick='kill_doclink(\""+id+"\");return false;'>"+
+        "<i>None of the above</i></a></li></ul>";
+  }
+  return false;
+}
+
+function get_anchor() {
+          var href = location.href;
+          var start = href.indexOf("#")+1;
+          if ((start != 0) && (start != href.length))
+              return href.substring(start, href.length);
+      }
+function redirect_url(dottedName) {
+          // Scan through each element of the "pages" list, and check
+          // if "name" matches with any of them.
+          for (var i=0; i<pages.length; i++) {
+
+              // Each page has the form "<pagename>-m" or "<pagename>-c";
+              // extract the <pagename> portion & compare it to dottedName.
+              var pagename = pages[i].substring(0, pages[i].length-2);
+              if (pagename == dottedName.substring(0,pagename.length)) {
+
+                  // We've found a page that matches `dottedName`;
+                  // construct its URL, using leftover `dottedName`
+                  // content to form an anchor.
+                  var pagetype = pages[i].charAt(pages[i].length-1);
+                  var url = pagename + ((pagetype=="m")?"-module.html":
+                                                        "-class.html");
+                  if (dottedName.length > pagename.length)
+                      url += "#" + dottedName.substring(pagename.length+1,
+                                                        dottedName.length);
+                  return url;
+              }
+          }
+      }
diff --git a/src/doc/build/style.css b/src/doc/build/style.css
new file mode 100644 (file)
index 0000000..28c256e
--- /dev/null
@@ -0,0 +1,32 @@
+@import url(docutils.css);
+@import url(default.css);
+a:link {
+       color: orange;
+       font-weight: bold;
+       text-decoration: none;
+}
+a:visited {
+       text-decoration: none;
+       color: #999999;
+}
+a:hover {
+       text-decoration: none;
+       color: #999999;
+}
+a:active {
+       text-decoration: none;
+       color: #999999;
+}
+
+.header {
+       color: orange;
+       background-color: white;
+       padding: 1em;
+}
+.footer {
+       color: #666;
+       background-color: inherit;
+       font-size: 75%;
+}
+
+
diff --git a/src/doc/build/tiramisu.jpeg b/src/doc/build/tiramisu.jpeg
new file mode 100644 (file)
index 0000000..84b391d
Binary files /dev/null and b/src/doc/build/tiramisu.jpeg differ
diff --git a/src/doc/code2html b/src/doc/code2html
new file mode 100755 (executable)
index 0000000..5fbd402
--- /dev/null
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+import types
+from os.path import join
+from inspect import getsource, getmembers, isclass, isfunction, ismethod, ismodule
+from importlib import import_module
+
+root="./build/api"
+
+# autopath
+
+from os.path import dirname, abspath, join, normpath
+import sys
+
+HERE = dirname(abspath(__file__))
+PATH = normpath(join(HERE, '..', '..'))
+if PATH not in sys.path:
+    sys.path.insert(1, PATH)
+
+htmltmpl = """
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>{title}</title>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8">
+<meta http-equiv="content-style-type" content="text/css">
+<meta http-equiv="expires" content="0">
+</head>
+<body>
+<pre>
+{content}
+</pre>
+</body>
+</html>
+"""
+
+def write_source(name, content):
+    fh = file(join(root, name)+'.html', 'w')
+    fh.write(format_html(name, content))
+    fh.close()
+
+def format_html(title, content):
+    return htmltmpl.format(title=title, content=content)
+
+def parse_module(module):
+    module = import_module(module)
+    write_source(module.__name__, getsource(module))
+#    classes = [(cls, value) for cls, value in getattr(module, '__dict__').items() if value == types.ClassType]
+    classes = getmembers(module, isclass)
+    for name, obj in classes:
+        write_source(module.__name__ + '.' + name, getsource(obj))
+#        methods = [(meth, value) for meth, value in getattr(obj, '__dict__').items() if type(value) == types.MethodType]
+        methods = getmembers(obj, ismethod)
+        for meth, value in methods:
+            write_source(module.__name__ + '.' + name + '.' + meth, getsource(value))
+
+    #functions = [(func, value) for func, value in getattr(module, '__dict__').items() if type(value) == types.FunctionType]
+    functions =  getmembers(module, isfunction)
+    for name, obj in functions:
+        write_source(module.__name__ + '.' + name, getsource(obj))
+
+def process_modules():
+    from glob import glob
+    from os.path import abspath, dirname, normpath, splitext, basename
+    here = abspath(__file__)
+    directory = dirname(here)
+    pyfiles = glob(normpath(join(directory, '..', '*.py')))
+    for pyf in pyfiles:
+        pyf = splitext(basename(pyf))[0]
+        modname = 'tiramisu.' + pyf
+        if not '__init__' in modname:
+            parse_module(modname)        
+
+    pyfiles = glob(normpath(join(directory, '..', 'test', '*.py')))
+    for pyf in pyfiles:
+        pyf = splitext(basename(pyf))[0]
+        modname = 'tiramisu.test.' + pyf
+        if not '__init__' in modname:
+            parse_module(modname)        
+
+process_modules()
+
diff --git a/src/doc/config.txt b/src/doc/config.txt
new file mode 100644 (file)
index 0000000..9b967d7
--- /dev/null
@@ -0,0 +1,158 @@
+.. default-role:: literal
+
+=======================
+Configuration Handling
+=======================
+
+:module: :api:`config.py`
+:tests:  - :api:`test_config.py`
+         - :api:`test_option_setting.py`
+             
+Main Assumption
+===============
+
+Configuration option objects :api:`config.Config()` are produced at the 
+entry points and handed down to where they are actually used. This keeps 
+configuration local but available everywhere and consistent.
+
+`Config` and `Option` objects
+==============================
+
+Configuration option objects can be created in different ways. Let's perform
+very basic `Config` object manipulations:
+
+::
+
+    >>> from tiramisu.config import Config
+    >>> from tiramisu.option import OptionDescription, BoolOption
+    >>> descr = OptionDescription("optgroup", "", [
+    ...     BoolOption("bool", "", default=False)])
+    >>>
+    >>> config = Config(descr)
+    >>> config.bool
+    False
+    >>> config.bool = True
+    >>> config.bool
+    True
+
+Take a look at :api:`test_config.test_base_config()` or 
+:api:`test_config.test_base_config_and_groups()`.
+
+
+Accessing the configuration `Option`'s
+-----------------------------------------
+
+The `Config` object attribute access notation stands for the value of the
+configuration's `Option`. That is, the `Config`'s object attribute is the name
+of the `Option`, and the value is the value accessed by the `__getattr__`
+attribute access mechanism. 
+
+If the attribute of the `Config` called by `__getattr__` has not been set before
+(by the classic `__setattr__` mechanism), the default value of the `Option`
+object is returned, and if no `Option` has been declared in the
+`OptionDescription` (that is the schema of the configuration), an
+`AttributeError` is raised.
+
+::
+
+    >>> gcdummy = BoolOption('dummy', 'dummy', default=False)
+    >>> gcdummy._name
+    'dummy'
+    >>> gcdummy.getdefault()
+    False
+    >>> descr = OptionDescription('tiramisu', '', [gcdummy])
+    >>> cfg = Config(descr)
+    >>> cfg.dummy
+    False
+    >>> cfg.dummy = True
+    >>> cfg.dummy
+    True
+    >>> cfg.idontexist
+    AttributeError: 'OptionDescription' object has no attribute 'idontexist'
+
+The configuration `Option` objects (in this case the `BoolOption`), are 
+organized into a tree into nested `OptionDescription` objects. Every 
+option has a name, as does every option group. The parts of the full 
+name of the option are separated by dots: e.g. 
+``config.optgroup.optname``.
+
+**Can you repeat it, what is the protocol of accessing a config's attribute ?**
+
+1. If the option has not been declared, an `AttributeError` is raised,
+
+2. If an option is declared, but neither a value nor a default value has
+   been set, the returned value is `None`,
+
+3. If an option is declared and a default value has been set, but no value
+   has been set, the returned value is the default value of the option,
+
+4. If an option is declared, and a value has been set, the returned value is
+   the value of the option.
+
+If you do not want to use the pythonic way, that is the attribute access 
+way to obtain the value of the configuration option, you can also search 
+for it recursively in the whole config namespaces with the ``get()`` 
+method :
+
+::
+
+    >>> config.get('bool')
+    True
+    
+
+To find the right option, `get()` searches recursively into the whole 
+tree. For example, to find an option which is in the `gc` namespace 
+there are two possibilites.
+
+If you know the path:
+
+::
+
+    >>> config.gc.dummy
+    False
+
+If you don't remember the path:
+
+::
+
+    >>> config.get('dummy')
+    False
+
+Setting the values of the options
+----------------------------------------
+
+An important part of the setting of the configuration consists of setting the
+values of the configuration options. There are different ways of setting values,
+the first one is of course the `__setattr__` method 
+
+::
+
+    cfg.name = value
+
+wich has the same effect that the "global" `set()` method : it expects that 
+the value owner is the default :ref:`glossary#valueowner`
+
+::
+
+     cfg.set(name=value)
+
+The global `setoption()` method of the config objects can set a value with a specific owner 
+
+::
+
+    cfg.setoption('name', value, 'owner')
+
+
+Finally, the local `setoption()` method directly in the `Option` object can be
+used. While the `Option` object refers to his parent, the config knows that the
+value has been changed and no bad side effect won't occur
+
+::
+
+    >>> booloption = BoolOption('bool', 'Test boolean option', default=True)
+    >>> descr = OptionDescription('descr', '', [booloption])
+    >>> cfg = Config(descr)
+    >>> booloption.setoption(cfg, False, 'owner')
+    >>> cfg.bool 
+    >>> False
+
diff --git a/src/doc/configapi.txt b/src/doc/configapi.txt
new file mode 100644 (file)
index 0000000..d6fe570
--- /dev/null
@@ -0,0 +1,103 @@
+.. default-role:: literal
+
+Config API Details
+==================
+
+:module: :api:`config.py`
+:test cases: - :api:`test_config_api.py`
+             - :api:`test_config_big_example.py`
+
+
+The handling of options is split into two parts: the description of 
+which options are available, what their possible values and defaults are 
+and how they are organized into a tree. A specific choice of options is 
+bundled into a configuration object which has a reference to its option 
+description (and therefore makes sure that the configuration values 
+adhere to the option description).
+
+The configuration object
+-------------------------
+
+:api:`config.Config()` object that lives in :api:`config.py` hold the 
+choosen values for the options (or the default value for the 
+:api:`option.Option()` object, if no choice was made).
+
+A `Config` object is informed by an :api:`option.OptionDescription` 
+instance. The attributes of the ``Config`` objects are the names of the 
+children of the ``OptionDescription``.
+
+Here are the (useful) methods on ``Config``:
+
+    :api:`config.Config.__init__(self, descr, **overrides)`:
+        ``descr`` is an instance of :api:`option.OptionDescription` that 
+        describes the configuration object. ``override`` can be used to 
+        set different default values (see method ``override``).
+
+    :api:`config.Config.override(self, overrides)`:
+        override default values. This marks the overridden values as defaults.
+        ``overrides`` is a dictionary of path strings to values.
+
+    :api:`config.Config.set(self, **kwargs)`:
+        "do what I mean"-interface to option setting. Searches all paths 
+        starting from that config for matches of the optional arguments 
+        and sets the found option if the match is not ambiguous.
+
+    :api:`config.Config.get(self, name)`:
+        the behavior is much like the attribute access way, except that 
+        the search for the option is performed recursively in the whole 
+        configuration tree.
+
+    :api:`config.Config.cfgimpl_read_write()`:
+        configuration level `read_write` status, see :doc:`status` 
+    
+    :api:`config.Config.cfgimpl_read_only()`:
+        configuration level `read_only` status, see :doc:`status` 
+
+Here are some private attributes of a `Config()` object, for a 
+comprehension of the internal merchanism:
+    
+- `_cfgimpl_descr =` :api:`option.OptionDescription()`, 
+  e.g. the :ref:`optionapi#schema`
+
+- `_cfgimpl_values` contains the :api:`option.Option()`'s values. 
+  Yes, the values of the options: remember that the values are stored **inside**
+  the :api:`config.Config()` and not in the `Option()`
+
+`_cfgimpl_values` contains something like that 
+
+::
+
+    {'int': 0, 'wantframework': False, 'objspace': 'std', 'bool': False,
+    'str': 'abc', 'gc': <config.Config object at 0xa33f8ec>, 'wantref': False}
+
+We can see that values can also be config objects, it's the 
+sub-namespaces that are stored in the values as `Config()` objects.
+
+convenience utilities (iteration, exports...)
+-----------------------------------------------
+
+With this :api:`config.Config()` configuration management entry point, 
+it is possible to
+
+- `iter` on config, notice that there is an iteration order wich is 
+  the order of the :ref:`optionapi#schema` specification entries,
+- compare two configs (equality),
+- export the whole config into a `dict` with :api:`config.make_dict()`,
+- `validate()` an option value into a config, see :doc:`consistency`.
+
+:api:`option.Option()` objects in a config are iterable in the pythonic 
+way, that is something like `[(name, value) for name, value in config]`. 
+
+To iter on groups in the same manner, use the
+:api:`config.Config.iter_groups()` method wich yields generators too.
+
+**iteration utilities**
+
+    :api:`config.Config.__iter__()` 
+        Pythonesque way of parsing group's ordered options.
+    
+    :api:`config.Config.iter_groups(group_type=None)`:
+        To iter on groups objects only. 
+        All groups are returned if `group_type` is `None`, otherwise the groups
+        can be filtered by categories (families, or whatever).
+
diff --git a/src/doc/consistency.txt b/src/doc/consistency.txt
new file mode 100644 (file)
index 0000000..4b00606
--- /dev/null
@@ -0,0 +1,104 @@
+.. default-role:: literal
+
+The global configuration's consistency
+========================================
+
+:module: :api:`config.py`
+:tests: :api:`test_option_consistency.py`
+
+Option's values type validation
+--------------------------------
+
+When a value is set to the option, the value is validated by the 
+option's :api:`option.Option()` validator's type.
+
+Notice that if the option is `multi`, that is the `multi` attribute is set to 
+`True`, then the validation of the option value accepts a list of values 
+of the same type.
+
+Requirements
+------------
+
+Configuration options can specify requirements as parameters at the init 
+time, the specification of some links between options or groups allows 
+to carry out a dependencies calculation. For example, an option can ben 
+hidden if another option has been set with some expected value. This is 
+just an example, because the possibilities are hudge.
+
+A requirement is specified using a list of triplets. The first element 
+of the triplet gives the path of the option that is required, the second 
+element is the value wich is expected to trigger the callback, and the 
+third one is the callback's action name (`hide`, `show`...)::
+
+    stroption = StrOption('str', 'Test string option', default="abc", 
+                          requires=[('int', 1, 'hide')])
+
+Take a look at an example here 
+:api:`test_option_consistency.test_hidden_if_in()`
+
+Config updates
+---------------
+
+New configuration options and groups can be dynamically added. 
+
+The configuration has to be *updated* after that the description has been 
+passed to the Config objet, see:
+
+::
+
+    >>> config = Config(descr)
+    >>> newoption = BoolOption('newoption', 'dummy twoo', default=False)
+    >>> descr.add_child(newoption)
+    >>> config.update()
+    >>> config.newoption
+    False
+
+in 
+
+- :api:`test_option_consistency.test_newoption_add_in_descr()`
+- :api:`test_option_consistency.test_newoption_add_in_subdescr()`
+- :api:`test_option_consistency.test_newoption_add_in_config()`
+
+
+Validation upon a whole configuration object
+----------------------------------------------
+
+An option's integrity can be validated towards a whole configuration.
+
+This type of validation is very open. Let's take a use case : an option 
+has a certain value, and the value of this option can change the owner 
+of another option or option group... Everything is possible.
+
+For example, the configuration paths have to be unique in the 
+:ref:`glossary#schema`, the validation is carried out at the 
+:api:`config.Config._cfgimpl_build()` time in the 
+:api:`config.Config._validate_duplicates()` method.
+
+Other hook are availables to validate upon a whole configuration at any 
+time.
+
+.. FIXME : get the validates hooks from the original config pypy's code
+
+Identical option names 
+----------------------
+
+If an :api:`option.Option()` happens to be defined twice in the 
+:ref:`glossary#schema` (e.g. the :api:`option.OptionDescription()`), 
+:that is the two options actually have the same name, an exception is raised.
+
+The calculation is currently carried out in the samespace, for example 
+if `config.gc.name` is defined, another option in `gc` with the name 
+`name` is **not** allowed, whereas `config.whateverelse.name` is still 
+allowed. 
+    
+.. the calculation was carried out by the requires, wich is not a goog idead
+
+    Type constraints with the `multi` type
+    ----------------------------------------
+
+    By convention, if a multi option has somme requires, the constraints on 
+    the multi type is in all the OptionGroup (a group has to be `multi`, and 
+    a multi of the same length).
+
+    See :api:`test_option_consistency.test_multi_constraints()`
+
diff --git a/src/doc/eole-report/eolreport/D01AccesVariables.txt b/src/doc/eole-report/eolreport/D01AccesVariables.txt
new file mode 100644 (file)
index 0000000..af6f19f
--- /dev/null
@@ -0,0 +1,82 @@
+.. default-role:: literal
+
+.. include:: inc/preambule.txt
+
+Accès aux variables 
+====================
+
+Protocole d'accès aux valeurs
+-------------------------------
+
+**Créole**
+
+- Si la variable n'a pas été déclarée, une erreur est levée
+- Si la variable a été déclarée, mais qu'aucune valeur n'a été définie, (ni valeur affectée, ni valeur par défaut) la valeur retournée est `[]` ou `""` ou `[""]` ou `["",""]`,
+- Si la variable a été déclarée et qu'une valeur par défaut a été définie, la valeur retournée et la valeur par défaut,
+- Si la variable a été déclarée et qu'une valeur a été définie, la valeur retournée est la valeur de la variable.
+
+**tiramisu**
+
+- Si la variable n'a pas été déclarée, une erreur est levée
+- Si la variable a été déclarée, mais qu'aucune valeur n'a été définie, (ni valeur affectée, ni valeur par défaut) la valeur retournée est `None`,
+- Si la variable a été déclarée et qu'une valeur par défaut a été définie, la valeur retournée et la valeur par défaut,
+- Si la variable a été déclarée et qu'une valeur a été définie, la valeur retournée est la valeur de la variable.
+
+la différence tient au fait de la valeur nulle (`None`) qui a été mal définie 
+dès le début dans `Créole`.
+
+Accès Créole par "dictionnaire"
+--------------------------------
+
+La définition est dans le `XML`
+
+::
+
+    <family name="general">
+
+    <variable name="adresse_ip_eth0">
+
+Le dictionnaire est chargé dans un `EoleDict()`
+
+::
+
+    from creole.cfgparser import EoleDict
+    eoldict = EoleDict(...)
+
+Un export dans un dictionnaire est necessaire pour manipuler les données
+
+::
+
+    from creole.parsedico import parse_dico
+
+    flatdict = parse_dico(eoldict)
+
+    assert dico['ip'] == '10.10.1.11'
+
+
+le resultat de l'accès aux données vient de `typeole.EoleVar('ip').get_value()`
+
+
+Accès `tiramisu` par espace de nommage
+----------------------------------------
+
+
+- espaces de nommages ;
+- c'est la configuration qui est responsable de l'accès aux valeurs ;
+- une configuration par accès direct (pas d'export) ;
+- un point d'entrée unique aisément manipulable grâce aux espaces de nommage.
+
+::
+
+    from tiramisu.config import Config
+    from tiramisu.option import OptionDescription
+    subdescr = OptionDescription("creole", [IPOption('ip')])
+    descr = OptionDescription("creole", [subdescr])
+    config = Config(descr)
+    assert config.creole.general.ip == '10.10.1.11'
+
+Les valeurs sont dépendantes **de la configuration** et donc la responsabilité 
+des valeurs dépend de la configuration et pas de la variable elle-même.
+
+
+
diff --git a/src/doc/eole-report/eolreport/D02CoherenceVariables.txt b/src/doc/eole-report/eolreport/D02CoherenceVariables.txt
new file mode 100644 (file)
index 0000000..fa37aaf
--- /dev/null
@@ -0,0 +1,109 @@
+.. default-role:: literal
+
+.. include:: inc/preambule.txt
+
+Cohérence des valeurs des variables 
+====================================
+
+type des variables 
+-------------------
+
+**Créole**
+
+pas d'unicité du type abstrait : `Multivar`, `CreoleVar` et `TypedVar`
+
+- `String`
+- `Ip`
+- `Netmask`
+- `Number`
+- `Boolean`
+- `OuiNon`
+
+**tiramisu**
+
+unicité du type abstrait : `Option()`
+
+pas de nouveau type multivalué, mais un attribut des types existants::
+
+    >>> from option import BoolOption
+    >>> boolopt = BoolOption('bool', 'description de bool', multi=True)
+
+tous les types Créole, plus
+
+- `SymlinkOption`
+- `CheckOption` qui permet de définir les "oui/non", "On/Off"
+
+Validations suivant l'organisation en familles
+-----------------------------------------------
+
+**Créole**
+
+**Organisation par accumulation de références sur des dictionnaires (`EoleDict`)**
+
+On peut charger un EoleDict avec des variables qui pointent vers des families
+qui n'existent pas, aucune validation n'est faite (confiance absolument faite au
+moment du chargemzent du XML)
+
+exemple, dans l'espace de nommage racine::
+
+    <variables>
+    <variable name="adresse_ip_eth0">
+
+
+::
+
+    from creole.parsedico import parse_dico
+    flatdict = parse_dico(eoldict)
+    dico['adresse_ip_eth0']
+    KeyError: 'adresse_ip_eth0'
+
+**Tiramisu**
+
+**Organisation par arborescence.**
+
+Un espace de nommage doit systématiquement être défini, la variable n'est
+accessible **que** par un path.
+
+
+Variables présentes deux fois
+-------------------------------
+
+- Créole : pas de validation possible
+- tiramisu : comportement règlable (on autorise l'unicité ou pas)
+
+- dans Créole les valeurs sont **fausses** (c'est la dernière variable qui qui gagne)
+
+Il faut faire confiance au XML 
+
+::
+
+    <family name="general">
+    <variable name="adresse_ip_eth0">
+    <valeur>toto
+
+
+    <family name="services">
+    <variable name="adresse_ip_eth0">
+    <valeur>tutu
+    
+
+dans `gen_config` la valeur retenue est::
+
+    general/adresse_ip_eth0 -> tutu 
+    services/adresse_ip_eth0 -> tutu 
+
+dans `parsedico`, la variable est écrasée::
+
+    >>> from creole.parsedico import parse_dico
+    >>> d = parse_dico()
+    >>> d['adresse_ip_eth0']
+    tutu
+    
+dans tiramisu::
+
+    >>> config.general.adresse_ip_eth0
+    toto
+    >>> config.services.adresse_ip_eth0
+    tutu
+    
+   
diff --git a/src/doc/eole-report/eolreport/D03ReglesEtats.txt b/src/doc/eole-report/eolreport/D03ReglesEtats.txt
new file mode 100644 (file)
index 0000000..70705f5
--- /dev/null
@@ -0,0 +1,113 @@
+.. default-role:: literal
+
+.. include:: inc/preambule.txt
+
+Etats et statuts des options de configuration
+================================================
+
+état des variables et lisibilité de l'API
+-------------------------------------------
+
+**Creole**
+
+`EoleVar()`
+
+- `get_value()`
+- `get_final_value()`
+- `get_final_value_at_index()`
+- `check_value()`
+- `get_prec_value()`
+- `get_calculated_value()` -> automatique
+
+**tiramisu**
+
+`Option()`
+
+- **aucune API** d'accès à la valeur d'une option au niveau de l'option de configuration
+- `option.getdefault()`
+- `option.setoption(config, value, owner)`
+
+variables "automatiques"
+------------------------------
+
+si `owner` == 'auto', la variable est automatique et la configuration le sait,
+elle lance alors les fonctions de calcul à chaque évaluation
+
+dans Créole, c'est validé aux niveau de la variable par un appel à `eval_func()`
+
+Accès suivant les états de la configuration
+--------------------------------------------
+
+- disabled
+- hidden
+- mode (normal/expert)
+- obligatoire (mandatory)
+- ...
+
+- `EoleVar.hidden`
+- `EoleVar.disabled`
+
+pas d'objet `Family` dans Créole donc l'organisation des hiérarchie de 
+hidden est opaque
+
+- `EoleDict.families['hidden']` pour avoir accès à l'état d'une famille
+
+dans Tiramisu
+
+- `hidden` au niveau `Option`, `OptionDescription` et **aussi** au niveau de 
+  la configuration ce qui permet d'avoir des états (inexistant dans `Créole`)
+  
+.. maitres/esclaves avec Créole : `mavar.get_slaves()`
+
+
+`hidden_if_in`, `hidden_if_not_in`
+-------------------------------------
+
+La notion est généralisée dans tiramisu avec les `requires`.
+
+Dans Créole : très difficile de conserver une cohérence des `hidden_if_in`
+quand il y en a plusieurs. 
+
+Dans Tiramisu : validation et levée d'exception si les **requirements** sont 
+incohérents, action inverse si aucun requires n'est matché.
+
+exemple de requires
+
+::
+
+    <family name="clamav">
+    <variable name="activer_clam">
+
+    <variable name="activer_clam_exim">
+    <valeur>non
+    
+    <variable name="activer_clam_samba">
+    <valeur>oui
+   
+    <condition name='hidden_if_in' source='activer_clam_exim'>
+    <param>non
+    <target type='variable'>activer_clam
+    <!-- ça hide (momentanément)-->
+    
+    <condition name='hidden_if_in' source='activer_clam_samba'>
+    <param>non
+    <target type='variable'>activer_clam
+    <!-- ça show (et c'est le dernier qui a raison) -->
+    
+:résultat: `activer_clam` est visible, c'est la dernière condition qui a raison
+
+avec tiramisu, `activer_clam` **dans les même conditions**, est cachée.
+
+::
+
+    >>> activer_clam = StrOption('activer_clam', 'activer clamav',
+                requires=[('activer_clam_exim', 'non', 'hide'), 
+                          ('activer_clam_samba', 'non', 'hide'),])
+    >>> config.clamav.activer_clam_exim = 'non'
+    >>> config.clamav.activer_clam_samba = 'oui'                     
+    >>> config.clamav.activer_clam
+    >>> Traceback (most recent call last):
+        File "<stdin>", line 1, in <module>
+        HiddenOptionError("trying to access to a hidden option:activer_clam")
+    >>> 
+
diff --git a/src/doc/eole-report/eolreport/Makefile b/src/doc/eole-report/eolreport/Makefile
new file mode 100644 (file)
index 0000000..fbf5816
--- /dev/null
@@ -0,0 +1,7 @@
+
+%.odt: %.txt
+       rst2odt --create-links --custom-odt-footer="Page %p% de %P%" --endnotes-end-doc --no-generator --stylesheet=styles.odt $< $@
+
+%.html: %.txt    
+       rst2html --stylesheet ./build/style.css $< > ./build/$@
+    
diff --git a/src/doc/eole-report/eolreport/build/Makefile b/src/doc/eole-report/eolreport/build/Makefile
new file mode 100644 (file)
index 0000000..cc5f93b
--- /dev/null
@@ -0,0 +1,6 @@
+.PHONY: clean
+.SUFFIXES:
+
+clean:
+       rm -f *.html
+       rm -f api/*.html
diff --git a/src/doc/eole-report/eolreport/build/default.css b/src/doc/eole-report/eolreport/build/default.css
new file mode 100644 (file)
index 0000000..8625c0e
--- /dev/null
@@ -0,0 +1,1080 @@
+body,body.editor,body.body {
+    font: 110% "Times New Roman", Arial, Verdana, Helvetica, serif;
+    background: White;
+    color: Black;
+}
+
+a, a.reference {
+       text-decoration: none; 
+}
+a[href]:hover { text-decoration: underline; }
+
+img {
+    border: none;
+       vertical-align: middle;
+}
+
+p, div.text {
+    text-align: left;
+    line-height: 1.5em;
+    margin: 0.5em 0em 0em 0em;
+}
+
+
+
+p a:active {
+       color: Red;
+    background-color: transparent;
+}
+
+p img {
+    border: 0;
+    margin: 0;
+}
+
+img.inlinephoto {
+    padding: 0;
+    padding-right: 1em;
+    padding-top: 0.7em;
+    float: left;
+}
+
+hr {
+    clear: both;
+    height: 1px;
+    color: #8CACBB;
+    background-color: transparent;
+}
+
+
+ul { 
+    line-height: 1.5em;
+    /*list-style-image: url("bullet.gif"); */
+    margin-left: 1.5em;
+    padding:0;
+}
+
+ol {
+    line-height: 1.5em;
+    margin-left: 1.5em;
+    padding:0;
+}
+
+ul a, ol a {
+    text-decoration: underline;
+}
+
+dl {
+}
+
+dt {
+    font-weight: bold;    
+}
+
+dd {
+    line-height: 1.5em;
+    margin-bottom: 1em;
+}
+
+blockquote {
+    font-family: Times, "Times New Roman", serif;
+    font-style: italic;
+    font-size: 120%;
+}
+
+code {
+    color: Black;
+    /*background-color: #dee7ec;*/
+    background-color: #cccccc;
+}
+
+pre {
+    padding: 1em;
+    border: 1px solid #8cacbb;
+    color: Black;
+    background-color: #dee7ec;
+    background-color: #cccccc;
+    overflow: auto;
+}
+
+
+.netscape4 {
+    display: none;
+}
+
+/* main page styles */
+
+/*a[href]:hover { color: black; text-decoration: underline; }
+a[href]:link { color: black; text-decoration: underline; }
+a[href] { color: black; text-decoration: underline; }
+*/
+
+span.menu_selected {
+       color: black;
+       font: 140% Verdana, Helvetica, Arial, sans-serif;
+       text-decoration: none;
+    padding-right: 0.3em;
+    background-color: #cccccc;
+}
+
+
+a.menu {
+       /*color: #3ba6ec; */
+       font: 140% Verdana, Helvetica, Arial, sans-serif;
+       text-decoration: none;
+    padding-right: 0.3em;
+}
+
+a.menu[href]:visited, a.menu[href]:link{
+       /*color: #3ba6ec; */
+       font: 140% Verdana, Helvetica, Arial, sans-serif;
+       text-decoration: none;
+}
+
+a.menu[href]:hover {
+       /*color: black;*/
+}
+
+div.project_title{
+  /*border-spacing: 20px;*/
+  font: 160% Verdana, Helvetica, Arial, sans-serif;
+  color: #3ba6ec; 
+  vertical-align: middle;
+  padding-bottom: 0.3em;
+}
+
+a.wikicurrent {
+  font: 100% Verdana, Helvetica, Arial, sans-serif;
+  color: #3ba6ec; 
+  vertical-align: middle;
+}
+
+
+table.body {
+  border: 0;
+  /*padding: 0;
+  border-spacing: 0px;
+  border-collapse: separate;
+  */
+}
+
+td.page-header-left {
+  padding: 5px;
+  /*border-bottom: 1px solid #444444;*/
+}
+
+td.page-header-top {
+  padding: 0;
+    
+  /*border-bottom: 1px solid #444444;*/
+}
+
+td.sidebar {
+  padding: 1 0 0 1;
+}
+
+td.sidebar p.classblock {
+  padding: 0 5 0 5;
+  margin: 1 1 1 1;
+  border: 1px solid #444444;
+  background-color: #eeeeee;
+}
+
+td.sidebar p.userblock {
+  padding: 0 5 0 5;
+  margin: 1 1 1 1;
+  border: 1px solid #444444;
+  background-color: #eeeeff;
+}
+
+td.content {
+  padding: 1 5 1 5;
+  vertical-align: top;
+  width: 100%;
+}
+
+p.ok-message {
+  background-color: #22bb22;
+  padding: 5 5 5 5;
+  color: white;
+  font-weight: bold;
+}
+p.error-message {
+  background-color: #bb2222;
+  padding: 5 5 5 5;
+  color: white;
+  font-weight: bold;
+}
+
+p:first-child { 
+  margin: 0 ;
+  padding: 0;
+}
+
+/* style for forms */
+table.form {
+  padding: 2;
+  border-spacing: 0px;
+  border-collapse: separate;
+}
+
+table.form th {
+  color: #333388;
+  text-align: right;
+  vertical-align: top;
+  font-weight: normal;
+}
+table.form th.header {
+  font-weight: bold;
+  background-color: #eeeeff;
+  text-align: left;
+}
+
+table.form th.required {
+  font-weight: bold;
+}
+
+table.form td {
+  color: #333333;
+  empty-cells: show;
+  vertical-align: top;
+}
+
+table.form td.optional {
+  font-weight: bold;
+  font-style: italic;
+}
+
+table.form td.html {
+  color: #777777;
+}
+
+/* style for lists */
+table.list {
+  border-spacing: 0px;
+  border-collapse: separate;
+  vertical-align: top;
+  padding-top: 0;
+  width: 100%;
+}
+
+table.list th {
+  padding: 0 4 0 4;
+  color: #404070;
+  background-color: #eeeeff;
+  border-right: 1px solid #404070;
+  border-top: 1px solid #404070;
+  border-bottom: 1px solid #404070;
+  vertical-align: top;
+  empty-cells: show;
+}
+table.list th a[href]:hover { color: #404070 }
+table.list th a[href]:link { color: #404070 }
+table.list th a[href] { color: #404070 }
+table.list th.group {
+  background-color: #f4f4ff;
+  text-align: center;
+  font-size: 120%;
+}
+
+table.list td {
+  padding: 0 4 0 4;
+  border: 0 2 0 2;
+  border-right: 1px solid #404070;
+  color: #404070;
+  background-color: white;
+  vertical-align: top;
+  empty-cells: show;
+}
+
+table.list tr.normal td {
+  background-color: white;
+  white-space: nowrap;
+}
+
+table.list tr.alt td {
+  background-color: #efefef;
+  white-space: nowrap;
+}
+
+table.list td:first-child {
+  border-left: 1px solid #404070;
+  border-right: 1px solid #404070;
+}
+
+table.list th:first-child {
+  border-left: 1px solid #404070;
+  border-right: 1px solid #404070;
+}
+
+table.list tr.navigation th {
+  text-align: right;
+}
+table.list tr.navigation th:first-child {
+  border-right: none;
+  text-align: left;
+}
+
+
+/* style for message displays */
+table.messages {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.messages th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.messages th {
+  font-weight: bold;
+  color: black;
+  text-align: left;
+  border-bottom: 1px solid #afafaf;
+}
+
+table.messages td {
+  font-family: monospace;
+  background-color: #efefef;
+  border-bottom: 1px solid #afafaf;
+  color: black;
+  empty-cells: show;
+  border-right: 1px solid #afafaf;
+  vertical-align: top;
+  padding: 2 5 2 5;
+}
+
+table.messages td:first-child {
+  border-left: 1px solid #afafaf;
+  border-right: 1px solid #afafaf;
+}
+
+/* style for file displays */
+table.files {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.files th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.files th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+}
+
+table.files td {
+  font-family: monospace;
+  empty-cells: show;
+}
+
+/* style for history displays */
+table.history {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.history th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+  font-size: 100%;
+}
+
+table.history th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+  font-size: 90%;
+}
+
+table.history td {
+  font-size: 90%;
+  vertical-align: top;
+  empty-cells: show;
+}
+
+
+/* style for class list */
+table.classlist {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.classlist th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.classlist th {
+  font-weight: bold;
+  text-align: left;
+}
+
+
+/* style for class help display */
+table.classhelp {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.classhelp th {
+  font-weight: bold;
+  text-align: left;
+  color: #707040;
+}
+
+table.classhelp td {
+  padding: 2 2 2 2;
+  border: 1px solid black;
+  text-align: left;
+  vertical-align: top;
+  empty-cells: show;
+}
+
+
+/* style for "other" displays */
+table.otherinfo {
+  border-spacing: 0px;
+  border-collapse: separate;
+  width: 100%;
+}
+
+table.otherinfo th.header{
+  padding-top: 10px;
+  border-bottom: 1px solid gray;
+  font-weight: bold;
+  background-color: white;
+  color: #707040;
+}
+
+table.otherinfo th {
+  border-bottom: 1px solid #afafaf;
+  font-weight: bold;
+  text-align: left;
+}
+
+input {
+    border: 1px solid #8cacbb;
+    color: Black;
+    background-color: white;
+    vertical-align: middle;
+    margin-bottom: 1px; /* IE bug fix */
+    padding: 0.1em;
+}
+
+select {
+    border: 1px solid #8cacbb;
+    color: Black;
+    background-color: white;
+    vertical-align: middle;
+    margin-bottom: 1px; /* IE bug fix */
+    padding: 0.1em;
+}
+
+
+a.nonexistent {
+    color: #FF2222;
+}
+a.nonexistent:visited {
+    color: #FF2222;
+}
+a.external {
+    color: #AA6600;
+}
+
+/*
+dl,ul,ol {
+    margin-top: 1pt;
+}
+tt,pre {
+    font-family: Lucida Console,Courier New,Courier,monotype;
+    font-size: 12pt;
+}
+pre.code {
+    margin-top: 8pt;
+    margin-bottom: 8pt;
+    background-color: #FFFFEE;
+    white-space:pre;
+    border-style:solid;
+    border-width:1pt;
+    border-color:#999999;
+    color:#111111;
+    padding:5px;
+    width:100%;
+}
+*/
+div.diffold {
+    background-color: #FFFF80;
+    border-style:none;
+    border-width:thin;
+    width:100%;
+}
+div.diffnew {
+    background-color: #80FF80;
+    border-style:none;
+    border-width:thin;
+    width:100%;
+}
+div.message {
+    margin-top: 6pt;
+    background-color: #E8FFE8;
+    border-style:solid;
+    border-width:1pt;
+    border-color:#999999;
+    color:#440000;
+    padding:5px;
+    width:100%;
+}
+strong.highlight {
+    background-color: #FFBBBB;
+/* as usual, NetScape fucks up with innocent CSS
+    border-color: #FFAAAA;
+    border-style: solid;
+    border-width: 1pt;
+*/
+}
+
+table.navibar {
+    background-color: #C8C8C8;
+    border-spacing: 3px;
+}
+td.navibar {
+    background-color: #E8E8E8;
+    vertical-align: top;
+    text-align: right;
+    padding: 0px;
+}
+
+div.pagename {
+    font-size: 140%;
+    color: blue;
+    text-align: center;
+    font-weight: bold;
+    background-color: white;
+    padding: 0 ;
+}
+
+a.wikiaction, input.wikiaction {
+    color: black; 
+    text-decoration: None;
+    text-align: center;
+    color: black;
+    /*border: 1px solid #3ba6ec; */
+    margin: 4px;
+    padding: 5;
+    padding-bottom: 0;
+    white-space: nowrap;
+}
+
+a.wikiaction[href]:hover { 
+       color: black; 
+       text-decoration: none; 
+       /*background-color: #dddddd; */
+}
+
+span.wikiuserpref {
+    padding-top: 1em;
+    font-size: 120%;
+}
+
+div.wikitrail {
+    vertical-align: bottom;
+    /*font-size: -1;*/
+    padding-top: 1em;
+    display: none;
+}
+
+div.wikiaction {
+    vertical-align: middle;
+    /*border-bottom: 1px solid #8cacbb;*/
+    padding-bottom:1em;
+    text-align: left;
+    width: 100%;
+}
+
+div.wikieditmenu {
+    text-align: right;
+}
+
+form.wikiedit {
+    border: 1px solid #8cacbb;
+    background-color: #f0f0f0;
+    background-color: #fabf00;
+    padding: 1em;
+    padding-right: 0em;
+}
+
+div.legenditem {
+    padding-top: 0.5em;
+    padding-left: 0.3em;
+}
+
+span.wikitoken {
+   background-color: #eeeeee;
+}
+    
+
+div#contentspace h1:first-child, div.heading:first-child { 
+  padding-top: 0;
+  margin-top: 0;
+}
+div#contentspace h2:first-child { 
+  padding-top: 0;
+  margin-top: 0;
+}
+
+/* heading and paragraph text */
+
+div.heading, h1 {
+    font-family: Verdana, Helvetica, Arial, sans-serif;
+    background-color: #58b3ef;
+    background-color: #FFFFFF; 
+    /*color: #4893cf;*/
+    color: black;
+    padding-top: 1.0em;
+    padding-bottom:0.2em;
+    text-align: left;
+    margin-top: 0em; 
+    /*margin-bottom:8pt;*/
+    font-weight: bold;
+    font-size: 115%;
+    border-bottom: 1px solid #8CACBB;
+}
+
+
+h1, h2, h3, h4, h5, h6 {
+    color: orange;
+    clear: left;
+    font: 100% Verdana, Helvetica, Arial, sans-serif;
+    margin: 0;
+    padding-left: 0em;
+    padding-top: 1em;
+    padding-bottom: 0.2em;
+    /*border-bottom: 1px solid #8CACBB;*/
+}
+/* h1,h2 { padding-top: 0; }*/
+
+
+h1 { font-size: 145%; }
+h2 { font-size: 135%; }
+h3 { font-size: 125%; }
+h4 { font-size: 120%; }
+h5 { font-size: 110%; }
+h6 { font-size: 80%; }
+
+h1 a { text-decoration: None;}
+
+div.exception {
+  background-color: #bb2222;
+  padding: 5 5 5 5;
+  color: white;
+  font-weight: bold;
+}
+pre.exception {
+    font-size: 110%;
+    padding: 1em;
+    border: 1px solid #8cacbb;
+    color: Black;
+    background-color: #dee7ec;
+    background-color: #cccccc;
+}
+
+/* defines for navgiation bar (documentation) */
+
+
+div.direntry {
+    padding-top: 0.3em;
+    padding-bottom: 0.3em;
+    margin-right: 1em;
+    font-weight: bold;
+    background-color: #dee7ec;
+    font-size: 110%;
+}
+
+div.fileentry {
+    font-family: Verdana, Helvetica, Arial, sans-serif;
+    padding-bottom: 0.3em;
+    white-space: nowrap;
+    line-height: 150%;
+}
+
+a.fileentry {
+    white-space: nowrap;
+}
+
+
+span.left {
+    text-align: left;
+}
+span.right {
+    text-align: right;
+}
+
+div.navbar {
+  /*margin: 0;*/
+  font-size: 80% /*smaller*/;
+  font-weight: bold;
+  text-align: left;
+  /* position: fixed; */
+  top: 100pt;
+  left: 0pt; /*  auto; */
+  width: 120pt;
+  /* right: auto;
+  right: 0pt;  2em; */
+}
+
+
+div.history a {
+    /* font-size: 70%; */
+}
+
+div.wikiactiontitle { 
+  font-weight: bold;
+}
+
+/*  REST  defines */
+
+div.document {
+    margin: 0;
+}
+
+h1.title {
+    margin: 0;
+    margin-bottom: 0.5em;
+}
+
+td.toplist {
+    vertical-align: top;
+}
+
+img#pyimg {
+    position: absolute;
+    top: 4px;
+    left: 4px;
+}
+    
+div#navspace {
+    position: absolute;
+    top: 130px;
+    left: 11px;
+    font-size: 100%;
+    width: 150px;
+    overflow: hidden; /* scroll;  */
+}
+
+div#metaspace {
+    position: absolute;
+    top: 40px;
+    left: 170px;
+}
+
+div#errorline {
+    position: relative;
+    top: 5px; 
+    float: right; 
+}
+
+div#contentspace {
+    position: absolute;
+       /* font: 120% "Times New Roman", serif;*/
+    font: 110% Verdana, Helvetica, Arial, sans-serif;
+    top: 130px;
+    left: 170px;
+    margin-right: 5px;
+}
+
+div#menubar {
+/*    width: 400px; */
+    float: left;
+}
+
+/* for the documentation page */
+div#docinfoline {
+  position: relative;
+  top: 5px; 
+  left: 0px;
+
+  /*background-color: #dee7ec; */
+  padding: 5pt; 
+  padding-bottom: 1em; 
+  color: black;
+  /*border-width: 1pt;
+  border-style: solid;*/
+
+}
+
+div#docnavlist {
+  /*background-color: #dee7ec; */
+  padding: 5pt; 
+  padding-bottom: 2em; 
+  color: black;
+  border-width: 1pt;
+  /*border-style: solid;*/
+}
+
+
+/* text markup */
+
+div.listtitle {
+    color: Black;
+    clear: left;
+    font: 120% Verdana, Helvetica, Arial, sans-serif;
+    margin: 0;
+    padding-left: 0em;
+    padding-top: 0em;
+    padding-bottom: 0.2em;
+    margin-right: 0.5em;
+    border-bottom: 1px solid #8CACBB;
+}
+
+div.actionbox h3 { 
+  padding-top: 0;
+  padding-right: 0.5em;
+  padding-left: 0.5em;
+  background-color: #fabf00;
+  text-align: center;
+  border: 1px solid black; /* 8cacbb; */
+}
+
+div.actionbox a { 
+  display: block;
+  padding-bottom: 0.5em;
+  padding-top: 0.5em;
+  margin-left: 0.5em;
+}
+
+div.actionbox a.history { 
+  display: block;
+  padding-bottom: 0.5em;
+  padding-top: 0.5em;
+  margin-left: 0.5em;
+  font-size: 90%; 
+}
+
+div.actionbox { 
+  margin-bottom: 2em;
+  padding-bottom: 1em;
+  overflow: hidden; /* scroll;  */
+}
+
+/* taken from docutils (oh dear, a bit senseless) */
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:date: $Date: 2003/01/22 22:26:48 $
+:version: $Revision: 1.29 $
+:copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+*/
+/*
+.first {
+  margin-top: 0 }
+
+.last {
+  margin-bottom: 0 }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+dd {
+  margin-bottom: 0.5em }
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.attention, div.caution, div.danger, div.error, div.hint,
+div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.hint p.admonition-title, div.important p.admonition-title,
+div.note p.admonition-title, div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  font-size: smaller }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.title {
+  text-align: center ;
+  color: orange}
+
+h2.subtitle {
+  color: orange;
+  text-align: center }
+
+hr {
+  width: 75% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.option-argument {
+  font-style: italic }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+table {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.citation {
+  border-left: solid thin gray ;
+  padding-left: 0.5ex }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.footnote {
+  border-left: solid thin black ;
+  padding-left: 0.5ex }
+
+td, th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+th.docinfo-name, th.field-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap }
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+  font-size: 100% }
+
+tt {
+  background-color: #eeeeee }
+
+ul.auto-toc {
+  list-style-type: none }
+*/
+
+div.section {
+  margin-top: 1.0em ;
+}    
diff --git a/src/doc/eole-report/eolreport/build/docutils.css b/src/doc/eole-report/eolreport/build/docutils.css
new file mode 100644 (file)
index 0000000..f03e03d
--- /dev/null
@@ -0,0 +1,255 @@
+.first {
+  margin-top: 0 ! important }
+
+.last {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: inherit }
+
+blockquote.epigraph {
+  margin: 2em 5em }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+dl.docutils dt {
+  font-weight: bold }
+
+dl dt { line-height: 150% }
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.document {
+  width: 600px ;
+  margin-left: 5em ;
+  margin-right: 5em }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin-left: 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1, h2, h3, h4, h5 {
+  font-family: sans-serif ;
+  line-height: 150% ;
+  color: orange} /* #666 } */
+
+h1.title {
+  text-align: center
+  }
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  font-size: small ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.option-argument {
+  font-style: italic }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+table.citation {
+  border-left: solid thin gray }
+
+table.docinfo {
+  /* float: right ; */
+  margin: 2em 4em ;
+  color: #666 }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+th.docinfo-name, th.field-name {
+  font-weight: bold ;
+  text-align: right ;
+  white-space: nowrap }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+tt.docutils {
+  background-color: #eeeeee }
+
+ul.auto-toc {
+  list-style-type: none }
+
diff --git a/src/doc/eole-report/eolreport/build/imgs/eol.png b/src/doc/eole-report/eolreport/build/imgs/eol.png
new file mode 100644 (file)
index 0000000..5b23138
Binary files /dev/null and b/src/doc/eole-report/eolreport/build/imgs/eol.png differ
diff --git a/src/doc/eole-report/eolreport/build/imgs/logo.png b/src/doc/eole-report/eolreport/build/imgs/logo.png
new file mode 100644 (file)
index 0000000..9c554f4
Binary files /dev/null and b/src/doc/eole-report/eolreport/build/imgs/logo.png differ
diff --git a/src/doc/eole-report/eolreport/build/index-report.html b/src/doc/eole-report/eolreport/build/index-report.html
new file mode 100644 (file)
index 0000000..a0597f8
--- /dev/null
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.8.1: http://docutils.sourceforge.net/" />
+<title>rapports eole</title>
+<style type="text/css">
+
+@import url(docutils.css);
+@import url(default.css);
+a:link {
+       color: orange;
+       font-weight: bold;
+       text-decoration: none;
+}
+a:visited {
+       text-decoration: none;
+       color: #999999;
+}
+a:hover {
+       text-decoration: none;
+       color: #999999;
+}
+a:active {
+       text-decoration: none;
+       color: #999999;
+}
+
+.header {
+       color: orange;
+       background-color: white;
+       padding: 1em;
+}
+.footer {
+       color: #666;
+       background-color: inherit;
+       font-size: 75%;
+}
+
+
+
+</style>
+</head>
+<body>
+<div class="document">
+
+
+<img alt="imgs/eol.png" class="align-right" src="imgs/eol.png" />
+<table class="docutils field-list" frame="void" rules="none">
+<col class="field-name" />
+<col class="field-body" />
+<tbody valign="top">
+<tr class="field"><th class="field-name">date:</th><td class="field-body">mai 2012</td>
+</tr>
+<tr class="field"><th class="field-name">description:</th><td class="field-body">rapports <tt class="docutils literal">Créole</tt>, compatibilités <tt class="docutils literal">Creole</tt> et <tt class="docutils literal">tiramisu</tt></td>
+</tr>
+</tbody>
+</table>
+<div class="section" id="vue-d-ensemble-des-rapports">
+<h1>Vue d'ensemble des rapports</h1>
+<p>Les rapports ci-dessous résument et permettent de donner des points d'appui à
+des discussions de recherche et développement concernant l'évolution du
+projet <tt class="docutils literal">Creole</tt> (comprenant <tt class="docutils literal">Creole_Serv</tt>). Il y a aussi le support de
+documentation développeur <tt class="docutils literal">tiramisu</tt> (en anglais) qui constitue une bonne
+base pour connaître et comprendre plus en détails les motivations de
+la nouvelle implementation.</p>
+<ul class="simple">
+<li><a class="reference external" href="pdfreport/D01AccesVariables.pdf">D01AccesVariables.pdf</a></li>
+<li><a class="reference external" href="pdfreport/D02CoherenceVariables.pdf">D02CoherenceVariables.pdf</a></li>
+<li><a class="reference external" href="pdfreport/D03ReglesEtats.pdf">D03ReglesEtats.pdf</a></li>
+</ul>
+</div>
+</div>
+</body>
+</html>
diff --git a/src/doc/eole-report/eolreport/build/pdfreport/D01AccesVariables.pdf b/src/doc/eole-report/eolreport/build/pdfreport/D01AccesVariables.pdf
new file mode 100644 (file)
index 0000000..471a375
Binary files /dev/null and b/src/doc/eole-report/eolreport/build/pdfreport/D01AccesVariables.pdf differ
diff --git a/src/doc/eole-report/eolreport/build/pdfreport/D02CoherenceVariables.pdf b/src/doc/eole-report/eolreport/build/pdfreport/D02CoherenceVariables.pdf
new file mode 100644 (file)
index 0000000..d8c37fe
Binary files /dev/null and b/src/doc/eole-report/eolreport/build/pdfreport/D02CoherenceVariables.pdf differ
diff --git a/src/doc/eole-report/eolreport/build/pdfreport/D03ReglesEtats.pdf b/src/doc/eole-report/eolreport/build/pdfreport/D03ReglesEtats.pdf
new file mode 100644 (file)
index 0000000..7ec977c
Binary files /dev/null and b/src/doc/eole-report/eolreport/build/pdfreport/D03ReglesEtats.pdf differ
diff --git a/src/doc/eole-report/eolreport/build/pdfreport/make_index b/src/doc/eole-report/eolreport/build/pdfreport/make_index
new file mode 100755 (executable)
index 0000000..ca207c8
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+import sys
+from glob import glob
+from os.path import isfile, dirname, abspath, join, basename, splitext
+from rst import Rest, Paragraph, Strong, ListItem, Link
+
+
+here = abspath(dirname(__file__))
+html = glob(join(here, '*.pdf'))
+
+basehtml = [basename(htm) for htm in html]
+basehtml.sort()
+
+content = Rest()
+
+for htm in basehtml:
+    link = Link( htm , "pdfreport/" +htm)
+    content.add(ListItem(link))
+
+sys.stdout.write(content.text())
+
+
diff --git a/src/doc/eole-report/eolreport/build/pdfreport/rst.py b/src/doc/eole-report/eolreport/build/pdfreport/rst.py
new file mode 100644 (file)
index 0000000..7548cdd
--- /dev/null
@@ -0,0 +1,410 @@
+# unproudly borrowed from pypy : 
+# http://codespeak.net/svn/pypy/trunk/pypy/tool/rest/rst.py
+""" reStructuredText generation tools
+
+    provides an api to build a tree from nodes, which can be converted to
+    ReStructuredText on demand
+
+    note that not all of ReST is supported, a usable subset is offered, but
+    certain features aren't supported, and also certain details (like how links
+    are generated, or how escaping is done) can not be controlled
+"""
+
+import re
+
+def escape(txt):
+    """escape ReST markup"""
+    if not isinstance(txt, str) and not isinstance(txt, unicode):
+        txt = str(txt)
+    # XXX this takes a very naive approach to escaping, but it seems to be
+    # sufficient...
+    for c in '\\*`|:_':
+        txt = txt.replace(c, '\\%s' % (c,))
+    return txt
+
+class RestError(Exception):
+    """ raised on containment errors (wrong parent) """
+
+class AbstractMetaclass(type):
+    def __new__(cls, *args):
+        obj = super(AbstractMetaclass, cls).__new__(cls, *args)
+        parent_cls = obj.parentclass
+        if parent_cls is None:
+            return obj
+        if not isinstance(parent_cls, list):
+            class_list = [parent_cls]
+        else:
+            class_list = parent_cls
+        if obj.allow_nesting:
+            class_list.append(obj)
+        
+        for _class in class_list:
+            if not _class.allowed_child:
+                _class.allowed_child = {obj:True}
+            else:
+                _class.allowed_child[obj] = True
+        return obj
+
+class AbstractNode(object):
+    """ Base class implementing rest generation
+    """
+    sep = ''
+    __metaclass__ = AbstractMetaclass
+    parentclass = None # this exists to allow parent to know what
+        # children can exist
+    allow_nesting = False
+    allowed_child = {}
+    defaults = {}
+    
+    _reg_whitespace = re.compile('\s+')
+
+    def __init__(self, *args, **kwargs):
+        self.parent = None
+        self.children = []
+        for child in args:
+            self._add(child)
+        for arg in kwargs:
+            setattr(self, arg, kwargs[arg])
+    
+    def join(self, *children):
+        """ add child nodes
+        
+            returns a reference to self
+        """
+        for child in children:
+            self._add(child)
+        return self
+    
+    def add(self, child):
+        """ adds a child node
+            
+            returns a reference to the child
+        """
+        self._add(child)
+        return child
+        
+    def _add(self, child):
+        if child.__class__ not in self.allowed_child:
+            raise RestError("%r cannot be child of %r" % \
+                (child.__class__, self.__class__))
+        self.children.append(child)
+        child.parent = self
+    
+    def __getitem__(self, item):
+        return self.children[item]
+    
+    def __setitem__(self, item, value):
+        self.children[item] = value
+
+    def text(self):
+        """ return a ReST string representation of the node """
+        return self.sep.join([child.text() for child in self.children])
+    
+    def wordlist(self):
+        """ return a list of ReST strings for this node and its children """ 
+        return [self.text()]
+
+class Rest(AbstractNode):
+    """ Root node of a document """
+    
+    sep = "\n\n"
+    def __init__(self, *args, **kwargs):
+        AbstractNode.__init__(self, *args, **kwargs)
+        self.links = {}
+    
+    def render_links(self, check=False):
+        """render the link attachments of the document"""
+        assert not check, "Link checking not implemented"
+        if not self.links:
+            return ""
+        link_texts = []
+        # XXX this could check for duplicates and remove them...
+        for link, target in self.links.iteritems():
+            link_texts.append(".. _`%s`: %s" % (escape(link), target))
+        return "\n" + "\n".join(link_texts) + "\n\n"
+
+    def text(self):
+        outcome = []
+        if (isinstance(self.children[0], Transition) or
+                isinstance(self.children[-1], Transition)):
+            raise ValueError, ('document must not begin or end with a '
+                               'transition')
+        for child in self.children:
+            outcome.append(child.text())
+        
+        # always a trailing newline
+        text = self.sep.join([i for i in outcome if i]) + "\n"
+        return text + self.render_links()
+
+class Transition(AbstractNode):
+    """ a horizontal line """
+    parentclass = Rest
+
+    def __init__(self, char='-', width=80, *args, **kwargs):
+        self.char = char
+        self.width = width
+        super(Transition, self).__init__(*args, **kwargs)
+        
+    def text(self):
+        return (self.width - 1) * self.char
+
+class Paragraph(AbstractNode):
+    """ simple paragraph """
+
+    parentclass = Rest
+    sep = " "
+    indent = ""
+    # FIXME
+    width = 880
+    
+    def __init__(self, *args, **kwargs):
+        # make shortcut
+        args = list(args)
+        for num, arg in enumerate(args):
+            if isinstance(arg, str):
+                args[num] = Text(arg)
+        super(Paragraph, self).__init__(*args, **kwargs)
+    
+    def text(self):
+        texts = []
+        for child in self.children:
+            texts += child.wordlist()
+        
+        buf = []
+        outcome = []
+        lgt = len(self.indent)
+        
+        def grab(buf):
+            outcome.append(self.indent + self.sep.join(buf))
+        
+        texts.reverse()
+        while texts:
+            next = texts[-1]
+            if not next:
+                texts.pop()
+                continue
+            if lgt + len(self.sep) + len(next) <= self.width or not buf:
+                buf.append(next)
+                lgt += len(next) + len(self.sep)
+                texts.pop()
+            else:
+                grab(buf)
+                lgt = len(self.indent)
+                buf = []
+        grab(buf)
+        return "\n".join(outcome)
+    
+class SubParagraph(Paragraph):
+    """ indented sub paragraph """
+
+    indent = " "
+    
+class Title(Paragraph):
+    """ title element """
+
+    parentclass = Rest
+    belowchar = "="
+    abovechar = ""
+    
+    def text(self):
+        txt = self._get_text()
+        lines = []
+        if self.abovechar:
+            lines.append(self.abovechar * len(txt))
+        lines.append(txt)
+        if self.belowchar:
+            lines.append(self.belowchar * len(txt))
+        return "\n".join(lines)
+
+    def _get_text(self):
+        txt = []
+        for node in self.children:
+            txt += node.wordlist()
+        return ' '.join(txt)
+
+class AbstractText(AbstractNode):
+    parentclass = [Paragraph, Title]
+    start = ""
+    end = ""
+    def __init__(self, _text):
+        self._text = _text
+    
+    def text(self):
+        text = self.escape(self._text)
+        return self.start + text + self.end
+
+    def escape(self, text):
+        if not isinstance(text, str) and not isinstance(text, unicode):
+            text = str(text)
+        if self.start:
+            text = text.replace(self.start, '\\%s' % (self.start,))
+        if self.end and self.end != self.start:
+            text = text.replace(self.end, '\\%s' % (self.end,))
+        return text
+    
+class Text(AbstractText):
+    def wordlist(self):
+        text = escape(self._text)
+        return self._reg_whitespace.split(text)
+
+class LiteralBlock(AbstractText):
+    parentclass = Rest
+    start = '::\n\n'
+
+    def text(self):
+        if not self._text.strip():
+            return ''
+        text = self.escape(self._text).split('\n')
+        for i, line in enumerate(text):
+            if line.strip():
+                text[i] = '  %s' % (line,)
+        return self.start + '\n'.join(text)
+
+class Em(AbstractText):
+    start = "*"
+    end = "*"
+
+class Strong(AbstractText):
+    start = "**"
+    end = "**"
+
+class Quote(AbstractText):
+    start = '``'
+    end = '``'
+
+class Anchor(AbstractText):
+    start = '_`'
+    end = '`'
+
+class Footnote(AbstractText):
+    def __init__(self, note, symbol=False):
+        raise NotImplemented('XXX')
+
+class Citation(AbstractText):
+    def __init__(self, text, cite):
+        raise NotImplemented('XXX')
+
+class ListItem(Paragraph):
+    allow_nesting = True
+    item_chars = '*+-'
+    
+    def text(self):
+        idepth = self.get_indent_depth()
+        indent = self.indent + (idepth + 1) * '  '
+        txt = '\n\n'.join(self.render_children(indent))
+        ret = []
+        item_char = self.item_chars[idepth]
+        ret += [indent[len(item_char)+1:], item_char, ' ', txt[len(indent):]]
+        return ''.join(ret)
+    
+    def render_children(self, indent):
+        txt = []
+        buffer = []
+        def render_buffer(fro, to):
+            if not fro:
+                return
+            p = Paragraph(indent=indent, *fro)
+            p.parent = self.parent
+            to.append(p.text())
+        for child in self.children:
+            if isinstance(child, AbstractText):
+                buffer.append(child)
+            else:
+                if buffer:
+                    render_buffer(buffer, txt)
+                    buffer = []
+                txt.append(child.text())
+
+        render_buffer(buffer, txt)
+        return txt
+
+    def get_indent_depth(self):
+        depth = 0
+        current = self
+        while (current.parent is not None and
+                isinstance(current.parent, ListItem)):
+            depth += 1
+            current = current.parent
+        return depth
+
+class OrderedListItem(ListItem):
+    item_chars = ["#."] * 5
+
+class DListItem(ListItem):
+    item_chars = None
+    def __init__(self, term, definition, *args, **kwargs):
+        self.term = term
+        super(DListItem, self).__init__(definition, *args, **kwargs)
+
+    def text(self):
+        idepth = self.get_indent_depth()
+        indent = self.indent + (idepth + 1) * '  '
+        txt = '\n\n'.join(self.render_children(indent))
+        ret = []
+        ret += [indent[2:], self.term, '\n', txt]
+        return ''.join(ret)
+
+class Link(AbstractText):
+    start = '`'
+    end = '`_'
+
+    def __init__(self, _text, target):
+        self._text = _text
+        self.target = target
+        self.rest = None
+    
+    def text(self):
+        if self.rest is None:
+            self.rest = self.find_rest()
+        if self.rest.links.get(self._text, self.target) != self.target:
+            raise ValueError('link name %r already in use for a different '
+                             'target' % (self.target,))
+        self.rest.links[self._text] = self.target
+        return AbstractText.text(self)
+
+    def find_rest(self):
+        # XXX little overkill, but who cares...
+        next = self
+        while next.parent is not None:
+            next = next.parent
+        return next
+
+class InternalLink(AbstractText):
+    start = '`'
+    end = '`_'
+    
+class LinkTarget(Paragraph):
+    def __init__(self, name, target):
+        self.name = name
+        self.target = target
+    
+    def text(self):
+        return ".. _`%s`:%s\n" % (self.name, self.target)
+
+class Substitution(AbstractText):
+    def __init__(self, text, **kwargs):
+        raise NotImplemented('XXX')
+
+class Directive(Paragraph):
+    indent = '   '
+    def __init__(self, name, *args, **options):
+        self.name = name
+        self.content = args
+        super(Directive, self).__init__()
+        self.options = options
+        
+    def text(self):
+        # XXX not very pretty...
+        txt = '.. %s::' % (self.name,)
+        options = '\n'.join(['    :%s: %s' % (k, v) for (k, v) in
+                             self.options.iteritems()])
+        if options:
+            txt += '\n%s' % (options,)
+
+        if self.content:
+            txt += '\n'
+            for item in self.content:
+                txt += '\n    ' + item
+        
+        return txt
+
diff --git a/src/doc/eole-report/eolreport/build/style.css b/src/doc/eole-report/eolreport/build/style.css
new file mode 100644 (file)
index 0000000..28c256e
--- /dev/null
@@ -0,0 +1,32 @@
+@import url(docutils.css);
+@import url(default.css);
+a:link {
+       color: orange;
+       font-weight: bold;
+       text-decoration: none;
+}
+a:visited {
+       text-decoration: none;
+       color: #999999;
+}
+a:hover {
+       text-decoration: none;
+       color: #999999;
+}
+a:active {
+       text-decoration: none;
+       color: #999999;
+}
+
+.header {
+       color: orange;
+       background-color: white;
+       padding: 1em;
+}
+.footer {
+       color: #666;
+       background-color: inherit;
+       font-size: 75%;
+}
+
+
diff --git a/src/doc/eole-report/eolreport/inc/00-Redacteur.txt b/src/doc/eole-report/eolreport/inc/00-Redacteur.txt
new file mode 100644 (file)
index 0000000..554e81b
--- /dev/null
@@ -0,0 +1,12 @@
+.. container:: rubric
+
+    **Rédacteurs**
+
+           | Gwenaël Rémond (gremond@cadoles.com)
+           | Emmanuel Garette (egarette@cadoles.com)
+
+**Référence**
+
+    | ``tiramisu/doc/eole-reports``
+    | ``git clone ssh://gitosis@git.cadol.es:2222/tiramisu.git``
+    
diff --git a/src/doc/eole-report/eolreport/inc/eol.png b/src/doc/eole-report/eolreport/inc/eol.png
new file mode 100644 (file)
index 0000000..5b23138
Binary files /dev/null and b/src/doc/eole-report/eolreport/inc/eol.png differ
diff --git a/src/doc/eole-report/eolreport/inc/logo.png b/src/doc/eole-report/eolreport/inc/logo.png
new file mode 100644 (file)
index 0000000..9c554f4
Binary files /dev/null and b/src/doc/eole-report/eolreport/inc/logo.png differ
diff --git a/src/doc/eole-report/eolreport/inc/menjva.gif b/src/doc/eole-report/eolreport/inc/menjva.gif
new file mode 100644 (file)
index 0000000..49d17a6
Binary files /dev/null and b/src/doc/eole-report/eolreport/inc/menjva.gif differ
diff --git a/src/doc/eole-report/eolreport/inc/preambule.txt b/src/doc/eole-report/eolreport/inc/preambule.txt
new file mode 100644 (file)
index 0000000..c25bb90
--- /dev/null
@@ -0,0 +1,18 @@
+.. csv-table::
+
+    .. image:: inc/logo.png, .. image:: inc/eol.png
+
+.. container:: title
+
+  Rapports de discussions de recherche et développements 
+
+------------
+
+.. container:: subtitle
+
+  Comparaison ``tiramisu`` et ``Créole`` 
+
+.. include:: 00-Redacteur.txt
+
+
+
diff --git a/src/doc/eole-report/eolreport/index-report.txt b/src/doc/eole-report/eolreport/index-report.txt
new file mode 100644 (file)
index 0000000..4670b94
--- /dev/null
@@ -0,0 +1,33 @@
+.. default-role:: literal
+
+.. title:: rapports eole
+
+
+.. image:: imgs/eol.png
+    :align: right
+
+:date: mai 2012
+:description: rapports `Créole`, compatibilités `Creole` et `tiramisu`
+
+
+Vue d'ensemble des rapports
+===================================
+
+Les rapports ci-dessous résument et permettent de donner des points d'appui à 
+des discussions de recherche et développement concernant l'évolution du 
+projet `Creole` (comprenant `Creole_Serv`). Il y a aussi le support de 
+documentation développeur `tiramisu` (en anglais) qui constitue une bonne 
+base pour connaître et comprendre plus en détails les motivations de 
+la nouvelle implementation.
+
+
+* `D01AccesVariables.pdf`_
+
+* `D02CoherenceVariables.pdf`_
+
+* `D03ReglesEtats.pdf`_
+
+.. _`D03ReglesEtats.pdf`: pdfreport/D03ReglesEtats.pdf
+.. _`D02CoherenceVariables.pdf`: pdfreport/D02CoherenceVariables.pdf
+.. _`D01AccesVariables.pdf`: pdfreport/D01AccesVariables.pdf
+
diff --git a/src/doc/eole-report/eolreport/styles.odt b/src/doc/eole-report/eolreport/styles.odt
new file mode 100644 (file)
index 0000000..2121251
Binary files /dev/null and b/src/doc/eole-report/eolreport/styles.odt differ
diff --git a/src/doc/eole-report/presentation/Makefile b/src/doc/eole-report/presentation/Makefile
new file mode 100644 (file)
index 0000000..7b32a56
--- /dev/null
@@ -0,0 +1,12 @@
+SRC=$(wildcard *.tex)
+OBJ=$(subst .tex,.pdf,$(SRC))
+
+pdf: $(OBJ)
+
+%.pdf: %.tex
+       pdflatex $< 
+
+clean:
+       rm -f $(OBJ)
+       rm -f *.aux *.log *.toc *.snm *.out *.nav
+       
diff --git a/src/doc/eole-report/presentation/definition.tex b/src/doc/eole-report/presentation/definition.tex
new file mode 100644 (file)
index 0000000..4bbea9f
--- /dev/null
@@ -0,0 +1,69 @@
+\begin{frame}
+ \frametitle{Comparaison entre le noyau de Créole et Tiramisu}
+ \begin{itemize}
+  \item \emph{Tiramisu} a pour objectif de 
+  \begin{itemize}
+  \item remplacer le noyau \emph{Creole} (\texttt{EoleDict}) de manière transparente ; 
+  \item résoudre les problèmes inhérents à \texttt{CreoleServ} ;
+  \end{itemize}
+  \item au niveau du code, il y a enfin une vraie séparation du c\oe ur et du fonctionnel ;
+  \item valide le type \emph{et la structure}, l'ajout de types est aisé.
+  \item \emph{Creole} : \texttt{EoleDict, EoleVars} $ \Leftrightarrow $ \texttt{Config, Option}\\
+  cf \texttt{tiramisu/doc/build/pydoc/index.html}
+  \item intégré à \texttt{gen\_config}, \texttt{cheetah}, \texttt{DTD Creole}, syntaxe \texttt{Creole} \dots
+  \item \texttt{eole-report/D02CoherenceVariables.pdf}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}
+ \frametitle{Gestionnaire de configuration existants}
+ \begin{itemize}
+  \item Le gestionnaire de conf de Victor Stinner $\Rightarrow$ \emph{NuFw}; 
+  \item puppet, cfgengine... $\Rightarrow$ intéressant, de nombreux comportements peuvent être repris, mais tel quel difficilement compatible avec \emph{Creole};
+  \item \emph{Creole} $\Leftrightarrow$ \texttt{tiramisu/doc/build/glossary.html}
+\end{itemize}
+\end{frame}
+
+\begin{frame}
+ \frametitle{Un "vrai" serveur de config}
+ \begin{itemize}
+  \item un serveur de données de configuration ;
+  \item $1^{ere}$ méthode : exportation (snapshot) d'un état de la config $ \Rightarrow $ Créole ;
+  \item $2^{eme}$ méthode : JIT (just in time) calculation, une modification 
+de l'état de la configuration est possible \emph{pendant} la manipulation et l'utilisation de la conf $ \Rightarrow $ Tiramisu.
+  \item \texttt{doc/getting-started.html}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}
+ \frametitle{Qu'est-ce qu'un gestionnaire de conf moderne ?}
+ \begin{itemize}
+  \item c'est une organisation arborescente des données (les données sont imbriquées) ;
+  \item c'est un accès facile aux données (typiquement une interface de type \emph{dictionnaire}) ;
+  \item clefs-valeurs, mais quelles valeurs exactement ? $ \Rightarrow $ calcul JIT (just in time) ;
+  \item \texttt{eole-report/D01AccesVariables.pdf}
+\end{itemize}
+\end{frame}
+
+\begin{frame}
+ \frametitle{Définition d'un gestionnaire de configuration}
+ \begin{itemize}
+  \item les families, groups, master \dots~ ce sont des \emph{schémas} de données (\texttt{OptionDescription}) ;
+  \item c'est la configuration (\texttt{Config}) qui est responsable de l'accès aux valeurs ;
+  \item la configuration est aisément manipulable, et a un point d'entrée unique ;
+  \item l'accès aux valeurs des \texttt{Options} de configuration ne peut se faire \emph{que} depuis la conf racine.
+  \item \texttt{eole-report/D01AccesVariables.pdf}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}
+ \frametitle{Organisation en espace de nommage}
+ \begin{itemize}
+  \item dans \emph{tiramisu} l'accent est mis sur l'organisation arborescente des données ;
+  \item la validation des options de configuration se fait par l'appartenance aux groupes (families, master/slaves \dots) ;
+  \item l'organisation en groupes est unifiée par l'espace de nommage ;
+  \item \texttt{eole-report/D03ReglesEtats.pdf}
+  \item lisibilité d'une config : \texttt{tiramisu/report/build/index.html} rapport html d'une config
+ \end{itemize}
+\end{frame}
+
diff --git a/src/doc/eole-report/presentation/statut.tex b/src/doc/eole-report/presentation/statut.tex
new file mode 100644 (file)
index 0000000..1bee414
--- /dev/null
@@ -0,0 +1,61 @@
+
+\begin{frame}
+ \frametitle{Etats ("status") de la configuration}
+ \begin{itemize}
+  \item système d'états de la configuration par \emph{droits d'accès} ;
+  \item \texttt{read write}, \texttt{read only} ;
+  \item correspond à \texttt{freeze}, \texttt{hidden}, \texttt{disabled} \dots ;
+  \item \texttt{doc/status.html} ;
+  \item \texttt{eole-report/D03ReglesEtats.pdf} ;
+ \end{itemize}
+\end{frame}
+
+\begin{frame}
+ \frametitle{hidden if in, hidden if not in}
+ \begin{itemize}
+ \item les hidden if in, disabled if, \dots sont généralisés
+ \item dans tiramisu, ce sont des pré-requis sur une (des) variables
+ \item \texttt{eole-report/D03ReglesEtats.pdf}
+ \item \texttt{doc/consistency.html}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}
+ \frametitle{un peu de mathématiques : prévenir les deadlocks}
+ \begin{itemize}
+\item sûreté : prévention des deadlocks ; 
+\item dans tiramisu, le modèle est suffisamment abstrait pour que son exploitation mathématique soit 
+réalisable par les techniques de \emph{Model Checking} ; 
+\item soit on a besoin de ne connaître que l'ensemble des états, pas leurs liens $\Rightarrow$ espace d'états ; 
+\item soit on a besoin de connaître toutes les relations $\Rightarrow$ graphe d'accessibilité ; 
+\item la configuration est modélisable en une structure de \emph{Kripe} ;
+\item déjà le parsing de la conf est facile, la preuve : \texttt{tiramisu/report/build/index.html}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}
+ \frametitle{un peu de mathématiques (suite) CreoleLint}
+ \begin{itemize}
+\item exemple : $ P = 3 \wedge Q = 1 \triangleleft \langle P = 1 \hookleftarrow Q = 0 \rangle$
+\item la propriété \og dans aucun état on a $P = 3$ et $Q = 1$  \fg~ est-elle vraie ? 
+Pour vérifier cette propriété, on a besoin de connaître l'espace d'états ;
+\item la propriété \og chaque chemin débutant dans un état accessible $P=1$ passe par un état où $Q=3$ et $P=2$ \fg~  
+est-elle vraie ? Cela demande de connaître le graphe d'accessibilité ; 
+\item les structures de \emph{Kripe} sont des machines à états étiquetées par les valuations de toutes les variables propositionnelles ;
+\item une compliation statique devient possible dans \emph{CreoleLint} \dots
+ \end{itemize}
+\end{frame}
+
+\begin{frame}
+ \frametitle{compatibilité Créole : ce qui reste à faire}
+ \begin{itemize}
+\item les options spéciales sont implémentées (auto, fill, obligatoire, \dots) reste la librairie des fonctions pour les variables automatiques \texttt{eosfunc} ;
+\item tous les états sont implémentés (hidden, disabled, mode (normal/expert), \dots), il faut fixer les comportement \texttt{read write} ; 
+\item les "valprec" (valeur précédentes) et une mémoire de \emph{tous} les états antérieurs ; 
+\item fixer les comportement des hides (sous-groupes récursifs, \dots) ;
+\item validations master/slaves, validations globales au regard de la configuration entière puisque c'est possible maintenant.
+\end{itemize}
+
+\end{frame}
+
+
diff --git a/src/doc/eole-report/presentation/tiramisu.tex b/src/doc/eole-report/presentation/tiramisu.tex
new file mode 100644 (file)
index 0000000..a6067c9
--- /dev/null
@@ -0,0 +1,36 @@
+%%presentation
+\documentclass{beamer}
+\usepackage{beamerthemetree}
+%%impression
+%\documentclass[a4paper,9pt]{extarticle}
+%\usepackage{beamerarticle}
+%%
+
+% class FR
+\usepackage[T1]{fontenc}
+\usepackage[utf8]{inputenc}
+\usepackage[frenchb]{babel}
+
+% image
+%% \usepackage{graphicx}
+\usepackage{alltt}
+\usecolortheme{crane}
+\beamertemplatetransparentcovered
+%\logo{\includegraphics[height=1cm]{ban.png}}
+
+\title{Tiramisu}
+\subtitle{gestionnaire de configuration}
+\author{Gwen}
+\institute{\texttt{git clone git://git.labs.libre-entreprise.org/tiramisu.git} \\ 
+\texttt{firefox tiramisu/doc/build/index.html}}
+
+\date{\today}
+
+\begin{document}
+\frame{\titlepage}
+
+\include{definition}
+\include{statut}
+
+\end{document}
+
diff --git a/src/doc/epydoc.sh b/src/doc/epydoc.sh
new file mode 100755 (executable)
index 0000000..f83252f
--- /dev/null
@@ -0,0 +1,3 @@
+epydoc --css grayscale -o ./build/pydoc ../*.py #config.py ../option.py
+#apirst2html.py --stylesheet=docutils.css --external-api=epydoc --external-api-root=epydoc:./api/ --external-api-file=epydoc:./api/api-objects.txt  doc.txt > doc.htm
+
diff --git a/src/doc/gaspacho.txt b/src/doc/gaspacho.txt
new file mode 100644 (file)
index 0000000..457e3e9
--- /dev/null
@@ -0,0 +1,70 @@
+- abstract values from `gaspacho`
+  
+    Les types possibles :
+
+    - sans valeur : `boolean`
+    - avec valeur : `unicode` (un texte libre), `integer` (un chiffre), `enum` (une liste de choix prédéfinies) et `list` (une liste de choix libres).
+
+    Les types sans valeurs sont les plus simples. Par exemple cette règle n’attend
+    aucune valeur particulière Vérifier que Firefox est le navigateur par défaut.
+
+    Alors que celle-ci attend une adresse IP Configuration du serveur proxy manuelle.
+
+    Il existe un autre type (multi) qui permet de mêler plusieurs types.
+
+    Il s’agit bien de définir ici le type de la règle (et uniquement de la règle).
+
+- configuration levels in `creole`
+
+  *thu, 28 april 2011*
+
+    Exemple de niveau de configuration (dans l'ordre) :
+
+    1. - Coeur
+
+    2. 
+        - Coeur
+        - gen_config
+
+    3.
+        - Coeur
+        - gen_config
+        - EAD
+
+    4.
+        - Coeur
+        - EAD
+
+    5.
+        - Coeur
+        - baculaconfig.py
+
+    (`fill` : calcule une valeur jusqu'à ce que l'utilisateur change la
+    valeur)
+
+    Gestion des ACL en écriture :
+
+    Le coeur charge les variables
+
+    - si auto : seul le coeur peut la modifier (cas 1) ;
+    - si fill : le coeur calcule une valeur tant que pas configuré par
+      l'utilisateur. L'utilisateur peut modifier (cas 2 ou 3) ;
+    - des variables modifiables que par gen_config (cas 2) ;
+
+    - des variables modifiables par gen_config ou l'EAD (cas 3) ;
+
+    - des variables d'autres applications (cas 4 et 5).
+
+    Gestion des ACLs en lecture :
+
+    - seule une application peut lire certaines variables (exemple un mot de
+      passe).
+
+
+
+
+
+
+
diff --git a/src/doc/getting-started.txt b/src/doc/getting-started.txt
new file mode 100644 (file)
index 0000000..5e8a228
--- /dev/null
@@ -0,0 +1,67 @@
+==================================
+`Tiramisu` - Getting Started 
+==================================
+
+What is Configuration handling ?
+================================= 
+
+Due to more and more available configuration options required to set up 
+an operating system, it became quite annoying to hand the necessary 
+options to where they are actually used and even more annoying to add 
+new options. To circumvent these problems the configuration management 
+was introduced.
+
+What is Tiramisu ?
+=================== 
+
+Tiramisu is yet another configuration handler, wich aims at producing 
+flexible and fast configuration options access. The main advantages are 
+its access :ref:`glossary#rules` and the fact that the configuration 's 
+consistency is preserved at any time, see :ref:`glossary#consistency`.
+
+There are type and structures's validations for configuration options, 
+and validations towards the whole configuration.
+
+Last but not least, configuration options can be reached and changed 
+according to the access rules from nearly everywhere in the OS boxes, 
+e.g. the containers via the `http/json` server.
+
+Just the facts 
+============== 
+
+.. _gettingtiramisu: 
+
+Download
+---------
+
+To obtain a copy of the sources, check it out from the repository using 
+`git`. We suggest using `git` if one wants to access the current development.
+
+::
+
+    git clone git://git.labs.libre-entreprise.org/tiramisu.git
+
+This will get you a fresh checkout of the code repository in a local 
+directory named ``tiramisu``.
+
+Understanding Tiramisu's architecture
+--------------------------------------
+
+The :ref:`glossary#schema` is loaded from an XML file, and the values of 
+the configuration options are recovered from a `.ini` like file.
+
+By now, all the in-depth informations about the configuration are stored 
+in a **single** object, the :api:`config.Config()` object, wich is 
+responsible of nearly everything. All the necessary options are stored 
+into a configuration object, which is available nearly everywhere, so 
+that adding new options becomes trivial.
+
+This `Config()` is available from everywhere with the help of an http server
+that serves configuration datas as `json` strings. 
+
+.. figure:: architecture.png
+   
+   The basics of Tiramisu's architecture.
+   Once loaded, http server serves the :api:`config.Config()` object, that is,
+   the configuration options and the configuration groups. 
+
diff --git a/src/doc/glossary.txt b/src/doc/glossary.txt
new file mode 100644 (file)
index 0000000..e041090
--- /dev/null
@@ -0,0 +1,97 @@
+.. default-role:: literal
+
+glossary
+==========
+
+.. _configuration:
+
+**configuration**
+
+    Global configuration object, wich contains the whole configuration 
+    options *and* their descriptions (option types and group)
+
+.. _`option description`:
+.. _`schema`:
+
+**schema**:
+**option description**
+
+    see :api:`option.OptionDescription`, see :ref:`optionapi#schema`
+
+    The schema of a configuration : 
+    
+    - the option types
+
+    - how they are organised in groups or even subgroups, that's why we 
+      call them **groups** too.
+
+.. _`configoption`:
+
+**configuration option**
+
+    An option object wich has a name and a value and can be accessed 
+    from the configuration object
+
+.. _`defaultvalue`:
+
+**default value**
+
+    Default value of a configuration option. The default value can be 
+    set at instanciation time, or even at any moment. Remember that if 
+    you reset the default value, the owner reset to `default`
+
+.. _`rules`:
+
+**acces rules**
+    
+    Access rules are : :api:`config.Config.cfgimpl_read_write()` or 
+    :api:`config.Config.cfgimpl_read_only()`, see :doc:`status` 
+
+**freeze**
+
+    A whole configuration can be frozen (used in read only access). See 
+    :doc:`status` for details.
+
+.. _`valueowner`: 
+
+**value owner** 
+    
+    When an option is modified, including at the instanciation, we 
+    always know who has modified it. It's the owner of the option, see 
+    :doc:`status` for more details.
+
+**hidden option**
+
+    a hidden option has a different behaviour on regards to the access 
+    of the value in the configuration, see :doc:`status` for more details.
+
+**disabled option**
+
+    a disabled option has a different behaviour on regards to the access 
+    of the value in the configuration, see :doc:`status` for more details.
+
+**fill option**
+
+    a fill option is like an automatic option except that it is 
+    calculated only if a value hasn't been set.
+        
+**auto option**
+
+    an automatic option is an option thas is carried out by an external 
+    calculation
+
+.. _mandatory:
+
+**mandatory option**
+
+    A mandatory option is a configuration option wich value has to be 
+    set, that is the default value cannot be `None`, see 
+    :ref:`optionapi#optioninit`
+    
+    
+.. _consistency:
+
+**consistency**
+
+    Preserve the consistency in a whole configuration is a tricky thing,
+    tiramisu takes care of it for you, see :doc:`consistency` for details.
diff --git a/src/doc/index.txt b/src/doc/index.txt
new file mode 100644 (file)
index 0000000..dab64cb
--- /dev/null
@@ -0,0 +1,40 @@
+.. default-role:: literal
+
+.. meta::
+
+   :description: configuration management
+   :keywords: config, configuration
+   
+.. title:: tiramisu
+
+.. |version| replace:: 0.1
+
+The tasting of `Tiramisu`
+=========================
+
+.. image:: tiramisu.jpeg
+   :height: 150px
+   
+`Tiramisu`
+
+    is a cool, refreshing Italian dessert,
+
+    it is also a configuration management tool.
+
+
+It's a pretty small, local (that is, straight on the operating system) 
+configuration handler.
+
+- :doc:`getting-started`: where to go from here,
+- :doc:`config` explains the good praticies of configuration handling,
+- :doc:`configapi` and :doc:`optionapi` describe the API's details,
+- :doc:`status` for a summary of the `Option`'s and `Config`'s statuses,
+- :doc:`consistency` for the local and global integrity constraints,
+
+
+- :doc:`glossary` describes the specific terms used in Tiramisu.
+- :doc:`pydoc/index` for the developer's API
+
+
+
+
diff --git a/src/doc/optionapi.txt b/src/doc/optionapi.txt
new file mode 100644 (file)
index 0000000..c3c534a
--- /dev/null
@@ -0,0 +1,127 @@
+.. default-role:: literal
+
+Options API Details
+=====================
+
+:module: :api:`option.py`
+
+.. _schema:
+
+Description of Options
+----------------------
+
+All the constructors take a ``name`` and a ``doc`` argument as first 
+arguments to give the option or option group a name and to document it. 
+Most constructors take a ``default`` argument that specifies the default 
+value of the option. If this argument is not supplied the default value 
+is assumed to be ``None``. 
+
+Appart from that, the `Option` object is not supposed to contain any 
+other value than the `tainted` attribute, which is explained later. The 
+container of the value is in the `Config` object.
+
+``OptionDescription``
++++++++++++++++++++++
+
+This class is used to group suboptions.
+
+    ``__init__(self, name, doc, children)``
+        ``children`` is a list of option descriptions (including
+        ``OptionDescription`` instances for nested namespaces).
+
+    ``set_group_type(self, group_name)``
+        Three available group_types : `default`, `family`, `group` and 
+        `master` (for master~slave group type). Notice that for a 
+        master~slave group, the name of the group and the name of the 
+        master option are identical.
+
+`Options description` objects lives in the `_cfgimpl_descr` config attribute. 
+
+If you need to access an option object, you can do it with the OptionDescription
+object. Not only the value of the option by attribute access, but the option
+object itself that lives behind the scene. It can always be accessed internally
+with the `_cfgimpl_descr` attribute of the `config` objects. For example, with a
+option named `name` in a `gc` group the `name` object can be accessed like
+this::
+
+    conf._cfgimpl_descr.name
+    
+of sub configs with ::
+
+    conf.gc._cfgimpl_descr.name
+
+This is a binding. The option objects are in the `_children` config's attribute.
+
+Why accessing an option object ? It is possible for example freeze the
+configuration option 
+
+::
+
+    conf.gc._cfgimpl_descr.dummy.freeze()
+
+or to hide it, or disable it, or... anything.
+
+.. _optioninit:
+
+generic option ``__init__`` method:
+
+    ``__init__(name, doc, default=None, requires=None, multi=False, mandatory=False)``
+
+    :``default``: specifies the default value of the option. 
+    :``requires``: is a list of names of options located anywhere in the configuration.
+    :``multi``: means the value can be a list.
+    :``mandatory``: see :ref:`glossary#mandatory`.
+
+.. _optiontype:
+
+``BoolOption``
+++++++++++++++
+
+Represents a choice between ``True`` and ``False``. 
+
+``IntOption``
++++++++++++++
+
+Represents a choice of an integer.
+
+``FloatOption``
++++++++++++++++
+
+Represents a choice of a floating point number.
+
+``StrOption``
++++++++++++++
+
+Represents the choice of a string.
+
+``SymLinkOption``
+++++++++++++++++++
+
+Redirects to another configuration option in the configuration, that is :
+
+- retrieves the value of the tagert,
+- can set the value of the target too.
+
+    ``__init__(self, name, path)``
+    
+        `path` is the path to the target, the option 
+
+``IPOption``
++++++++++++++
+
+Represents the choice of an ip.
+
+``NetmaskOption``
++++++++++++++++++++
+
+Represents the choice of a netmask.
+
+``ChoiceOption``
+++++++++++++++++
+
+Represents a choice out of several objects. The option can also have the value
+``None``.
+
+    ``__init__(self, name, doc, values, default=None, requires=None)``
+        ``values`` is a list of values the option can possibly take.
+
diff --git a/src/doc/rst2html.py b/src/doc/rst2html.py
new file mode 100755 (executable)
index 0000000..3e356f3
--- /dev/null
@@ -0,0 +1,82 @@
+#!/usr/bin/python
+# unproudly borrowed from David Goodger's rst2html.py
+
+"""
+A minimal front end to the Docutils Publisher, producing HTML.
+"""
+
+try:
+    import locale
+    locale.setlocale(locale.LC_ALL, '')
+except:
+    pass
+
+from docutils.core import publish_cmdline, default_description
+# ____________________________________________________________
+from docutils import nodes, utils
+from docutils.parsers.rst import roles
+
+"""
+description of the new roles:
+
+`:api:` : link to the code
+
+- code.py becomes api/code.html
+- code.Code.code_test becomes api/code.Code.code_test.html
+- code.Code() becomes api/code.Code.html
+
+`:doc:`a link to an internal file
+example become example.html
+
+ref: link with anchor as in an external file 
+
+:ref:`toto#titi` becomes toto.html#titi 
+"""
+from os.path import splitext
+
+def api_reference_role(role, rawtext, text, lineno, inliner,
+                    options={}, content=[]):
+    basename = text
+    if "(" in text:
+        basename = text.split("(")[0]
+    if ".py" in text:
+        basename = splitext(text)[0]                
+    if "test_" in text:
+        refuri = "api/" + "tiramisu.test." + basename + '.html'
+    else:
+        refuri = "api/" + "tiramisu." + basename + '.html'
+    roles.set_classes(options)
+    node = nodes.reference(rawtext, utils.unescape(text), refuri=refuri,
+                        **options)
+    return [node], []
+
+roles.register_local_role('api', api_reference_role)
+
+def doc_reference_role(role, rawtext, text, lineno, inliner,
+                    options={}, content=[]):
+    refuri = text + '.html'
+    roles.set_classes(options)
+    node = nodes.reference(rawtext, utils.unescape(text), refuri=refuri,
+                        **options)
+    return [node], []
+
+roles.register_local_role('doc', doc_reference_role)
+
+def ref_reference_role(role, rawtext, text, lineno, inliner,
+                    options={}, content=[]):
+    fname, anchor = text.split('#')
+    refuri = fname + '.html#' + anchor 
+    roles.set_classes(options)
+    node = nodes.reference(rawtext, utils.unescape(anchor), refuri=refuri,
+                        **options)
+    return [node], []
+
+roles.register_local_role('ref', ref_reference_role)
+
+# ____________________________________________________________
+
+description = ('Generates (X)HTML documents from standalone reStructuredText '
+               'sources.  ' + default_description)
+
+publish_cmdline(writer_name='html', description=description)
+
diff --git a/src/doc/status.txt b/src/doc/status.txt
new file mode 100644 (file)
index 0000000..23de627
--- /dev/null
@@ -0,0 +1,181 @@
+.. default-role:: literal
+
+Configuration status
+======================
+
+:module: :api:`config.py`
+:tests: - :api:`test_option_owner.py`
+        - :api:`test_option_type.py` 
+        - :api:`test_option_default.py`
+
+Available configuration statuses 
+----------------------------------
+
+These configuration statuses corresponds to specific global attributes : 
+
+**read write status**
+
+    The configuration can be accessed by `__get__` and `__set__`
+    properties, except for the `hidden` configuration options but, yes, it is
+    possible to modify a disabled option.
+
+    To enable read-write status, call
+    :api:`config.Config.cfgimpl_read_write()`
+    
+**read only status**
+
+    The whole configuration is `frozen`, that is modifiying a value is 
+    forbidden. We can access to a configuration option only with the 
+    `__getattr__` property.
+    
+    The configuration has not an access to the hidden options
+    but can read the disabled options.  
+
+    To enable read only status, call :api:`config.Config.cfgimpl_read_only()`
+
+.. csv-table:: **Configuration's statuses summary**
+   :header: " ", "Hidden", "Disabled", "Mandatory"
+
+    "read only status", `False`, `True`, `True`
+    "read-write status", `True`, `False`, `False`
+
+Freezing a configuration
+---------------------------
+
+It is possible to *freeze* a single `Option` object with 
+:api:`option.Option.freeze()`. If you try to modify a frozen option, it 
+raises a `TypeError: trying to change a frozen option object`.
+
+At the configuration level, :api:`config.Config.cfgimpl_freeze()` freeze 
+the whole configuration options.
+
+- :api:`test_option_type.test_freeze_one_option()`
+- :api:`test_option_type.test_frozen_value()`
+- :api:`test_option_type.test_freeze()`
+
+
+Restricted access to an `Option()`
+-----------------------------------
+
+Configuration options access statuses are defined at configuration level 
+that corresponds to theses :api:`option.Option()`'s attribute: 
+
+**hidden**
+
+    This means that an option raises an `HiddenOptionError` if we try to access 
+    the value of the option. 
+
+    See `hide()` or `show()` in `Option()` that comes from 
+    :api:`option.HiddenBaseType`
+
+corresponding convenience API provided:
+
+    `hide()`:
+        set the `hidden` attribute to `True`
+
+    `show()`:
+        set the `hidden` attribute to `False`
+
+**disabled**
+
+    This means that an option *doesn't exists* (doesn't say anything 
+    much more thant an `AttibuteAccess` error)
+
+    See in :api:`option.DisabledBaseType` the origins of 
+    `Option.enable()` or `Option.disable()`
+
+corresponding convenience API provided:
+
+    `disable()`:
+        set the `disabled` attribute to `True`
+
+    `enable()`:
+        set the `disabled` attribute to `False`
+
+mode 
+
+    a mode is `normal` or `expert`, just a category of `Option()` or 
+    group wich determines if an option is easy to choose or not, 
+    available methods are:
+
+    `get_mode()`:
+        returns the current mode
+        
+    `set_mode(mode)`:
+        sets a new mode
+
+    see it in :api:`option.ModeBaseType`
+
+Value owners
+-------------
+
+Every configuration option has a **owner**. When the option is 
+instanciated, the owner is `default` because a default value has been 
+set (including `None`, take a look at the tests).
+
+The `value_owner` is the man who did it. Yes, the man who changed the value of the
+configuration option. 
+
+- At the instance of the `Config` object, the value owner is `default` because
+  the default values are set at the instance of the configuration option object,
+
+::
+    
+    # let's expect there is an option named 'name'
+    config = Config(descr, bool=False)
+    # the override method has been called
+    config._cfgimpl_value_owners['name'] == 'default'
+
+- at the modification of an option, the owner is `default_owner`, (which is `user`)
+
+::
+
+    # modification of the value by attribute access
+    config.gc.dummy = True
+    assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
+    assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'user'
+
+- the default owner can be set with the `set_owner()` method
+
+::
+
+    config.set_owner('spam')
+    config.set(dummy=True)
+    assert config.gc._cfgimpl_value_owners['dummy'] == 'spam'
+    assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'spam'
+
+Special owners
+---------------
+
+If the owner of a configuration option is `auto` or `fill` the behavior of the
+access of the value changes. In fact, there is nothing in the value. 
+The value comes from somewhere else (typically, it is calculated by the
+operation system). 
+
+**auto**
+
+    This means that it is a calculated value and therefore automatically 
+    protected it cannot be modified by attribute access once the owner 
+    is `auto`.
+    
+    The configuration option is hidden and a fonction in a specific
+    library is called for the computation of the value.
+
+**fill**
+
+    if the configuration option has a default value, the default is
+    returned, otherwise the value is calculated
+
+The default values behavior
+----------------------------
+
+Configuration options have default values that are stored in the 
+`Option()` object itself. Default values, the `default`, can be set in 
+various ways.
+
+.. FIXME : ADD DETAILS HERE
+
+If a default value is modified by overriding it, not only the value of 
+the option resets to the default that is proposed, but the owner is 
+modified too, it is reseted to `default`.
+
diff --git a/src/doc/todo.txt b/src/doc/todo.txt
new file mode 100644 (file)
index 0000000..7f89337
--- /dev/null
@@ -0,0 +1,126 @@
+:date: 20 janvier 2012
+
+créer une variable implicite cachée
+
+:: 
+
+    <variable name="toto"
+
+    exists='False' hidden='True'>
+    <value>non<value>
+
+si la variable n'existe pas, elle est crée avec une valeur par défaut
+
+cela permet une alternative aux dépendances (pour ne pas installer un 
+paquet inutilement)
+
+coder ça exactement comme les hidden ou les disabled, avec une levée 
+d'exception supplémentaire comme filtre.
+
+:date: 20 janvier 2012
+
+coder un cache pour les options dont le propriétaire est "auto" ou "fill"
+mettre ça dans un attribut `_cache` de l'option 
+
+mettre une contrainte de temps dans le cache
+
+- pouvoir forcer le recalcul de toutes les variables (vider le cache)
+  globalement dans toute la config
+
+- mettre une contrainte de temps donnée 
+  expires = timestamp + deltatime
+
+:date: 17 avril
+
+- lever une exception parlante (pour l'instant, c'est une "KeyError") 
+  lorsqu'on essaye d'affecter quelque chose
+  à un groupe, genre
+
+::
+
+    cfg = Config(descr)
+    cfg.gc = "uvw"
+
+alors que gc est un groupe
+
+:date: 12 avril
+
+- faire un mode dégradé avec des warnings
+- validations de longueur des maitres/esclaves ailleurs à sortir des requires
+  et à mettre dans des validators
+  
+:date: 3 avril 2012
+
+- hide sur les sous-sous groupe : il faut que ça hide **tout** les sous-groupe
+  récursivement
+  
+groupes `master/slaves`:
+
+    faut-il coder les multi avec des requires, ou bien simplement 
+    un groupe avec comme variable le nom du groupe ?
+
+auto, fill, obligatoire
+
+2012-03-22
+
+    **groupe master**
+        
+        faire une api du genre : `Option().is_master()`
+        pour cela, tester `if self.parent._name == self._name: return True`
+
+- mettre un attribut `auto` aux options de configuration, de manière à 
+  ce qu'elles sachent quelle fonction eos appeler (que ça soit une info 
+  dans l'option ou bien au niveau de la config ?)
+  le fait de détecter un "auto" vient du owner, mais il faut savoir 
+  quelle fonction appeler
+
+A documenter
+-------------
+
+- les variables multiples
+- expliquer les urls du json dans la doc
+- documenter le typage des options descriptions descr_type 
+
+A ajouter
+---------  
+
+Option -> attribut help (en plus de doc)
+          get_help() (à mettre en class Type avec Doc aussi)
+          
+separator -> pas pour l'instant
+
+fill, auto, obligatoire
+
+nouveau type : 
+
+type option (dérivé de ChoiceOPtion) dans lequel il y a des nouvelles valeurs
+possibles (pas de validations) ou plutôt une StringOption qui propose un choix
+de valeurs par défault de type liste.
+
+:date: 24 mars
+
+- hide pour les sous-sous config (récursivement) et pas seulement une 
+  seule sous-config (ou bien, quelque chose de réglable)
+
+- validate global : vérifier à l'init de la conf qu'une variable 
+  n'existe pas déjà, etc
+
+:date: 26 janvier
+
+- un attribut eosfunc pour auto + les paramètres à donner à la fonction
+  pareil pour le fill (function et paramètres)
+
+reset
+-------
+
+**à discuter** : ça correspond exactement au override, 
+ou bien au opt.setoption(None, 'default')
+
+**si la valeur par défaut est définie, un __get__ ne pourra jamais 
+renvoyer None.** ce qui est bloquant. Il faut pouvoir revenir à None.
+
+pour supprimer la valeur d'une options (et revenir à la valeur par défault)
+cfg.reset() (supprime _cfgimpl_value[name]) et _cfgimpl_value_owner[name])
+
+reset() 
+
diff --git a/src/error.py b/src/error.py
new file mode 100644 (file)
index 0000000..4588f71
--- /dev/null
@@ -0,0 +1,25 @@
+class AmbigousOptionError(Exception):
+    pass
+class NoMatchingOptionFound(AttributeError):
+    pass
+class ConfigError(Exception):
+    pass
+class ConflictConfigError(ConfigError):
+    pass
+class HiddenOptionError(AttributeError):
+    pass
+class DisabledOptionError(AttributeError):
+    pass 
+class NotFoundError(Exception):
+    pass
+class MethodCallError(Exception):
+    pass 
+class RequiresError(Exception):
+    pass    
+class MandatoryError(Exception):
+    pass 
+class SpecialOwnersError(Exception):
+    pass 
+class ModeOptionError(Exception):
+    pass
+    
diff --git a/src/gpl-3.0.txt b/src/gpl-3.0.txt
new file mode 100644 (file)
index 0000000..818433e
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE\r
+                       Version 3, 29 June 2007\r
+\r
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\r
+ Everyone is permitted to copy and distribute verbatim copies\r
+ of this license document, but changing it is not allowed.\r
+\r
+                            Preamble\r
+\r
+  The GNU General Public License is a free, copyleft license for\r
+software and other kinds of works.\r
+\r
+  The licenses for most software and other practical works are designed\r
+to take away your freedom to share and change the works.  By contrast,\r
+the GNU General Public License is intended to guarantee your freedom to\r
+share and change all versions of a program--to make sure it remains free\r
+software for all its users.  We, the Free Software Foundation, use the\r
+GNU General Public License for most of our software; it applies also to\r
+any other work released this way by its authors.  You can apply it to\r
+your programs, too.\r
+\r
+  When we speak of free software, we are referring to freedom, not\r
+price.  Our General Public Licenses are designed to make sure that you\r
+have the freedom to distribute copies of free software (and charge for\r
+them if you wish), that you receive source code or can get it if you\r
+want it, that you can change the software or use pieces of it in new\r
+free programs, and that you know you can do these things.\r
+\r
+  To protect your rights, we need to prevent others from denying you\r
+these rights or asking you to surrender the rights.  Therefore, you have\r
+certain responsibilities if you distribute copies of the software, or if\r
+you modify it: responsibilities to respect the freedom of others.\r
+\r
+  For example, if you distribute copies of such a program, whether\r
+gratis or for a fee, you must pass on to the recipients the same\r
+freedoms that you received.  You must make sure that they, too, receive\r
+or can get the source code.  And you must show them these terms so they\r
+know their rights.\r
+\r
+  Developers that use the GNU GPL protect your rights with two steps:\r
+(1) assert copyright on the software, and (2) offer you this License\r
+giving you legal permission to copy, distribute and/or modify it.\r
+\r
+  For the developers' and authors' protection, the GPL clearly explains\r
+that there is no warranty for this free software.  For both users' and\r
+authors' sake, the GPL requires that modified versions be marked as\r
+changed, so that their problems will not be attributed erroneously to\r
+authors of previous versions.\r
+\r
+  Some devices are designed to deny users access to install or run\r
+modified versions of the software inside them, although the manufacturer\r
+can do so.  This is fundamentally incompatible with the aim of\r
+protecting users' freedom to change the software.  The systematic\r
+pattern of such abuse occurs in the area of products for individuals to\r
+use, which is precisely where it is most unacceptable.  Therefore, we\r
+have designed this version of the GPL to prohibit the practice for those\r
+products.  If such problems arise substantially in other domains, we\r
+stand ready to extend this provision to those domains in future versions\r
+of the GPL, as needed to protect the freedom of users.\r
+\r
+  Finally, every program is threatened constantly by software patents.\r
+States should not allow patents to restrict development and use of\r
+software on general-purpose computers, but in those that do, we wish to\r
+avoid the special danger that patents applied to a free program could\r
+make it effectively proprietary.  To prevent this, the GPL assures that\r
+patents cannot be used to render the program non-free.\r
+\r
+  The precise terms and conditions for copying, distribution and\r
+modification follow.\r
+\r
+                       TERMS AND CONDITIONS\r
+\r
+  0. Definitions.\r
+\r
+  "This License" refers to version 3 of the GNU General Public License.\r
+\r
+  "Copyright" also means copyright-like laws that apply to other kinds of\r
+works, such as semiconductor masks.\r
+\r
+  "The Program" refers to any copyrightable work licensed under this\r
+License.  Each licensee is addressed as "you".  "Licensees" and\r
+"recipients" may be individuals or organizations.\r
+\r
+  To "modify" a work means to copy from or adapt all or part of the work\r
+in a fashion requiring copyright permission, other than the making of an\r
+exact copy.  The resulting work is called a "modified version" of the\r
+earlier work or a work "based on" the earlier work.\r
+\r
+  A "covered work" means either the unmodified Program or a work based\r
+on the Program.\r
+\r
+  To "propagate" a work means to do anything with it that, without\r
+permission, would make you directly or secondarily liable for\r
+infringement under applicable copyright law, except executing it on a\r
+computer or modifying a private copy.  Propagation includes copying,\r
+distribution (with or without modification), making available to the\r
+public, and in some countries other activities as well.\r
+\r
+  To "convey" a work means any kind of propagation that enables other\r
+parties to make or receive copies.  Mere interaction with a user through\r
+a computer network, with no transfer of a copy, is not conveying.\r
+\r
+  An interactive user interface displays "Appropriate Legal Notices"\r
+to the extent that it includes a convenient and prominently visible\r
+feature that (1) displays an appropriate copyright notice, and (2)\r
+tells the user that there is no warranty for the work (except to the\r
+extent that warranties are provided), that licensees may convey the\r
+work under this License, and how to view a copy of this License.  If\r
+the interface presents a list of user commands or options, such as a\r
+menu, a prominent item in the list meets this criterion.\r
+\r
+  1. Source Code.\r
+\r
+  The "source code" for a work means the preferred form of the work\r
+for making modifications to it.  "Object code" means any non-source\r
+form of a work.\r
+\r
+  A "Standard Interface" means an interface that either is an official\r
+standard defined by a recognized standards body, or, in the case of\r
+interfaces specified for a particular programming language, one that\r
+is widely used among developers working in that language.\r
+\r
+  The "System Libraries" of an executable work include anything, other\r
+than the work as a whole, that (a) is included in the normal form of\r
+packaging a Major Component, but which is not part of that Major\r
+Component, and (b) serves only to enable use of the work with that\r
+Major Component, or to implement a Standard Interface for which an\r
+implementation is available to the public in source code form.  A\r
+"Major Component", in this context, means a major essential component\r
+(kernel, window system, and so on) of the specific operating system\r
+(if any) on which the executable work runs, or a compiler used to\r
+produce the work, or an object code interpreter used to run it.\r
+\r
+  The "Corresponding Source" for a work in object code form means all\r
+the source code needed to generate, install, and (for an executable\r
+work) run the object code and to modify the work, including scripts to\r
+control those activities.  However, it does not include the work's\r
+System Libraries, or general-purpose tools or generally available free\r
+programs which are used unmodified in performing those activities but\r
+which are not part of the work.  For example, Corresponding Source\r
+includes interface definition files associated with source files for\r
+the work, and the source code for shared libraries and dynamically\r
+linked subprograms that the work is specifically designed to require,\r
+such as by intimate data communication or control flow between those\r
+subprograms and other parts of the work.\r
+\r
+  The Corresponding Source need not include anything that users\r
+can regenerate automatically from other parts of the Corresponding\r
+Source.\r
+\r
+  The Corresponding Source for a work in source code form is that\r
+same work.\r
+\r
+  2. Basic Permissions.\r
+\r
+  All rights granted under this License are granted for the term of\r
+copyright on the Program, and are irrevocable provided the stated\r
+conditions are met.  This License explicitly affirms your unlimited\r
+permission to run the unmodified Program.  The output from running a\r
+covered work is covered by this License only if the output, given its\r
+content, constitutes a covered work.  This License acknowledges your\r
+rights of fair use or other equivalent, as provided by copyright law.\r
+\r
+  You may make, run and propagate covered works that you do not\r
+convey, without conditions so long as your license otherwise remains\r
+in force.  You may convey covered works to others for the sole purpose\r
+of having them make modifications exclusively for you, or provide you\r
+with facilities for running those works, provided that you comply with\r
+the terms of this License in conveying all material for which you do\r
+not control copyright.  Those thus making or running the covered works\r
+for you must do so exclusively on your behalf, under your direction\r
+and control, on terms that prohibit them from making any copies of\r
+your copyrighted material outside their relationship with you.\r
+\r
+  Conveying under any other circumstances is permitted solely under\r
+the conditions stated below.  Sublicensing is not allowed; section 10\r
+makes it unnecessary.\r
+\r
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\r
+\r
+  No covered work shall be deemed part of an effective technological\r
+measure under any applicable law fulfilling obligations under article\r
+11 of the WIPO copyright treaty adopted on 20 December 1996, or\r
+similar laws prohibiting or restricting circumvention of such\r
+measures.\r
+\r
+  When you convey a covered work, you waive any legal power to forbid\r
+circumvention of technological measures to the extent such circumvention\r
+is effected by exercising rights under this License with respect to\r
+the covered work, and you disclaim any intention to limit operation or\r
+modification of the work as a means of enforcing, against the work's\r
+users, your or third parties' legal rights to forbid circumvention of\r
+technological measures.\r
+\r
+  4. Conveying Verbatim Copies.\r
+\r
+  You may convey verbatim copies of the Program's source code as you\r
+receive it, in any medium, provided that you conspicuously and\r
+appropriately publish on each copy an appropriate copyright notice;\r
+keep intact all notices stating that this License and any\r
+non-permissive terms added in accord with section 7 apply to the code;\r
+keep intact all notices of the absence of any warranty; and give all\r
+recipients a copy of this License along with the Program.\r
+\r
+  You may charge any price or no price for each copy that you convey,\r
+and you may offer support or warranty protection for a fee.\r
+\r
+  5. Conveying Modified Source Versions.\r
+\r
+  You may convey a work based on the Program, or the modifications to\r
+produce it from the Program, in the form of source code under the\r
+terms of section 4, provided that you also meet all of these conditions:\r
+\r
+    a) The work must carry prominent notices stating that you modified\r
+    it, and giving a relevant date.\r
+\r
+    b) The work must carry prominent notices stating that it is\r
+    released under this License and any conditions added under section\r
+    7.  This requirement modifies the requirement in section 4 to\r
+    "keep intact all notices".\r
+\r
+    c) You must license the entire work, as a whole, under this\r
+    License to anyone who comes into possession of a copy.  This\r
+    License will therefore apply, along with any applicable section 7\r
+    additional terms, to the whole of the work, and all its parts,\r
+    regardless of how they are packaged.  This License gives no\r
+    permission to license the work in any other way, but it does not\r
+    invalidate such permission if you have separately received it.\r
+\r
+    d) If the work has interactive user interfaces, each must display\r
+    Appropriate Legal Notices; however, if the Program has interactive\r
+    interfaces that do not display Appropriate Legal Notices, your\r
+    work need not make them do so.\r
+\r
+  A compilation of a covered work with other separate and independent\r
+works, which are not by their nature extensions of the covered work,\r
+and which are not combined with it such as to form a larger program,\r
+in or on a volume of a storage or distribution medium, is called an\r
+"aggregate" if the compilation and its resulting copyright are not\r
+used to limit the access or legal rights of the compilation's users\r
+beyond what the individual works permit.  Inclusion of a covered work\r
+in an aggregate does not cause this License to apply to the other\r
+parts of the aggregate.\r
+\r
+  6. Conveying Non-Source Forms.\r
+\r
+  You may convey a covered work in object code form under the terms\r
+of sections 4 and 5, provided that you also convey the\r
+machine-readable Corresponding Source under the terms of this License,\r
+in one of these ways:\r
+\r
+    a) Convey the object code in, or embodied in, a physical product\r
+    (including a physical distribution medium), accompanied by the\r
+    Corresponding Source fixed on a durable physical medium\r
+    customarily used for software interchange.\r
+\r
+    b) Convey the object code in, or embodied in, a physical product\r
+    (including a physical distribution medium), accompanied by a\r
+    written offer, valid for at least three years and valid for as\r
+    long as you offer spare parts or customer support for that product\r
+    model, to give anyone who possesses the object code either (1) a\r
+    copy of the Corresponding Source for all the software in the\r
+    product that is covered by this License, on a durable physical\r
+    medium customarily used for software interchange, for a price no\r
+    more than your reasonable cost of physically performing this\r
+    conveying of source, or (2) access to copy the\r
+    Corresponding Source from a network server at no charge.\r
+\r
+    c) Convey individual copies of the object code with a copy of the\r
+    written offer to provide the Corresponding Source.  This\r
+    alternative is allowed only occasionally and noncommercially, and\r
+    only if you received the object code with such an offer, in accord\r
+    with subsection 6b.\r
+\r
+    d) Convey the object code by offering access from a designated\r
+    place (gratis or for a charge), and offer equivalent access to the\r
+    Corresponding Source in the same way through the same place at no\r
+    further charge.  You need not require recipients to copy the\r
+    Corresponding Source along with the object code.  If the place to\r
+    copy the object code is a network server, the Corresponding Source\r
+    may be on a different server (operated by you or a third party)\r
+    that supports equivalent copying facilities, provided you maintain\r
+    clear directions next to the object code saying where to find the\r
+    Corresponding Source.  Regardless of what server hosts the\r
+    Corresponding Source, you remain obligated to ensure that it is\r
+    available for as long as needed to satisfy these requirements.\r
+\r
+    e) Convey the object code using peer-to-peer transmission, provided\r
+    you inform other peers where the object code and Corresponding\r
+    Source of the work are being offered to the general public at no\r
+    charge under subsection 6d.\r
+\r
+  A separable portion of the object code, whose source code is excluded\r
+from the Corresponding Source as a System Library, need not be\r
+included in conveying the object code work.\r
+\r
+  A "User Product" is either (1) a "consumer product", which means any\r
+tangible personal property which is normally used for personal, family,\r
+or household purposes, or (2) anything designed or sold for incorporation\r
+into a dwelling.  In determining whether a product is a consumer product,\r
+doubtful cases shall be resolved in favor of coverage.  For a particular\r
+product received by a particular user, "normally used" refers to a\r
+typical or common use of that class of product, regardless of the status\r
+of the particular user or of the way in which the particular user\r
+actually uses, or expects or is expected to use, the product.  A product\r
+is a consumer product regardless of whether the product has substantial\r
+commercial, industrial or non-consumer uses, unless such uses represent\r
+the only significant mode of use of the product.\r
+\r
+  "Installation Information" for a User Product means any methods,\r
+procedures, authorization keys, or other information required to install\r
+and execute modified versions of a covered work in that User Product from\r
+a modified version of its Corresponding Source.  The information must\r
+suffice to ensure that the continued functioning of the modified object\r
+code is in no case prevented or interfered with solely because\r
+modification has been made.\r
+\r
+  If you convey an object code work under this section in, or with, or\r
+specifically for use in, a User Product, and the conveying occurs as\r
+part of a transaction in which the right of possession and use of the\r
+User Product is transferred to the recipient in perpetuity or for a\r
+fixed term (regardless of how the transaction is characterized), the\r
+Corresponding Source conveyed under this section must be accompanied\r
+by the Installation Information.  But this requirement does not apply\r
+if neither you nor any third party retains the ability to install\r
+modified object code on the User Product (for example, the work has\r
+been installed in ROM).\r
+\r
+  The requirement to provide Installation Information does not include a\r
+requirement to continue to provide support service, warranty, or updates\r
+for a work that has been modified or installed by the recipient, or for\r
+the User Product in which it has been modified or installed.  Access to a\r
+network may be denied when the modification itself materially and\r
+adversely affects the operation of the network or violates the rules and\r
+protocols for communication across the network.\r
+\r
+  Corresponding Source conveyed, and Installation Information provided,\r
+in accord with this section must be in a format that is publicly\r
+documented (and with an implementation available to the public in\r
+source code form), and must require no special password or key for\r
+unpacking, reading or copying.\r
+\r
+  7. Additional Terms.\r
+\r
+  "Additional permissions" are terms that supplement the terms of this\r
+License by making exceptions from one or more of its conditions.\r
+Additional permissions that are applicable to the entire Program shall\r
+be treated as though they were included in this License, to the extent\r
+that they are valid under applicable law.  If additional permissions\r
+apply only to part of the Program, that part may be used separately\r
+under those permissions, but the entire Program remains governed by\r
+this License without regard to the additional permissions.\r
+\r
+  When you convey a copy of a covered work, you may at your option\r
+remove any additional permissions from that copy, or from any part of\r
+it.  (Additional permissions may be written to require their own\r
+removal in certain cases when you modify the work.)  You may place\r
+additional permissions on material, added by you to a covered work,\r
+for which you have or can give appropriate copyright permission.\r
+\r
+  Notwithstanding any other provision of this License, for material you\r
+add to a covered work, you may (if authorized by the copyright holders of\r
+that material) supplement the terms of this License with terms:\r
+\r
+    a) Disclaiming warranty or limiting liability differently from the\r
+    terms of sections 15 and 16 of this License; or\r
+\r
+    b) Requiring preservation of specified reasonable legal notices or\r
+    author attributions in that material or in the Appropriate Legal\r
+    Notices displayed by works containing it; or\r
+\r
+    c) Prohibiting misrepresentation of the origin of that material, or\r
+    requiring that modified versions of such material be marked in\r
+    reasonable ways as different from the original version; or\r
+\r
+    d) Limiting the use for publicity purposes of names of licensors or\r
+    authors of the material; or\r
+\r
+    e) Declining to grant rights under trademark law for use of some\r
+    trade names, trademarks, or service marks; or\r
+\r
+    f) Requiring indemnification of licensors and authors of that\r
+    material by anyone who conveys the material (or modified versions of\r
+    it) with contractual assumptions of liability to the recipient, for\r
+    any liability that these contractual assumptions directly impose on\r
+    those licensors and authors.\r
+\r
+  All other non-permissive additional terms are considered "further\r
+restrictions" within the meaning of section 10.  If the Program as you\r
+received it, or any part of it, contains a notice stating that it is\r
+governed by this License along with a term that is a further\r
+restriction, you may remove that term.  If a license document contains\r
+a further restriction but permits relicensing or conveying under this\r
+License, you may add to a covered work material governed by the terms\r
+of that license document, provided that the further restriction does\r
+not survive such relicensing or conveying.\r
+\r
+  If you add terms to a covered work in accord with this section, you\r
+must place, in the relevant source files, a statement of the\r
+additional terms that apply to those files, or a notice indicating\r
+where to find the applicable terms.\r
+\r
+  Additional terms, permissive or non-permissive, may be stated in the\r
+form of a separately written license, or stated as exceptions;\r
+the above requirements apply either way.\r
+\r
+  8. Termination.\r
+\r
+  You may not propagate or modify a covered work except as expressly\r
+provided under this License.  Any attempt otherwise to propagate or\r
+modify it is void, and will automatically terminate your rights under\r
+this License (including any patent licenses granted under the third\r
+paragraph of section 11).\r
+\r
+  However, if you cease all violation of this License, then your\r
+license from a particular copyright holder is reinstated (a)\r
+provisionally, unless and until the copyright holder explicitly and\r
+finally terminates your license, and (b) permanently, if the copyright\r
+holder fails to notify you of the violation by some reasonable means\r
+prior to 60 days after the cessation.\r
+\r
+  Moreover, your license from a particular copyright holder is\r
+reinstated permanently if the copyright holder notifies you of the\r
+violation by some reasonable means, this is the first time you have\r
+received notice of violation of this License (for any work) from that\r
+copyright holder, and you cure the violation prior to 30 days after\r
+your receipt of the notice.\r
+\r
+  Termination of your rights under this section does not terminate the\r
+licenses of parties who have received copies or rights from you under\r
+this License.  If your rights have been terminated and not permanently\r
+reinstated, you do not qualify to receive new licenses for the same\r
+material under section 10.\r
+\r
+  9. Acceptance Not Required for Having Copies.\r
+\r
+  You are not required to accept this License in order to receive or\r
+run a copy of the Program.  Ancillary propagation of a covered work\r
+occurring solely as a consequence of using peer-to-peer transmission\r
+to receive a copy likewise does not require acceptance.  However,\r
+nothing other than this License grants you permission to propagate or\r
+modify any covered work.  These actions infringe copyright if you do\r
+not accept this License.  Therefore, by modifying or propagating a\r
+covered work, you indicate your acceptance of this License to do so.\r
+\r
+  10. Automatic Licensing of Downstream Recipients.\r
+\r
+  Each time you convey a covered work, the recipient automatically\r
+receives a license from the original licensors, to run, modify and\r
+propagate that work, subject to this License.  You are not responsible\r
+for enforcing compliance by third parties with this License.\r
+\r
+  An "entity transaction" is a transaction transferring control of an\r
+organization, or substantially all assets of one, or subdividing an\r
+organization, or merging organizations.  If propagation of a covered\r
+work results from an entity transaction, each party to that\r
+transaction who receives a copy of the work also receives whatever\r
+licenses to the work the party's predecessor in interest had or could\r
+give under the previous paragraph, plus a right to possession of the\r
+Corresponding Source of the work from the predecessor in interest, if\r
+the predecessor has it or can get it with reasonable efforts.\r
+\r
+  You may not impose any further restrictions on the exercise of the\r
+rights granted or affirmed under this License.  For example, you may\r
+not impose a license fee, royalty, or other charge for exercise of\r
+rights granted under this License, and you may not initiate litigation\r
+(including a cross-claim or counterclaim in a lawsuit) alleging that\r
+any patent claim is infringed by making, using, selling, offering for\r
+sale, or importing the Program or any portion of it.\r
+\r
+  11. Patents.\r
+\r
+  A "contributor" is a copyright holder who authorizes use under this\r
+License of the Program or a work on which the Program is based.  The\r
+work thus licensed is called the contributor's "contributor version".\r
+\r
+  A contributor's "essential patent claims" are all patent claims\r
+owned or controlled by the contributor, whether already acquired or\r
+hereafter acquired, that would be infringed by some manner, permitted\r
+by this License, of making, using, or selling its contributor version,\r
+but do not include claims that would be infringed only as a\r
+consequence of further modification of the contributor version.  For\r
+purposes of this definition, "control" includes the right to grant\r
+patent sublicenses in a manner consistent with the requirements of\r
+this License.\r
+\r
+  Each contributor grants you a non-exclusive, worldwide, royalty-free\r
+patent license under the contributor's essential patent claims, to\r
+make, use, sell, offer for sale, import and otherwise run, modify and\r
+propagate the contents of its contributor version.\r
+\r
+  In the following three paragraphs, a "patent license" is any express\r
+agreement or commitment, however denominated, not to enforce a patent\r
+(such as an express permission to practice a patent or covenant not to\r
+sue for patent infringement).  To "grant" such a patent license to a\r
+party means to make such an agreement or commitment not to enforce a\r
+patent against the party.\r
+\r
+  If you convey a covered work, knowingly relying on a patent license,\r
+and the Corresponding Source of the work is not available for anyone\r
+to copy, free of charge and under the terms of this License, through a\r
+publicly available network server or other readily accessible means,\r
+then you must either (1) cause the Corresponding Source to be so\r
+available, or (2) arrange to deprive yourself of the benefit of the\r
+patent license for this particular work, or (3) arrange, in a manner\r
+consistent with the requirements of this License, to extend the patent\r
+license to downstream recipients.  "Knowingly relying" means you have\r
+actual knowledge that, but for the patent license, your conveying the\r
+covered work in a country, or your recipient's use of the covered work\r
+in a country, would infringe one or more identifiable patents in that\r
+country that you have reason to believe are valid.\r
+\r
+  If, pursuant to or in connection with a single transaction or\r
+arrangement, you convey, or propagate by procuring conveyance of, a\r
+covered work, and grant a patent license to some of the parties\r
+receiving the covered work authorizing them to use, propagate, modify\r
+or convey a specific copy of the covered work, then the patent license\r
+you grant is automatically extended to all recipients of the covered\r
+work and works based on it.\r
+\r
+  A patent license is "discriminatory" if it does not include within\r
+the scope of its coverage, prohibits the exercise of, or is\r
+conditioned on the non-exercise of one or more of the rights that are\r
+specifically granted under this License.  You may not convey a covered\r
+work if you are a party to an arrangement with a third party that is\r
+in the business of distributing software, under which you make payment\r
+to the third party based on the extent of your activity of conveying\r
+the work, and under which the third party grants, to any of the\r
+parties who would receive the covered work from you, a discriminatory\r
+patent license (a) in connection with copies of the covered work\r
+conveyed by you (or copies made from those copies), or (b) primarily\r
+for and in connection with specific products or compilations that\r
+contain the covered work, unless you entered into that arrangement,\r
+or that patent license was granted, prior to 28 March 2007.\r
+\r
+  Nothing in this License shall be construed as excluding or limiting\r
+any implied license or other defenses to infringement that may\r
+otherwise be available to you under applicable patent law.\r
+\r
+  12. No Surrender of Others' Freedom.\r
+\r
+  If conditions are imposed on you (whether by court order, agreement or\r
+otherwise) that contradict the conditions of this License, they do not\r
+excuse you from the conditions of this License.  If you cannot convey a\r
+covered work so as to satisfy simultaneously your obligations under this\r
+License and any other pertinent obligations, then as a consequence you may\r
+not convey it at all.  For example, if you agree to terms that obligate you\r
+to collect a royalty for further conveying from those to whom you convey\r
+the Program, the only way you could satisfy both those terms and this\r
+License would be to refrain entirely from conveying the Program.\r
+\r
+  13. Use with the GNU Affero General Public License.\r
+\r
+  Notwithstanding any other provision of this License, you have\r
+permission to link or combine any covered work with a work licensed\r
+under version 3 of the GNU Affero General Public License into a single\r
+combined work, and to convey the resulting work.  The terms of this\r
+License will continue to apply to the part which is the covered work,\r
+but the special requirements of the GNU Affero General Public License,\r
+section 13, concerning interaction through a network will apply to the\r
+combination as such.\r
+\r
+  14. Revised Versions of this License.\r
+\r
+  The Free Software Foundation may publish revised and/or new versions of\r
+the GNU General Public License from time to time.  Such new versions will\r
+be similar in spirit to the present version, but may differ in detail to\r
+address new problems or concerns.\r
+\r
+  Each version is given a distinguishing version number.  If the\r
+Program specifies that a certain numbered version of the GNU General\r
+Public License "or any later version" applies to it, you have the\r
+option of following the terms and conditions either of that numbered\r
+version or of any later version published by the Free Software\r
+Foundation.  If the Program does not specify a version number of the\r
+GNU General Public License, you may choose any version ever published\r
+by the Free Software Foundation.\r
+\r
+  If the Program specifies that a proxy can decide which future\r
+versions of the GNU General Public License can be used, that proxy's\r
+public statement of acceptance of a version permanently authorizes you\r
+to choose that version for the Program.\r
+\r
+  Later license versions may give you additional or different\r
+permissions.  However, no additional obligations are imposed on any\r
+author or copyright holder as a result of your choosing to follow a\r
+later version.\r
+\r
+  15. Disclaimer of Warranty.\r
+\r
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\r
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\r
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY\r
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\r
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\r
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\r
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\r
+\r
+  16. Limitation of Liability.\r
+\r
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\r
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\r
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\r
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\r
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\r
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\r
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\r
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\r
+SUCH DAMAGES.\r
+\r
+  17. Interpretation of Sections 15 and 16.\r
+\r
+  If the disclaimer of warranty and limitation of liability provided\r
+above cannot be given local legal effect according to their terms,\r
+reviewing courts shall apply local law that most closely approximates\r
+an absolute waiver of all civil liability in connection with the\r
+Program, unless a warranty or assumption of liability accompanies a\r
+copy of the Program in return for a fee.\r
+\r
+                     END OF TERMS AND CONDITIONS\r
+\r
+            How to Apply These Terms to Your New Programs\r
+\r
+  If you develop a new program, and you want it to be of the greatest\r
+possible use to the public, the best way to achieve this is to make it\r
+free software which everyone can redistribute and change under these terms.\r
+\r
+  To do so, attach the following notices to the program.  It is safest\r
+to attach them to the start of each source file to most effectively\r
+state the exclusion of warranty; and each file should have at least\r
+the "copyright" line and a pointer to where the full notice is found.\r
+\r
+    <one line to give the program's name and a brief idea of what it does.>\r
+    Copyright (C) <year>  <name of author>\r
+\r
+    This program is free software: you can redistribute it and/or modify\r
+    it under the terms of the GNU General Public License as published by\r
+    the Free Software Foundation, either version 3 of the License, or\r
+    (at your option) any later version.\r
+\r
+    This program is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+    GNU General Public License for more details.\r
+\r
+    You should have received a copy of the GNU General Public License\r
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
+\r
+Also add information on how to contact you by electronic and paper mail.\r
+\r
+  If the program does terminal interaction, make it output a short\r
+notice like this when it starts in an interactive mode:\r
+\r
+    <program>  Copyright (C) <year>  <name of author>\r
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\r
+    This is free software, and you are welcome to redistribute it\r
+    under certain conditions; type `show c' for details.\r
+\r
+The hypothetical commands `show w' and `show c' should show the appropriate\r
+parts of the General Public License.  Of course, your program's commands\r
+might be different; for a GUI interface, you would use an "about box".\r
+\r
+  You should also get your employer (if you work as a programmer) or school,\r
+if any, to sign a "copyright disclaimer" for the program, if necessary.\r
+For more information on this, and how to apply and follow the GNU GPL, see\r
+<http://www.gnu.org/licenses/>.\r
+\r
+  The GNU General Public License does not permit incorporating your program\r
+into proprietary programs.  If your program is a subroutine library, you\r
+may consider it more useful to permit linking proprietary applications with\r
+the library.  If this is what you want to do, use the GNU Lesser General\r
+Public License instead of this License.  But first, please read\r
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.\r
diff --git a/src/option.py b/src/option.py
new file mode 100644 (file)
index 0000000..9339e12
--- /dev/null
@@ -0,0 +1,504 @@
+# -*- coding: utf-8 -*-
+"option types and option description for the configuration management"
+# Copyright (C) 2012 Team tiramisu (see README for all contributors)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# The original `Config` design model is unproudly borrowed from 
+# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
+# the whole pypy projet is under MIT licence
+# ____________________________________________________________
+from autolib import special_owners
+from basetype import HiddenBaseType, DisabledBaseType, ModeBaseType, modes
+from error import (ConfigError, ConflictConfigError, NotFoundError, 
+                   SpecialOwnersError, RequiresError)
+available_actions = ['hide', 'show', 'enable', 'disable'] 
+reverse_actions = {'hide': 'show', 'show': 'hide', 
+                   'disable':'enable', 'enable': 'disable'}
+# ____________________________________________________________
+# OptionDescription authorized group_type values
+group_types = ['default', 'family', 'group', 'master']
+# multi types 
+class Multi(list):
+    "container that support items for the values of list (multi) options" 
+    def __init__(self, lst, config=None, child=None):
+        self.config = config
+        self.child = child
+        super(Multi, self).__init__(lst)
+        
+    def __getitem__(self, key):
+        value =  super(Multi, self).__getitem__(key)
+        if value is None:
+            return self.child.default_multi
+            
+    def __setitem__(self, key, value):
+        if value is None:
+            owner = 'default'
+        else:
+            owner = self.config._cfgimpl_owner 
+        oldowner = self.child.getowner(self.config)
+        oldowner[key] = owner        
+        self.child.setowner(self.config, oldowner)
+        if value != None and not self.child._validate(value):
+            raise ConfigError("invalid value {0} "
+                "for option {1}".format(str(value), self.child._name))
+        return super(Multi, self).__setitem__(key, value)
+
+    def append(self, value):
+        if value is None:
+            owner = 'default'
+        else:
+            owner = self.config._cfgimpl_owner 
+        oldowner = self.child.getowner(self.config)
+        oldowner.append(owner)
+        self.child.setowner(self.config, oldowner)
+        # changer dans la config la valeur par défaut et le owner
+        if value != None and not self.child._validate(value):
+            raise ConfigError("invalid value {0} "
+                "for option {1}".format(str(value), self.child._name))
+        super(Multi, self).append(value)
+    
+#    def pop(self):
+#        pass 
+# ____________________________________________________________
+#
+class Option(HiddenBaseType, DisabledBaseType, ModeBaseType):
+    #reminder: an Option object is **not** a container for the value
+    _frozen = False
+    def __init__(self, name, doc, default=None, default_multi=None, 
+                 requires=None, mandatory=False, multi=False, callback=None, 
+                 callback_params=None, mode='normal'):
+        self._name = name
+        self.doc = doc
+        self._requires = requires
+        self._mandatory = mandatory
+        self.multi = multi
+        if not self.multi and default_multi is not None:
+            raise ConfigError("a default_multi is set whereas multi is False"
+                  " in option: {0}".format(name)) 
+        if default_multi is not None and not self._validate(default_multi):
+            raise ConfigError("invalid default_multi value {0} "
+                "for option {1}".format(str(default_multi), name))
+        self.default_multi = default_multi
+        #if self.multi and default_multi is None:
+            # _cfgimpl_warnings[name] = DefaultMultiWarning   
+        if callback is not None and (default is not None or default_multi is not None):
+            raise ConfigError("defaut values not allowed if option: {0}" 
+                "is calculated".format(name))
+        self.callback = callback
+        if self.callback is None and callback_params is not None:
+            raise ConfigError("params defined for a callback function but"
+            " no callback defined yet for option {0}".format(name)) 
+        self.callback_params = callback_params
+        if mode not in modes:
+            raise ConfigError("mode {0} not available".format(mode))
+        self.mode = mode
+        if self.multi == True:
+            if default == None:
+                default = []
+            if not isinstance(default, list) or not self.validate(default):
+                raise ConfigError("invalid default value {0} "
+                "for option {1} : not list type".format(str(default), name))
+        else:
+            if default != None and not self.validate(default):
+                raise ConfigError("invalid default value {0} " 
+                                         "for option {1}".format(str(default), name))
+        self.default = default
+        
+    def validate(self, value):
+        if self.multi == False:
+            # None allows the reset of the value
+            if value != None:
+                return self._validate(value)
+        else:
+            if not isinstance(value, list): 
+                raise ConfigError("invalid value {0} " 
+                        "for option {1} which must be a list".format(value,
+                        self._name))
+            for val in value:
+                if val != None:
+                    # None allows the reset of the value
+                    if not self._validate(val):
+                        return False
+        return True
+
+    def getdefault(self):
+        return self.default
+
+    def getdoc(self):
+        return self.doc
+
+    def getcallback(self):
+        return self.callback
+
+    def getcallback_params(self):
+        return self.callback_params
+
+    def setowner(self, config, owner):
+        # config *must* be only the **parent** config (not the toplevel config) 
+        # owner is a **real* owner, a list is actually allowable here
+        name = self._name
+        if self._frozen:
+            raise TypeError("trying to change a frozen option's owner: %s" % name)
+        if owner in special_owners:
+            if self.callback == None:
+                raise SpecialOwnersError("no callback specified for" 
+                                                      "option {0}".format(name))
+        if self.is_multi():
+            if not type(owner) == list:
+                raise ConfigError("invalid owner for multi "
+                    "option: {0}".format(self._name))
+        config._cfgimpl_value_owners[name] = owner
+
+    def getowner(self, config):
+        # config *must* be only the **parent** config (not the toplevel config) 
+        return config._cfgimpl_value_owners[self._name]
+
+    def setoption(self, config, value, who):
+        "who is **not necessarily** a owner because it cannot be a list"
+        name = self._name
+        if self._frozen:
+            raise TypeError('trying to change a frozen option object: %s' % name)
+        # we want the possibility to reset everything
+        if who == "default" and value is None:
+            self.default = None
+            return
+        if not self.validate(value):
+            raise ConfigError('invalid value %s for option %s' % (value, name))
+        if who == "default":
+            # changes the default value (and therefore resets the previous value)
+            if self._validate(value):
+                self.default = value
+            else:
+                raise ConfigError("invalid value %s for option %s" % (value, name))
+        apply_requires(self, config)
+        # FIXME put the validation for the multi somewhere else
+#            # it is a multi **and** it has requires
+#            if self.multi == True:
+#                if type(value) != list:
+#                    raise TypeError("value {0} must be a list".format(value))
+#                if self._requires is not None:
+#                    for reqname in self._requires:
+#                        # FIXME : verify that the slaves are all multi
+#                        #option = getattr(config._cfgimpl_descr, reqname)
+#    #                    if not option.multi == True:
+#    #                        raise ConflictConfigError("an option with requires "
+#    #                         "has to be a list type : {0}".format(name)) 
+#                        if len(config._cfgimpl_values[reqname]) != len(value):
+#                            raise ConflictConfigError("an option with requires "
+#                             "has not the same length of the others " 
+#                             "in the group : {0}".format(reqname)) 
+        config._cfgimpl_previous_values[name] = config._cfgimpl_values[name] 
+        config._cfgimpl_values[name] = value
+
+    def getkey(self, value):
+        return value
+
+    def freeze(self):
+        self._frozen = True
+        return True
+
+    def unfreeze(self):
+        self._frozen = False
+    # ____________________________________________________________
+    def is_multi(self):
+        return self.multi
+
+    def is_mandatory(self):
+        return self._mandatory
+        
+class ChoiceOption(Option):
+    opt_type = 'string'
+    
+    def __init__(self, name, doc, values, default=None, requires=None,
+                 callback=None, callback_params=None, multi=False, 
+                                                           mandatory=False):
+        self.values = values
+        super(ChoiceOption, self).__init__(name, doc, default=default,
+                           callback=callback, callback_params=callback_params, 
+                           requires=requires, multi=multi, mandatory=mandatory)
+
+    def setoption(self, config, value, who):
+        name = self._name
+        super(ChoiceOption, self).setoption(config, value, who)
+
+    def _validate(self, value):
+        return value is None or value in self.values
+
+class BoolOption(Option):
+    opt_type = 'bool'
+    
+#    def __init__(self, name, doc, default=None, requires=None,
+#                                  validator=None, multi=False, mandatory=False):
+#        super(BoolOption, self).__init__(name, doc, default=default, 
+#                            requires=requires, multi=multi, mandatory=mandatory)
+        #self._validator = validator
+
+    def _validate(self, value):
+        return isinstance(value, bool)
+
+# FIXME config level validator             
+#    def setoption(self, config, value, who):
+#        name = self._name
+#        if value and self._validator is not None:
+#            toplevel = config._cfgimpl_get_toplevel()
+#            self._validator(toplevel)
+#        super(BoolOption, self).setoption(config, value, who)
+
+class IntOption(Option):
+    opt_type = 'int'
+    
+    def _validate(self, value):
+        try:
+            int(value)
+        except TypeError:
+            return False
+        return True
+                            
+    def setoption(self, config, value, who):
+        try:
+            super(IntOption, self).setoption(config, value, who)
+        except TypeError, e:
+            raise ConfigError(*e.args)
+
+class FloatOption(Option):
+    opt_type = 'float'
+
+    def _validate(self, value):
+        try:
+            float(value)
+        except TypeError:
+            return False
+        return True
+
+    def setoption(self, config, value, who):
+        try:
+            super(FloatOption, self).setoption(config, float(value), who)
+        except TypeError, e:
+            raise ConfigError(*e.args)
+
+class StrOption(Option):
+    opt_type = 'string'
+    
+    def _validate(self, value):
+        return isinstance(value, str)
+                                     
+    def setoption(self, config, value, who):
+        try:
+            super(StrOption, self).setoption(config, value, who)
+        except TypeError, e:
+            raise ConfigError(*e.args)
+
+class SymLinkOption(object): #(HiddenBaseType, DisabledBaseType):
+    opt_type = 'symlink'
+    
+    def __init__(self, name, path):
+        self._name = name
+        self.path = path 
+    
+    def setoption(self, config, value, who):
+        try:
+            setattr(config, self.path, value) # .setoption(self.path, value, who)
+        except TypeError, e:
+            raise ConfigError(*e.args)
+
+class IPOption(Option):
+    opt_type = 'ip'
+    
+    def _validate(self, value):
+        # by now the validation is nothing but a string, use IPy instead
+        return isinstance(value, str)
+                                     
+    def setoption(self, config, value, who):
+        try:
+            super(IPOption, self).setoption(config, value, who)
+        except TypeError, e:
+            raise ConfigError(*e.args)
+
+class NetmaskOption(Option):
+    opt_type = 'netmask'
+    
+    def _validate(self, value):
+        # by now the validation is nothing but a string, use IPy instead
+        return isinstance(value, str)
+                                     
+    def setoption(self, config, value, who):
+        try:
+            super(NetmaskOption, self).setoption(config, value, who)
+        except TypeError, e:
+            raise ConfigError(*e.args)
+
+class ArbitraryOption(Option):
+    def __init__(self, name, doc, default=None, defaultfactory=None, 
+                                   requires=None, multi=False, mandatory=False):
+        super(ArbitraryOption, self).__init__(name, doc, requires=requires,
+                                               multi=multi, mandatory=mandatory)
+        self.defaultfactory = defaultfactory
+        if defaultfactory is not None:
+            assert default is None
+
+    def _validate(self, value):
+        return True
+
+    def getdefault(self):
+        if self.defaultfactory is not None:
+            return self.defaultfactory()
+        return self.default
+
+class OptionDescription(HiddenBaseType, DisabledBaseType, ModeBaseType):
+    group_type = 'default'
+    
+    def __init__(self, name, doc, children, requires=None):
+        self._name = name
+        self.doc = doc
+        self._children = children
+        self._requires = requires
+        self._build()
+    
+    def getdoc(self):
+        return self.doc
+
+    def _build(self):
+        for child in self._children:
+            setattr(self, child._name, child)
+
+    def add_child(self, child):
+        "dynamically adds a configuration option"
+        #Nothing is static. Even the Mona Lisa is falling apart.
+        for ch in self._children:
+            if isinstance(ch, Option):
+                if child._name == ch._name:
+                    raise ConflictConfigError("existing option : {0}".format(
+                                                                   child._name))
+        self._children.append(child)
+        setattr(self, child._name, child)
+    
+    def update_child(self, child):
+        "modification of an existing option"
+        # XXX : corresponds to the `redefine`, is it usefull 
+        pass
+        
+    def getkey(self, config):
+        return tuple([child.getkey(getattr(config, child._name))
+                      for child in self._children])
+
+    def getpaths(self, include_groups=False, currpath=None):
+        """returns a list of all paths in self, recursively
+           currpath should not be provided (helps with recursion)
+        """
+        if currpath is None:
+            currpath = []
+        paths = []
+        for option in self._children:
+            attr = option._name
+            if attr.startswith('_cfgimpl'):
+                continue
+            value = getattr(self, attr)
+            if isinstance(value, OptionDescription):
+                if include_groups:
+                    paths.append('.'.join(currpath + [attr]))
+                currpath.append(attr)
+                paths += value.getpaths(include_groups=include_groups,
+                                        currpath=currpath)
+                currpath.pop()
+            else:
+                paths.append('.'.join(currpath + [attr]))
+        return paths
+    # ____________________________________________________________
+
+    def set_group_type(self, group_type):
+        if group_type in group_types:
+            self.group_type = group_type
+        else:
+            raise ConfigError('not allowed value for group_type : {0}'.format(
+                              group_type))
+    
+    def get_group_type(self):
+        return self.group_type
+    # ____________________________________________________________
+    def hide(self):
+        super(OptionDescription, self).hide()
+        # FIXME : AND THE SUBCHILDREN ? 
+        for child in self._children:
+            if isinstance(child, OptionDescription):
+                child.hide()
+    
+    def show(self):
+        # FIXME : AND THE SUBCHILDREN ?? 
+        super(OptionDescription, self).show()
+        for child in self._children:
+            if isinstance(child, OptionDescription):
+                child.show()
+    # ____________________________________________________________
+    def disable(self):
+        super(OptionDescription, self).disable()
+        # FIXME : AND THE SUBCHILDREN ? 
+        for child in self._children:
+            if isinstance(child, OptionDescription):
+                child.disable()
+    
+    def enable(self):
+        # FIXME : AND THE SUBCHILDREN ? 
+        super(OptionDescription, self).enable()
+        for child in self._children:
+            if isinstance(child, OptionDescription):
+                child.enable()
+# ____________________________________________________________
+def apply_requires(opt, config):
+    if hasattr(opt, '_requires'):
+        if opt._requires is not None:
+            # malformed requirements
+            rootconfig = config._cfgimpl_get_toplevel()
+            for req in opt._requires:
+                if not type(req) == tuple and len(req) in (3, 4):
+                    raise RequiresError("malformed requirements for option:"
+                                                   " {0}".format(opt._name))
+            # all actions **must** be identical
+            actions = [req[2] for req in opt._requires]
+            action = actions[0]
+            for act in actions:
+                if act != action:
+                    raise RequiresError("malformed requirements for option:"
+                                                   " {0}".format(opt._name))
+            # filters the callbacks
+            matches = False
+            for req in opt._requires:
+                if len(req) == 3:
+                    name, expected, action = req
+                    inverted = False
+                if len(req) == 4:
+                    name, expected, action, inverted = req
+                    if inverted == 'inverted':
+                        inverted = True
+                homeconfig, shortname = \
+                                      rootconfig._cfgimpl_get_home_by_path(name)
+                # FIXME: doesn't work with 'auto' or 'fill' yet 
+                # (copy the code from the __getattr__
+                if shortname in homeconfig._cfgimpl_values:
+                    value = homeconfig._cfgimpl_values[shortname]
+                    if (not inverted and value == expected) or \
+                            (inverted and value != expected):
+                        if action not in available_actions:
+                            raise RequiresError("malformed requirements"
+                                           " for option: {0}".format(opt._name))
+                        getattr(opt, action)() #.hide() or show() or...
+                        matches = True
+                else: # option doesn't exist ! should not happen...
+                    raise NotFoundError("required option not found: "
+                                                             "{0}".format(name))
+            # no callback has been triggered, then just reverse the action
+            if not matches:
+                getattr(opt, reverse_actions[action])()
+                
diff --git a/src/report/Makefile b/src/report/Makefile
new file mode 100644 (file)
index 0000000..760f9bb
--- /dev/null
@@ -0,0 +1,15 @@
+.SUFFIXES:
+
+.PHONY: all clean
+
+all: html
+
+generate:
+       python ./generate.py
+                       
+html: generate
+       make -C ./build all
+
+clean: 
+       make -C ./build clean
+       
diff --git a/src/report/__init__.py b/src/report/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/report/build/Makefile b/src/report/build/Makefile
new file mode 100644 (file)
index 0000000..e6b01ad
--- /dev/null
@@ -0,0 +1,18 @@
+SRC=$(wildcard *.txt)
+HTMLFRAGMENT=$(addsuffix .html, $(basename $(SRC)))
+
+.SUFFIXES:
+
+.PHONY: all clean
+
+all: html
+
+html: $(HTMLFRAGMENT)
+
+%.html: %.txt    
+       ./rst2html.py --stylesheet ./style.css $< > $@
+
+clean:
+       rm -f *.html
+       rm -f *.txt
+       
diff --git a/src/report/build/basic.css b/src/report/build/basic.css
new file mode 100644 (file)
index 0000000..f0379f3
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * basic.css
+ * ~~~~~~~~~
+ *
+ * Sphinx stylesheet -- basic theme.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+div.clearer {
+    clear: both;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+    width: 100%;
+    font-size: 90%;
+}
+
+div.related h3 {
+    display: none;
+}
+
+div.related ul {
+    margin: 0;
+    padding: 0 0 0 10px;
+    list-style: none;
+}
+
+div.related li {
+    display: inline;
+}
+
+div.related li.right {
+    float: right;
+    margin-right: 5px;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+    padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+    float: left;
+    width: 230px;
+    margin-left: -100%;
+    font-size: 90%;
+}
+
+div.sphinxsidebar ul {
+    list-style: none;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+    margin-left: 20px;
+    list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+    margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+    border: 1px solid #98dbcc;
+    font-family: sans-serif;
+    font-size: 1em;
+}
+
+div.sphinxsidebar input[type="text"] {
+    width: 170px;
+}
+
+div.sphinxsidebar input[type="submit"] {
+    width: 30px;
+}
+
+img {
+    border: 0;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+    margin: 10px 0 0 20px;
+    padding: 0;
+}
+
+ul.search li {
+    padding: 5px 0 5px 20px;
+    background-image: url(file.png);
+    background-repeat: no-repeat;
+    background-position: 0 7px;
+}
+
+ul.search li a {
+    font-weight: bold;
+}
+
+ul.search li div.context {
+    color: #888;
+    margin: 2px 0 0 30px;
+    text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+    font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+    width: 90%;
+}
+
+table.contentstable p.biglink {
+    line-height: 150%;
+}
+
+a.biglink {
+    font-size: 1.3em;
+}
+
+span.linkdescr {
+    font-style: italic;
+    padding-top: 5px;
+    font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable {
+    width: 100%;
+}
+
+table.indextable td {
+    text-align: left;
+    vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+    height: 10px;
+}
+
+table.indextable tr.cap {
+    margin-top: 10px;
+    background-color: #f2f2f2;
+}
+
+img.toggler {
+    margin-right: 3px;
+    margin-top: 3px;
+    cursor: pointer;
+}
+
+div.modindex-jumpbox {
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    margin: 1em 0 1em 0;
+    padding: 0.4em;
+}
+
+div.genindex-jumpbox {
+    border-top: 1px solid #ddd;
+    border-bottom: 1px solid #ddd;
+    margin: 1em 0 1em 0;
+    padding: 0.4em;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+a.headerlink {
+    visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+    visibility: visible;
+}
+
+div.body p.caption {
+    text-align: inherit;
+}
+
+div.body td {
+    text-align: left;
+}
+
+.field-list ul {
+    padding-left: 1em;
+}
+
+.first {
+    margin-top: 0 !important;
+}
+
+p.rubric {
+    margin-top: 30px;
+    font-weight: bold;
+}
+
+img.align-left, .figure.align-left, object.align-left {
+    clear: left;
+    float: left;
+    margin-right: 1em;
+}
+
+img.align-right, .figure.align-right, object.align-right {
+    clear: right;
+    float: right;
+    margin-left: 1em;
+}
+
+img.align-center, .figure.align-center, object.align-center {
+  display: block;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+.align-left {
+    text-align: left;
+}
+
+.align-center {
+    text-align: center;
+}
+
+.align-right {
+    text-align: right;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar {
+    margin: 0 0 0.5em 1em;
+    border: 1px solid #ddb;
+    padding: 7px 7px 0 7px;
+    background-color: #ffe;
+    width: 40%;
+    float: right;
+}
+
+p.sidebar-title {
+    font-weight: bold;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+
+div.topic {
+    border: 1px solid #ccc;
+    padding: 7px 7px 0 7px;
+    margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+    font-size: 1.1em;
+    font-weight: bold;
+    margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+    margin-top: 10px;
+    margin-bottom: 10px;
+    padding: 7px;
+}
+
+div.admonition dt {
+    font-weight: bold;
+}
+
+div.admonition dl {
+    margin-bottom: 0;
+}
+
+p.admonition-title {
+    margin: 0px 10px 5px 0px;
+    font-weight: bold;
+}
+
+div.body p.centered {
+    text-align: center;
+    margin-top: 25px;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+    border: 0;
+    border-collapse: collapse;
+}
+
+table.docutils td, table.docutils th {
+    padding: 1px 8px 1px 5px;
+    border-top: 0;
+    border-left: 0;
+    border-right: 0;
+    border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+    border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+    border: 0 !important;
+}
+
+th {
+    text-align: left;
+    padding-right: 5px;
+}
+
+table.citation {
+    border-left: solid 1px gray;
+    margin-left: 1px;
+}
+
+table.citation td {
+    border-bottom: none;
+}
+
+/* -- other body styles ----------------------------------------------------- */
+
+ol.arabic {
+    list-style: decimal;
+}
+
+ol.loweralpha {
+    list-style: lower-alpha;
+}
+
+ol.upperalpha {
+    list-style: upper-alpha;
+}
+
+ol.lowerroman {
+    list-style: lower-roman;
+}
+
+ol.upperroman {
+    list-style: upper-roman;
+}
+
+dl {
+    margin-bottom: 15px;
+}
+
+dd p {
+    margin-top: 0px;
+}
+
+dd ul, dd table {
+    margin-bottom: 10px;
+}
+
+dd {
+    margin-top: 3px;
+    margin-bottom: 10px;
+    margin-left: 30px;
+}
+
+dt:target, .highlighted {
+    background-color: #fbe54e;
+}
+
+dl.glossary dt {
+    font-weight: bold;
+    font-size: 1.1em;
+}
+
+.field-list ul {
+    margin: 0;
+    padding-left: 1em;
+}
+
+.field-list p {
+    margin: 0;
+}
+
+.refcount {
+    color: #060;
+}
+
+.optional {
+    font-size: 1.3em;
+}
+
+.versionmodified {
+    font-style: italic;
+}
+
+.system-message {
+    background-color: #fda;
+    padding: 5px;
+    border: 3px solid red;
+}
+
+.footnote:target  {
+    background-color: #ffa;
+}
+
+.line-block {
+    display: block;
+    margin-top: 1em;
+    margin-bottom: 1em;
+}
+
+.line-block .line-block {
+    margin-top: 0;
+    margin-bottom: 0;
+    margin-left: 1.5em;
+}
+
+.guilabel, .menuselection {
+    font-family: sans-serif;
+}
+
+.accelerator {
+    text-decoration: underline;
+}
+
+.classifier {
+    font-style: oblique;
+}
+
+abbr, acronym {
+    border-bottom: dotted 1px;
+    cursor: help;
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+    overflow: auto;
+    overflow-y: hidden;  /* fixes display issues on Chrome browsers */
+}
+
+td.linenos pre {
+    padding: 5px 0px;
+    border: 0;
+    background-color: transparent;
+    color: #aaa;
+}
+
+table.highlighttable {
+    margin-left: 0.5em;
+}
+
+table.highlighttable td {
+    padding: 0 0.5em 0 0.5em;
+}
+
+tt.descname {
+    background-color: transparent;
+    font-weight: bold;
+    font-size: 1.2em;
+}
+
+tt.descclassname {
+    background-color: transparent;
+}
+
+tt.xref, a tt {
+    background-color: transparent;
+    font-weight: bold;
+}
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+    background-color: transparent;
+}
+
+.viewcode-link {
+    float: right;
+}
+
+.viewcode-back {
+    float: right;
+    font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+    margin: -1px -10px;
+    padding: 0 10px;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+    vertical-align: middle;
+}
+
+div.body div.math p {
+    text-align: center;
+}
+
+span.eqno {
+    float: right;
+}
+
+/* -- printout stylesheet --------------------------------------------------- */
+
+@media print {
+    div.document,
+    div.documentwrapper,
+    div.bodywrapper {
+        margin: 0 !important;
+        width: 100%;
+    }
+
+    div.sphinxsidebar,
+    div.related,
+    div.footer,
+    #top-link {
+        display: none;
+    }
+}
\ No newline at end of file
diff --git a/src/report/build/rst2html.py b/src/report/build/rst2html.py
new file mode 100755 (executable)
index 0000000..cfa6769
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/python
+# unproudly borrowed from David Goodger's rst2html.py
+
+""" A minimal front end to the Docutils Publisher, producing HTML with a 
+`config` role 
+"""
+
+try:
+    import locale
+    locale.setlocale(locale.LC_ALL, '')
+except:
+    pass
+
+from docutils.core import publish_cmdline, default_description
+# ____________________________________________________________
+from docutils import nodes, utils
+from docutils.parsers.rst import roles
+
+# ____________________________________________________________
+#register a :config: ReST link role for use in documentation    
+def config_reference_role(role, rawtext, text, lineno, inliner,
+                    options={}, content=[]):
+    basename = text
+    refuri = "report/build" + basename + '.html'
+    roles.set_classes(options)
+    node = nodes.reference(rawtext, utils.unescape(text), refuri=refuri,
+                        **options)
+    return [node], []
+
+roles.register_local_role('config', config_reference_role)
+# ____________________________________________________________
+
+
+description = ('Generates (X)HTML documents from standalone reStructuredText '
+               'sources.  ' + default_description)
+
+publish_cmdline(writer_name='html', description=description)
+
diff --git a/src/report/build/style.css b/src/report/build/style.css
new file mode 100644 (file)
index 0000000..1126f9d
--- /dev/null
@@ -0,0 +1,795 @@
+/*
+ * rtd.css
+ * ~~~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- sphinxdoc theme.  Originally created by
+ * Armin Ronacher for Werkzeug.
+ *
+ * Customized for ReadTheDocs by Eric Pierce & Eric Holscher
+ *
+ * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/* RTD colors
+ * light blue: #e8ecef
+ * medium blue: #8ca1af
+ * dark blue: #465158
+ * dark grey: #444444
+ *
+ * white hover: #d1d9df;
+ * medium blue hover: #697983;
+ * green highlight: #8ecc4c
+ * light blue (project bar): #e8ecef
+ */
+
+@import url("basic.css");
+
+/* PAGE LAYOUT -------------------------------------------------------------- */
+
+body {
+    font: 100%/1.5 "ff-meta-web-pro-1","ff-meta-web-pro-2",Arial,"Helvetica Neue",sans-serif; 
+    text-align: center;
+    color: black;
+    background-color: #465158;
+    padding: 0;
+    margin: 0;
+}
+
+div.document {
+    text-align: left;
+    background-color: #e8ecef;
+}
+
+div.bodywrapper {
+    background-color: #ffffff;
+    border-left: 1px solid #ccc;
+    border-bottom: 1px solid #ccc;
+    margin: 0 0 0 16em;
+}
+
+div.body {
+    margin: 0;
+    padding: 0.5em 1.3em;
+    min-width: 20em;
+}
+
+div.related {
+    font-size: 1em;
+    background-color: #465158;
+}
+
+div.documentwrapper {
+    float: left;
+    width: 100%;
+    background-color: #e8ecef;
+}
+
+
+/* HEADINGS --------------------------------------------------------------- */
+
+h1 {
+    margin: 0;
+    padding: 0.7em 0 0.3em 0;
+    font-size: 1.5em;
+    line-height: 1.15;
+    color: #111;
+    clear: both;
+}
+
+h2 {
+    margin: 2em 0 0.2em 0;
+    font-size: 1.35em;
+    padding: 0;
+    color: #465158;
+}
+
+h3 {
+    margin: 1em 0 -0.3em 0;
+    font-size: 1.2em;
+    color: #6c818f;
+}
+
+div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
+    color: black;
+}
+
+h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
+    display: none;
+    margin: 0 0 0 0.3em;
+    padding: 0 0.2em 0 0.2em;
+    color: #aaa !important;
+}
+
+h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
+h5:hover a.anchor, h6:hover a.anchor {
+    display: inline;
+}
+
+h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
+h5 a.anchor:hover, h6 a.anchor:hover {
+    color: #777;
+    background-color: #eee;
+}
+
+
+/* LINKS ------------------------------------------------------------------ */
+
+/* Normal links get a pseudo-underline */
+a {
+    color: #444;
+    text-decoration: none;
+    border-bottom: 1px solid #ccc;
+}
+
+/* Links in sidebar, TOC, index trees and tables have no underline */
+.sphinxsidebar a,
+.toctree-wrapper a,
+.indextable a,
+#indices-and-tables a {
+    color: #444;
+    text-decoration: none;
+    border-bottom: none;
+}
+
+/* Most links get an underline-effect when hovered */
+a:hover,
+div.toctree-wrapper a:hover,
+.indextable a:hover,
+#indices-and-tables a:hover {
+    color: #111;
+    text-decoration: none;
+    border-bottom: 1px solid #111;
+}
+
+/* Footer links */
+div.footer a {
+    color: #86989B;
+    text-decoration: none;
+    border: none;
+}
+div.footer a:hover {
+    color: #a6b8bb;
+    text-decoration: underline;
+    border: none;
+}
+
+/* Permalink anchor (subtle grey with a red hover) */
+div.body a.headerlink {
+    color: #ccc;
+    font-size: 1em;
+    margin-left: 6px;
+    padding: 0 4px 0 4px;
+    text-decoration: none;
+    border: none;
+}
+div.body a.headerlink:hover {
+    color: #c60f0f;
+    border: none;
+}
+
+
+/* NAVIGATION BAR --------------------------------------------------------- */
+
+div.related ul {
+    height: 2.5em;
+}
+
+div.related ul li {
+    margin: 0;
+    padding: 0.65em 0;
+    float: left;
+    display: block;
+    color: white; /* For the >> separators */
+    font-size: 0.8em;
+}
+
+div.related ul li.right {
+    float: right;
+    margin-right: 5px;
+    color: transparent; /* Hide the | separators */
+}
+
+/* "Breadcrumb" links in nav bar */
+div.related ul li a {
+    order: none;
+    background-color: inherit;
+    font-weight: bold;
+    margin: 6px 0 6px 4px;
+    line-height: 1.75em;
+    color: #ffffff;
+    padding: 0.4em 0.8em;
+    border: none;
+    border-radius: 3px;
+}
+/* previous / next / modules / index links look more like buttons */
+div.related ul li.right a {
+    margin: 0.375em 0;
+    background-color: #697983;
+    text-shadow: 0 1px rgba(0, 0, 0, 0.5);
+    border-radius: 3px;
+    -webkit-border-radius: 3px;
+    -moz-border-radius: 3px;
+}
+/* All navbar links light up as buttons when hovered */
+div.related ul li a:hover {
+    background-color: #8ca1af;
+    color: #ffffff;
+    text-decoration: none;
+    border-radius: 3px;
+    -webkit-border-radius: 3px;
+    -moz-border-radius: 3px;
+}
+/* Take extra precautions for tt within links */
+a tt,
+div.related ul li a tt {
+    background: inherit !important;
+    color: inherit !important;
+}
+
+
+/* SIDEBAR ---------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+    padding: 0;
+}
+
+div.sphinxsidebar {
+    margin: 0;
+    margin-left: -100%;
+    float: left;
+    top: 3em;
+    left: 0;
+    padding: 0 1em;
+    width: 14em;
+    font-size: 1em;
+    text-align: left;
+    background-color: #e8ecef;
+}
+
+div.sphinxsidebar img {
+    max-width: 12em;
+}
+
+div.sphinxsidebar h3,
+div.sphinxsidebar h4,
+div.sphinxsidebar p.logo {
+    margin: 1.2em 0 0.3em 0;
+    font-size: 1em;
+    padding: 0;
+    color: #222222;
+    font-family: "ff-meta-web-pro-1", "ff-meta-web-pro-2", "Arial", "Helvetica Neue", sans-serif;
+}
+
+div.sphinxsidebar h3 a {
+    color: #444444;
+}
+
+div.sphinxsidebar ul,
+div.sphinxsidebar p {
+    margin-top: 0;
+    padding-left: 0;
+    line-height: 130%;
+    background-color: #e8ecef;
+}
+
+/* No bullets for nested lists, but a little extra indentation */
+div.sphinxsidebar ul ul {
+    list-style-type: none;
+    margin-left: 1.5em;
+    padding: 0;
+}
+
+/* A little top/bottom padding to prevent adjacent links' borders
+ * from overlapping each other */
+div.sphinxsidebar ul li {
+    padding: 1px 0;
+}
+
+/* A little left-padding to make these align with the ULs */
+div.sphinxsidebar p.topless {
+    padding-left: 0 0 0 1em;
+}
+
+/* Make these into hidden one-liners */
+div.sphinxsidebar ul li,
+div.sphinxsidebar p.topless {
+    white-space: nowrap;
+    overflow: hidden;
+}
+/* ...which become visible when hovered */
+div.sphinxsidebar ul li:hover,
+div.sphinxsidebar p.topless:hover {
+    overflow: visible;
+}
+
+/* Search text box and "Go" button */
+#searchbox {
+    margin-top: 2em;
+    margin-bottom: 1em;
+    background: #ddd;
+    padding: 0.5em;
+    border-radius: 6px;
+    -moz-border-radius: 6px;
+    -webkit-border-radius: 6px;
+}
+#searchbox h3 {
+    margin-top: 0;
+}
+
+/* Make search box and button abut and have a border */
+input,
+div.sphinxsidebar input {
+    border: 1px solid #999;
+    float: left;
+}
+
+/* Search textbox */
+input[type="text"] {
+    margin: 0;
+    padding: 0 3px;
+    height: 20px;
+    width: 144px;
+    border-top-left-radius: 3px;
+    border-bottom-left-radius: 3px;
+    -moz-border-radius-topleft: 3px;
+    -moz-border-radius-bottomleft: 3px;
+    -webkit-border-top-left-radius: 3px;
+    -webkit-border-bottom-left-radius: 3px;
+}
+/* Search button */
+input[type="submit"] {
+    margin: 0 0 0 -1px; /* -1px prevents a double-border with textbox */
+    height: 22px;
+    color: #444;
+    background-color: #e8ecef;
+    padding: 1px 4px;
+    font-weight: bold;
+    border-top-right-radius: 3px;
+    border-bottom-right-radius: 3px;
+    -moz-border-radius-topright: 3px;
+    -moz-border-radius-bottomright: 3px;
+    -webkit-border-top-right-radius: 3px;
+    -webkit-border-bottom-right-radius: 3px;
+}
+input[type="submit"]:hover {
+    color: #ffffff;
+    background-color: #8ecc4c;
+}
+
+div.sphinxsidebar p.searchtip {
+    clear: both;
+    padding: 0.5em 0 0 0;
+    background: #ddd;
+    color: #666;
+    font-size: 0.9em;
+}
+
+/* Sidebar links are unusual */
+div.sphinxsidebar li a,
+div.sphinxsidebar p a {
+    background: #e8ecef; /* In case links overlap main content */
+    border-radius: 3px;
+    -moz-border-radius: 3px;
+    -webkit-border-radius: 3px;
+    border: 1px solid transparent; /* To prevent things jumping around on hover */
+    padding: 0 5px 0 5px;
+}
+div.sphinxsidebar li a:hover,
+div.sphinxsidebar p a:hover {
+    color: #111;
+    text-decoration: none;
+    border: 1px solid #888;
+}
+div.sphinxsidebar p.logo a {
+    border: 0;
+}
+
+/* Tweak any link appearing in a heading */
+div.sphinxsidebar h3 a {
+}
+
+
+
+
+/* OTHER STUFF ------------------------------------------------------------ */
+
+cite, code, tt {
+    font-family: 'Consolas', 'Deja Vu Sans Mono',
+                 'Bitstream Vera Sans Mono', monospace;
+    font-size: 0.95em;
+    letter-spacing: 0.01em;
+}
+
+tt {
+    background-color: #f2f2f2;
+    color: #444;
+}
+
+tt.descname, tt.descclassname, tt.xref {
+    border: 0;
+}
+
+hr {
+    border: 1px solid #abc;
+    margin: 2em;
+}
+
+
+pre, #_fontwidthtest {
+    font-family: 'Consolas', 'Deja Vu Sans Mono',
+                 'Bitstream Vera Sans Mono', monospace;
+    margin: 1em 2em;
+    font-size: 0.95em;
+    letter-spacing: 0.015em;
+    line-height: 120%;
+    padding: 0.5em;
+    border: 1px solid #ccc;
+    background-color: #eee;
+    border-radius: 6px;
+    -moz-border-radius: 6px;
+    -webkit-border-radius: 6px;
+}
+
+pre a {
+    color: inherit;
+    text-decoration: underline;
+}
+
+td.linenos pre {
+    margin: 1em 0em;
+}
+
+td.code pre {
+    margin: 1em 0em;
+}
+
+div.quotebar {
+    background-color: #f8f8f8;
+    max-width: 250px;
+    float: right;
+    padding: 2px 7px;
+    border: 1px solid #ccc;
+}
+
+div.topic {
+    background-color: #f8f8f8;
+}
+
+table {
+    border-collapse: collapse;
+    margin: 0 -0.5em 0 -0.5em;
+}
+
+table td, table th {
+    padding: 0.2em 0.5em 0.2em 0.5em;
+}
+
+
+/* ADMONITIONS AND WARNINGS ------------------------------------------------- */
+
+/* Shared by admonitions, warnings and sidebars */
+div.admonition,
+div.warning,
+div.sidebar {
+    font-size: 0.9em;
+    margin: 2em;
+    padding: 0;
+    /*
+    border-radius: 6px;
+    -moz-border-radius: 6px;
+    -webkit-border-radius: 6px;
+    */
+}
+div.admonition p,
+div.warning p,
+div.sidebar p {
+    margin: 0.5em 1em 0.5em 1em;
+    padding: 0;
+}
+div.admonition pre,
+div.warning pre,
+div.sidebar pre {
+    margin: 0.4em 1em 0.4em 1em;
+}
+div.admonition p.admonition-title,
+div.warning p.admonition-title,
+div.sidebar p.sidebar-title {
+    margin: 0;
+    padding: 0.1em 0 0.1em 0.5em;
+    color: white;
+    font-weight: bold;
+    font-size: 1.1em;
+    text-shadow: 0 1px rgba(0, 0, 0, 0.5);
+}
+div.admonition ul, div.admonition ol,
+div.warning ul, div.warning ol,
+div.sidebar ul, div.sidebar ol {
+    margin: 0.1em 0.5em 0.5em 3em;
+    padding: 0;
+}
+
+
+/* Admonitions and sidebars only */
+div.admonition, div.sidebar {
+    border: 1px solid #609060;
+    background-color: #e9ffe9;
+}
+div.admonition p.admonition-title,
+div.sidebar p.sidebar-title {
+    background-color: #70A070;
+    border-bottom: 1px solid #609060;
+}
+
+
+/* Warnings only */
+div.warning {
+    border: 1px solid #900000;
+    background-color: #ffe9e9;
+}
+div.warning p.admonition-title {
+    background-color: #b04040;
+    border-bottom: 1px solid #900000;
+}
+
+
+/* Sidebars only */
+div.sidebar {
+  max-width: 30%;
+}
+
+
+
+div.versioninfo {
+    margin: 1em 0 0 0;
+    border: 1px solid #ccc;
+    background-color: #DDEAF0;
+    padding: 8px;
+    line-height: 1.3em;
+    font-size: 0.9em;
+}
+
+.viewcode-back {
+    font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+                 'Verdana', sans-serif;
+}
+
+div.viewcode-block:target {
+    background-color: #f4debf;
+    border-top: 1px solid #ac9;
+    border-bottom: 1px solid #ac9;
+}
+
+dl {
+    margin: 1em 0 2.5em 0;
+}
+
+/* Highlight target when you click an internal link */
+dt:target {
+    background: #ffe080;
+}
+/* Don't highlight whole divs */
+div.highlight {
+    background: transparent;
+}
+/* But do highlight spans (so search results can be highlighted) */
+span.highlight {
+    background: #ffe080;
+}
+
+div.footer {
+    background-color: #465158;
+    color: #eeeeee;
+    padding: 0 2em 2em 2em;
+    clear: both;
+    font-size: 0.8em;
+    text-align: center;
+}
+
+p {
+    margin: 0.8em 0 0.5em 0;
+}
+
+.section p img.math {
+    margin: 0;
+}
+
+
+.section p img {
+    margin: 1em 2em;
+}
+
+
+/* MOBILE LAYOUT -------------------------------------------------------------- */
+
+@media screen and (max-width: 600px) {
+    
+    h1, h2, h3, h4, h5 {
+        position: relative;
+    }
+
+    ul {
+        padding-left: 1.25em;
+    }
+
+    div.bodywrapper a.headerlink, #indices-and-tables h1 a {
+        color: #e6e6e6;
+        font-size: 80%;
+        float: right;
+        line-height: 1.8;
+        position: absolute;
+        right: -0.7em;
+        visibility: inherit;
+    }
+
+    div.bodywrapper h1 a.headerlink, #indices-and-tables h1 a {
+        line-height: 1.5;
+    }
+
+    pre {
+        font-size: 0.7em;
+        overflow: auto;
+        word-wrap: break-word;
+        white-space: pre-wrap;
+    }
+
+    div.related ul {
+        height: 2.5em;
+        padding: 0;
+        text-align: left;
+    }
+
+    div.related ul li {
+        clear: both;
+        color: #465158;
+        padding: 0.2em 0;
+    }
+
+    div.related ul li:last-child {
+        border-bottom: 1px dotted #8ca1af;
+        padding-bottom: 0.4em;
+        margin-bottom: 1em;
+        width: 100%;
+    }
+
+    div.related ul li a {
+        color: #465158;
+        padding-right: 0;
+    }
+
+    div.related ul li a:hover {
+        background: inherit;
+        color: inherit;
+    }
+
+    div.related ul li.right {
+        clear: none;
+        padding: 0.65em 0;
+        margin-bottom: 0.5em;
+    }
+
+    div.related ul li.right a {
+        color: #fff;
+        padding-right: 0.8em;
+    }
+
+    div.related ul li.right a:hover {
+        background-color: #8ca1af;
+    }
+
+    div.body {
+        clear: both;
+        min-width: 0;
+        word-wrap: break-word;
+    }
+
+    div.bodywrapper {
+        margin: 0 0 0 0;
+    }
+
+    div.sphinxsidebar {
+        float: none;
+        margin: 0;
+        width: auto;
+    }
+
+    div.sphinxsidebar input[type="text"] {
+        height: 2em;
+        line-height: 2em;
+        width: 70%;
+    }
+
+    div.sphinxsidebar input[type="submit"] {
+        height: 2em;
+        margin-left: 0.5em;
+        width: 20%;
+    }
+
+    div.sphinxsidebar p.searchtip {
+        background: inherit;
+        margin-bottom: 1em;
+    }
+
+    div.sphinxsidebar ul li, div.sphinxsidebar p.topless {
+        white-space: normal;
+    }
+
+    .bodywrapper img {
+        display: block;
+        margin-left: auto;
+        margin-right: auto;
+        max-width: 100%;
+    }
+
+    div.documentwrapper {
+        float: none;
+    }
+
+    div.admonition, div.warning, pre, blockquote {
+        margin-left: 0em;
+        margin-right: 0em;
+    }
+
+    .body p img {
+        margin: 0;
+    }
+
+    #searchbox {
+        background: transparent;
+    }
+
+    .related:not(:first-child) li {
+        display: none;
+    }
+
+    .related:not(:first-child) li.right {
+        display: block;
+    }
+
+    div.footer {
+        padding: 1em;
+    }
+
+    .rtd_doc_footer .badge {
+        float: none;
+        margin: 1em auto;
+        position: static;
+    }
+
+    .rtd_doc_footer .badge.revsys-inline {
+        margin-right: auto;
+        margin-bottom: 2em;
+    }
+
+    table.indextable {
+        display: block;
+        width: auto; 
+    }
+
+    .indextable tr {
+        display: block;
+    }
+
+    .indextable td {
+        display: block;
+        padding: 0;
+        width: auto !important;
+    }
+
+    .indextable td dt {
+        margin: 1em 0;
+    }
+
+    ul.search {
+        margin-left: 0.25em;
+    }
+
+    ul.search li div.context {
+        font-size: 90%;
+        line-height: 1.1;
+        margin-bottom: 1;
+        margin-left: 0;
+    }
+
+}
diff --git a/src/report/generate.py b/src/report/generate.py
new file mode 100644 (file)
index 0000000..b4112a1
--- /dev/null
@@ -0,0 +1,99 @@
+from os.path import dirname, join
+from rst import Rest, Paragraph, Strong, OrderedListItem, ListItem, Title, Link, Transition
+from rst import Directive, Em, Quote, Text
+from tiramisu.option import *
+from tiramisu.config import *
+#from makerestdoc import *
+
+docdir = join(dirname(__file__), 'build')
+
+def make_rst_file(filename, rstcontent):
+    fh = file(filename, 'w')
+    fh.write(rstcontent.text())
+    fh.close()
+
+def descr_content(path, prefix, descr, root=False):
+    content = Rest()
+    title = Title(abovechar="", belowchar="=")
+    if root:
+        title.join(Text("Configuration's overview for: "), Quote(descr._name))
+    else:
+        title.join(Text("Group's overview for: "), Quote(descr._name))
+    content.add(title)
+    content.add(ListItem().join(Strong("name:"), Text(descr._name)))
+    if not root:
+        content.add(ListItem().join(Strong("path:"), Text(path)))
+    content.add(ListItem().join(Strong("description:"), Text(descr.doc)))
+    if not root:
+        content.add(ListItem().join(Strong("container:"), Text(prefix)))
+    if not root:
+        content.add(ListItem().join(Strong("type:"), Text(descr.group_type)))
+    if not root:
+        content.add(ListItem().join(Strong("requirements:"), Text(str(descr._requires))))
+    content.add(ListItem().join(Strong("is hidden:"), Text(str(descr._is_hidden()))))
+    content.add(ListItem().join(Strong("is disabled:"), Text(str(descr._is_disabled()))))
+    content.add(Transition())
+    content.add(Title(abovechar="", belowchar="-").join(Text("Ordered list of childrens for:"), Text(path)))
+    for opt in descr._children:
+        name = opt._name
+        link = Link(name + ":", join(path + '.' + name + ".html"))
+        # because of SympLink opt
+        if hasattr(opt, 'doc'):
+            doc = opt.doc
+        else:
+            doc = name
+        content.add(OrderedListItem(link, Text(opt.doc)))
+    content.add(Transition())
+    content.add(Paragraph(Link("back to index", "index.html")))
+    make_rst_file(join(docdir, path + '.txt'), content)
+    if root:
+        make_rst_file(join(docdir, 'index.txt'), content)
+    
+def opt_rst_content(path, prefix, descr, value):
+    content = Rest()
+    title = Title(abovechar="", belowchar="=")
+    title.join(Text("Configuration's option overview for: "), Quote(descr._name))
+    content.add(title)
+    content.add(ListItem().join(Strong("name:"), Text(descr._name)))
+    content.add(ListItem().join(Strong("value:"), Text(str(value))))
+    content.add(ListItem().join(Strong("path:"), Text(path)))
+    content.add(ListItem().join(Strong("container:"), Text(prefix)))
+    if isinstance(descr, ChoiceOption):
+        content.add(ListItem().join(Strong("possible values:"), Text(str(descr.values))))
+    if not isinstance(descr, SymLinkOption):
+        content.add(ListItem().join(Strong("type:"), Text(str(descr.opt_type))))
+        content.add(ListItem().join(Strong("default:"), Text(str(descr.getdefault()))))
+        content.add(ListItem().join(Strong("description:"), Text(str(descr.getdoc()))))
+        content.add(ListItem().join(Strong("requirements:"), Text(str(descr._requires))))
+        content.add(ListItem().join(Strong("is hidden:"), Text(str(descr._is_hidden()))))
+        content.add(ListItem().join(Strong("is disabled:"), Text(str(descr._is_disabled()))))
+        content.add(ListItem().join(Strong("is frozen:"), Text(str(descr._frozen))))
+        content.add(ListItem().join(Strong("is multi:"), Text(str(descr.multi))))
+        content.add(ListItem().join(Strong("is mandatory:"), Text(str(descr.is_mandatory()))))
+    else:
+        content.add(ListItem().join(Strong("links to:"), Text(str(descr.path))))
+    content.add(Transition())
+    content.add(Paragraph(Link("back to container", join(prefix + ".html"))))
+    make_rst_file(join(docdir, path + '.txt'), content)
+        
+def make_rest_overview(cfg, title=True):
+    rootname = cfg._cfgimpl_descr._name
+    descr_content(rootname, rootname, cfg._cfgimpl_descr, root=True)
+    #cfg.cfgimpl_read_write()
+    cfg._cfgimpl_disabled = False
+    cfg._cfgimpl_hidden = False
+    for path in cfg.getpaths(include_groups=True, allpaths=True):
+        child = cfg.unwrap_from_path(path)
+        fullpath = rootname + '.' + path 
+        prefix = fullpath.rsplit(".", 1)[0]
+        if isinstance(child, OptionDescription):
+            descr_content(fullpath, prefix, child)
+        else: 
+            value = getattr(cfg, path)
+            opt_rst_content(fullpath, prefix, child, value)
+
+if __name__ == '__main__':
+    from test_config_big_example import get_example_config
+    make_rest_overview(get_example_config())
+# ____________________________________________________________
+
diff --git a/src/report/makerestdoc.py b/src/report/makerestdoc.py
new file mode 100644 (file)
index 0000000..3ca042d
--- /dev/null
@@ -0,0 +1,115 @@
+from tiramisu.config import Config
+from tiramisu import option
+# we shall keep extendable types out of the reach of unexceptional guys like us 
+# horror __metaclass__ = extendabletype
+
+def get_fullpath(opt, path):
+    if path:
+        return "%s.%s" % (path, opt._name)
+    else:
+        return opt._name
+
+class Option:
+    def make_rest_doc(self, path=""):
+        fullpath = get_fullpath(self, path)
+        result = Rest(
+            Title(fullpath, abovechar="=", belowchar="="),
+            ListItem(Strong("name:"), self._name),
+            ListItem(Strong("description:"), self.doc))
+        return result
+
+class ChoiceOption(Option, option.ChoiceOption):
+    def make_rest_doc(self, path=""):
+        content = super(ChoiceOption, self).make_rest_doc(path)
+        content.add(ListItem(Strong("option type:"), "choice option"))
+        content.add(ListItem(Strong("possible values:"),
+                             *[ListItem(str(val)) for val in self.values]))
+        if self.default is not None:
+            content.add(ListItem(Strong("default:"), str(self.default)))
+
+#        requirements = []
+#        
+#        for val in self.values:
+#            if val not in self._requires:
+#                continue
+#            req = self._requires[val]
+#            requirements.append(ListItem("value '%s' requires:" % (val, ),
+#                *[ListItem(Link(opt, opt + ".html"),
+#                           "to be set to '%s'" % (rval, ))
+#                      for (opt, rval) in req]))
+#        if requirements:
+#            content.add(ListItem(Strong("requirements:"), *requirements))
+        return content
+
+class BoolOption(Option, option.BoolOption):
+    def make_rest_doc(self, path=""):
+        content = super(BoolOption, self).make_rest_doc(path)
+        fullpath = get_fullpath(self, path)
+        content.add(ListItem(Strong("option type:"), "boolean option"))
+        if self.default is not None:
+            content.add(ListItem(Strong("default:"), str(self.default)))
+#        if self._requires is not None:
+#            requirements = [ListItem(Link(opt, opt + ".html"),
+#                               "must be set to '%s'" % (rval, ))
+#                                for (opt, rval) in self._requires]
+#            if requirements:
+#                content.add(ListItem(Strong("requirements:"), *requirements))
+        return content
+
+class IntOption(Option, option.IntOption):
+    def make_rest_doc(self, path=""):
+        content = super(IntOption, self).make_rest_doc(path)
+        content.add(ListItem(Strong("option type:"), "integer option"))
+        if self.default is not None:
+            content.add(ListItem(Strong("default:"), str(self.default)))
+        return content
+
+class FloatOption(Option, option.FloatOption):
+    def make_rest_doc(self, path=""):
+        content = super(FloatOption, self).make_rest_doc(path)
+        content.add(ListItem(Strong("option type:"), "float option"))
+        if self.default is not None:
+            content.add(ListItem(Strong("default:"), str(self.default)))
+        return content
+
+class StrOption(Option, option.StrOption):
+    def make_rest_doc(self, path=""):
+        content = super(StrOption, self).make_rest_doc(path)
+        content.add(ListItem(Strong("option type:"), "string option"))
+        if self.default is not None:
+            content.add(ListItem(Strong("default:"), str(self.default)))
+        return content
+
+#class ArbitraryOption:
+#    def make_rest_doc(self, path=""):
+#        content = super(ArbitraryOption, self).make_rest_doc(path)
+#        content.add(ListItem(Strong("option type:"),
+#                             "arbitrary option (mostly internal)"))
+#        if self.default is not None:
+#            content.add(ListItem(Strong("default:"), str(self.default)))
+#        elif self.defaultfactory is not None:
+#            content.add(ListItem(Strong("factory for the default value:"),
+#                                 str(self.defaultfactory)))
+#        return content
+
+class OptionDescription(option.OptionDescription):
+    def make_rest_doc(self, path=""):
+        fullpath = get_fullpath(self, path)
+        content = Rest(
+            Title(fullpath, abovechar="=", belowchar="="))
+        toctree = []
+        for child in self._children:
+            subpath = fullpath + "." + child._name
+            toctree.append(subpath)
+        content.add(Directive("toctree", *toctree, **{'maxdepth': 4}))
+        content.join(
+            ListItem(Strong("name:"), self._name),
+            ListItem(Strong("description:"), self.doc))
+        stack = []
+        curr = content
+#        config = Config(self)
+        return content
+
+# ____________________________________________________________
+
+
diff --git a/src/report/rst.py b/src/report/rst.py
new file mode 100644 (file)
index 0000000..7548cdd
--- /dev/null
@@ -0,0 +1,410 @@
+# unproudly borrowed from pypy : 
+# http://codespeak.net/svn/pypy/trunk/pypy/tool/rest/rst.py
+""" reStructuredText generation tools
+
+    provides an api to build a tree from nodes, which can be converted to
+    ReStructuredText on demand
+
+    note that not all of ReST is supported, a usable subset is offered, but
+    certain features aren't supported, and also certain details (like how links
+    are generated, or how escaping is done) can not be controlled
+"""
+
+import re
+
+def escape(txt):
+    """escape ReST markup"""
+    if not isinstance(txt, str) and not isinstance(txt, unicode):
+        txt = str(txt)
+    # XXX this takes a very naive approach to escaping, but it seems to be
+    # sufficient...
+    for c in '\\*`|:_':
+        txt = txt.replace(c, '\\%s' % (c,))
+    return txt
+
+class RestError(Exception):
+    """ raised on containment errors (wrong parent) """
+
+class AbstractMetaclass(type):
+    def __new__(cls, *args):
+        obj = super(AbstractMetaclass, cls).__new__(cls, *args)
+        parent_cls = obj.parentclass
+        if parent_cls is None:
+            return obj
+        if not isinstance(parent_cls, list):
+            class_list = [parent_cls]
+        else:
+            class_list = parent_cls
+        if obj.allow_nesting:
+            class_list.append(obj)
+        
+        for _class in class_list:
+            if not _class.allowed_child:
+                _class.allowed_child = {obj:True}
+            else:
+                _class.allowed_child[obj] = True
+        return obj
+
+class AbstractNode(object):
+    """ Base class implementing rest generation
+    """
+    sep = ''
+    __metaclass__ = AbstractMetaclass
+    parentclass = None # this exists to allow parent to know what
+        # children can exist
+    allow_nesting = False
+    allowed_child = {}
+    defaults = {}
+    
+    _reg_whitespace = re.compile('\s+')
+
+    def __init__(self, *args, **kwargs):
+        self.parent = None
+        self.children = []
+        for child in args:
+            self._add(child)
+        for arg in kwargs:
+            setattr(self, arg, kwargs[arg])
+    
+    def join(self, *children):
+        """ add child nodes
+        
+            returns a reference to self
+        """
+        for child in children:
+            self._add(child)
+        return self
+    
+    def add(self, child):
+        """ adds a child node
+            
+            returns a reference to the child
+        """
+        self._add(child)
+        return child
+        
+    def _add(self, child):
+        if child.__class__ not in self.allowed_child:
+            raise RestError("%r cannot be child of %r" % \
+                (child.__class__, self.__class__))
+        self.children.append(child)
+        child.parent = self
+    
+    def __getitem__(self, item):
+        return self.children[item]
+    
+    def __setitem__(self, item, value):
+        self.children[item] = value
+
+    def text(self):
+        """ return a ReST string representation of the node """
+        return self.sep.join([child.text() for child in self.children])
+    
+    def wordlist(self):
+        """ return a list of ReST strings for this node and its children """ 
+        return [self.text()]
+
+class Rest(AbstractNode):
+    """ Root node of a document """
+    
+    sep = "\n\n"
+    def __init__(self, *args, **kwargs):
+        AbstractNode.__init__(self, *args, **kwargs)
+        self.links = {}
+    
+    def render_links(self, check=False):
+        """render the link attachments of the document"""
+        assert not check, "Link checking not implemented"
+        if not self.links:
+            return ""
+        link_texts = []
+        # XXX this could check for duplicates and remove them...
+        for link, target in self.links.iteritems():
+            link_texts.append(".. _`%s`: %s" % (escape(link), target))
+        return "\n" + "\n".join(link_texts) + "\n\n"
+
+    def text(self):
+        outcome = []
+        if (isinstance(self.children[0], Transition) or
+                isinstance(self.children[-1], Transition)):
+            raise ValueError, ('document must not begin or end with a '
+                               'transition')
+        for child in self.children:
+            outcome.append(child.text())
+        
+        # always a trailing newline
+        text = self.sep.join([i for i in outcome if i]) + "\n"
+        return text + self.render_links()
+
+class Transition(AbstractNode):
+    """ a horizontal line """
+    parentclass = Rest
+
+    def __init__(self, char='-', width=80, *args, **kwargs):
+        self.char = char
+        self.width = width
+        super(Transition, self).__init__(*args, **kwargs)
+        
+    def text(self):
+        return (self.width - 1) * self.char
+
+class Paragraph(AbstractNode):
+    """ simple paragraph """
+
+    parentclass = Rest
+    sep = " "
+    indent = ""
+    # FIXME
+    width = 880
+    
+    def __init__(self, *args, **kwargs):
+        # make shortcut
+        args = list(args)
+        for num, arg in enumerate(args):
+            if isinstance(arg, str):
+                args[num] = Text(arg)
+        super(Paragraph, self).__init__(*args, **kwargs)
+    
+    def text(self):
+        texts = []
+        for child in self.children:
+            texts += child.wordlist()
+        
+        buf = []
+        outcome = []
+        lgt = len(self.indent)
+        
+        def grab(buf):
+            outcome.append(self.indent + self.sep.join(buf))
+        
+        texts.reverse()
+        while texts:
+            next = texts[-1]
+            if not next:
+                texts.pop()
+                continue
+            if lgt + len(self.sep) + len(next) <= self.width or not buf:
+                buf.append(next)
+                lgt += len(next) + len(self.sep)
+                texts.pop()
+            else:
+                grab(buf)
+                lgt = len(self.indent)
+                buf = []
+        grab(buf)
+        return "\n".join(outcome)
+    
+class SubParagraph(Paragraph):
+    """ indented sub paragraph """
+
+    indent = " "
+    
+class Title(Paragraph):
+    """ title element """
+
+    parentclass = Rest
+    belowchar = "="
+    abovechar = ""
+    
+    def text(self):
+        txt = self._get_text()
+        lines = []
+        if self.abovechar:
+            lines.append(self.abovechar * len(txt))
+        lines.append(txt)
+        if self.belowchar:
+            lines.append(self.belowchar * len(txt))
+        return "\n".join(lines)
+
+    def _get_text(self):
+        txt = []