Full Code of afiniate/seresye for AI

master fd4a0713402a cached
63 files
238.8 KB
70.4k tokens
10 symbols
1 requests
Download .txt
Showing preview only (256K chars total). Download the full file or copy to clipboard to get everything.
Repository: afiniate/seresye
Branch: master
Commit: fd4a0713402a
Files: 63
Total size: 238.8 KB

Directory structure:
gitextract_cfewqrrs/

├── .gitignore
├── LICENSE.md
├── README.md
├── do-gh-pages
├── doc/
│   ├── CNAME
│   ├── _layouts/
│   │   └── default.html
│   ├── assets/
│   │   ├── css/
│   │   │   ├── code.css
│   │   │   ├── prettify.css
│   │   │   ├── skeleton/
│   │   │   │   ├── 404.html
│   │   │   │   ├── index.html
│   │   │   │   ├── javascripts/
│   │   │   │   │   └── tabs.js
│   │   │   │   ├── robots.txt
│   │   │   │   └── stylesheets/
│   │   │   │       ├── base.css
│   │   │   │       ├── layout.css
│   │   │   │       └── skeleton.css
│   │   │   └── style.css
│   │   └── javascript/
│   │       ├── html5.js
│   │       ├── lang-apollo.js
│   │       ├── lang-clj.js
│   │       ├── lang-css.js
│   │       ├── lang-go.js
│   │       ├── lang-hs.js
│   │       ├── lang-lisp.js
│   │       ├── lang-lua.js
│   │       ├── lang-ml.js
│   │       ├── lang-n.js
│   │       ├── lang-proto.js
│   │       ├── lang-scala.js
│   │       ├── lang-sql.js
│   │       ├── lang-tex.js
│   │       ├── lang-vb.js
│   │       ├── lang-vhdl.js
│   │       ├── lang-wiki.js
│   │       ├── lang-xq.js
│   │       ├── lang-yaml.js
│   │       └── prettify.js
│   └── index.md
├── examples/
│   ├── seresye_phil.erl
│   ├── seresye_prodcons.erl
│   └── seresyee_auto.erl
├── features/
│   ├── seresyet_12.feature
│   └── seresyet_13.feature
├── include/
│   └── seresye.hrl
├── rebar.config
├── sinan.config
├── src/
│   ├── internal.hrl
│   ├── seresye.app.src
│   ├── seresye.erl
│   ├── seresye_agenda.erl
│   ├── seresye_app.erl
│   ├── seresye_autoneg.erl
│   ├── seresye_engine.erl
│   ├── seresye_speedtest.erl
│   ├── seresye_sup.erl
│   ├── seresye_transform.erl
│   └── seresye_tree_list.erl
└── test/
    ├── seresyet_12.erl
    ├── seresyet_13.erl
    ├── seresyet_cannibals.erl
    ├── seresyet_relatives.erl
    ├── seresyet_sample.erl
    ├── seresyet_sieve.erl
    └── seresyet_simple_relatives.erl

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
_build
erl_crash.dump
doc/_site
deps
ebin


================================================
FILE: LICENSE.md
================================================
BSD License
===========

Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.
* Neither the name of Francesca Gangemi, Corrado Santoro may be used
  to endorse or promote products derived from this software without
  specific prior written permission.


THIS SOFTWARE IS PROVIDED BY Francesca Gangemi AND Corrado Santoro ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.


================================================
FILE: README.md
================================================
SERESYE - Swarm oriented ERlang Expert SYstem Engine
====================================================

Introduction
------------

SERESYE is a Rete based rules engine written in Erlang, descended
directly from the Eresye project by Francesca Gangemi and Corrado
Santoro. In the following article we will describe how to use the
system.

As it is widely known, a rule-based system is composed by a
**knowledge base**, which stores a set of *facts* representing the
'universe of discourse' of a given application, and a set of
**production rules**, which are used to infer knowledge and/or reason
about the knowledge. A rule is activated when one or more facts match
the template(s) given in the rule declaration: in such a case, the
body of the rule contains a code that is thus executed

In SERESYE, *facts* are expressed by means of Erlang tuples or records,
while rules are written using standard Erlang function clauses, whose
declaration reports, in the clause head, the facts or fact templates
that have to be matched for the rule to be activated and executed.

For more information about SERESYE please refer to the paper docs directory.

For more information about rule-based inference engines and expert
systems, you can refer to the book: *S. Russell and
P. Norvig. **Artificial Intelligence: A Modern Approach/2E.** Prentice
Hall, 2003.*

To write an AI application with SERESYE the following steps have to be
performed:

1. Indentify your universe of discourse and determine the facts that
   have to be used to represent such a world;

2. Indentify the rules that you need and write them by using, e.g.
   first-order-logic predicates or even natural language;

3. Implement the system by writing your rules as Erlang function
   clauses, according to the modality required by SERESYE.


The Application: the Domain of Relatives
----------------------------------------

We will design a system able to derive new knowledge using some
inference rules and starting from a small set; as a sample
application, we chose the domain of relatives: we will start from some
base concepts, such as *parent*, *male* and *female*, and then, by
means of a proper set of rules, we will derive the concepts of
*mother*, *father*, *sister*, *brother*, *grandmother* and
*grandfather*.

According to the list above, we will first derive the facts that will be
used to represent our concepts. Given the set of relationships above, they
will be represented by means of the following facts:

<table border="1" align="center">
<thead>
  <tr>
    <td>#</td>
    <td>Concept</td>
    <td>Fact / Erlang tuple</td>
  </tr>
</thead>
<tbody>
  <tr>
    <td>1</td>
    <td>X is male</td>
    <td><tt>{male, X}</tt></td>
  </tr>
  <tr>
    <td>2</td>
    <td>X is female</td>
    <td><tt>{female, X}</tt></td>
  </tr>
  <tr>
    <td>3</td>
    <td>X is Y's parent</td>
    <td><tt>{parent, X, Y}</tt></td>
  </tr>
  <tr>
    <td>4</td>
    <td>X is Y's mother</td>
    <td><tt>{mother, X, Y}</tt></td>
  </tr>
  <tr>
    <td>5</td>
    <td>X is Y's father</td>
    <td><tt>{father, X, Y}</tt></td>
  </tr>
  <tr>
    <td>6</td>
    <td>X is Y's sister</td>
    <td><tt>{sister, X, Y}</tt></td>
  </tr>
  <tr>
    <td>7</td>
    <td>X is Y's brother</td>
    <td><tt>{brother, X, Y}</tt></td>
  </tr>
  <tr>
    <td>8</td>
    <td>X is Y's grandmother</td>
    <td><tt>{grandmother, X, Y}</tt></td>
  </tr>
  <tr>
    <td>9</td>
    <td>X is Y's grandfather</td>
    <td><tt>{grandfather, X, Y}</tt></td>
  </tr>
</tbody>
</table>

Concepts 1, 2 and 3 will be used as a base to derive the other ones.

Deriving new concepts by means of rules
---------------------------------------

#### Concept: mother

The rule to derive the concept of mother is quite
straightforward:

    if X is female and X is Y's parent then X is Y's mother.

From the point of view of SERESYE, since knowledge is stored in the
*knowledge base* of the engine, the rule above is translated into the
following one: *if the facts {female, X} and {parent, X, Y} are
*asserted* in the knowledge base, then we assert the fact {mother, X,
Y}.

The rule *mother* can be thus written as follows:

    %%
    %% if (X is female) and (X is Y's parent) then (X is Y's mother)
    %%
    mother (Engine, {female, X}, {parent, X, Y}) ->
      seresye:assert (Engine, {mother, X, Y}).


#### Concept: father

This concept can be easily derived by means of the following rule:

    %%
    %% if (X is male) and (X is Y's parent) then (X is Y's father)
    %%
    father (Engine, {male, X}, {parent, X, Y}) ->
      seresye:assert (Engine, {father, X, Y}).


#### Concept: sister

 This concept can be expressed by the following rule:

    if Y and Z have the same parent and Z is female, then Z
    is the Y's sister.

The SERESYE rule used to map this concept is:

    %%
    %% if (Y and Z have the same parent X) and (Z is female)
    %%    then (Z is Y's sister)
    %%
    sister (Engine, {parent, X, Y}, {parent, X, Z}, {female, Z}) when Y =/= Z ->
      seresye:assert (Engine, {sister, Z, Y}).


Please note the guard, which is needed to ensure that when Y and Z are
bound to the same value, the rule is not activated (indeed this is
possible since the same fact can match both the first and second
'parent' pattern).

#### Concept: brother

Given the previous one, this concept is now quite simple to
implement:


    %%
    %% if (Y and Z have the same parent X) and (Z is male)
    %%    then (Z is Y's brother)
    %%
    brother (Engine, {parent, X, Y}, {parent, X, Z}, {male, Z}) when Y =/= Z ->
      seresye:assert (Engine, {brother, Z, Y}).


#### Concepts: grandmother and grandfather

The former concept can be expressed by means of the rule:

    if X is Y's mother and Y is Z's parent, then X is Z's
    grandmother.</u>* The latter concept is now obvious.

Both can be implemented using the following SERESYE rules:

    %%
    %% if (X is Y's mother) and (Y is Z's parent)
    %%    then (X is Z's grandmother)
    %%
    grandmother (Engine, {mother, X, Y}, {parent, Y, Z}) ->
      seresye:assert (Engine, {grandmother, X, Z}).

    %%
    %% if (X is Y's father) and (Y is Z's parent)
    %%    then (X is Z's grandfather)
    %%
    grandfather (Engine, {father, X, Y}, {parent, Y, Z}) ->
      seresye:assert (Engine, {grandfather, X, Z}).


Instantiating the Engine and Populating the Knowledge Base
----------------------------------------------------------

After writing the rules, we need to:

- define the rules to seresye
- instantiate the engine;
- populate the knowledge base with a set of initial facts.

We define the rules to SERESYE by defined a 'rules' attribute at the
start of the module.

    %%%
    %%% relatives.erl
    %%%
    -module (relatives).

    -export([father/3, grandfather/3, grandmother/3,
             mother/3, brother/4, sister/4, start/0]).

    -rules([mother, father, brother, sister, grandfather,
            grandmother]).

We continue on to instantiate the engine and popoulate the knowledge
base in the function *start* below:

    start () ->
      application:start(seresye) % Only if it is not already started
      seresye:start(relatives),
      seresye:add_rules(relatives, ?MODULE)

      seresye:assert(relatives,
                     [{male, bob}, {male, corrado}, {male, mark}, {male, caesar},
                      {female, alice}, {female, sara}, {female, jane}, {female, anna},
                      {parent, jane, bob}, {parent, corrado, bob},
                      {parent, jane, mark}, {parent, corrado, mark},
                      {parent, jane, alice}, {parent, corrado, alice},
                      {parent, bob, caesar}, {parent, bob, anna},
                      {parent, sara, casear}, {parent, sara, anna}]),
      ok.

As the listing reports, creating a new SERESYE engine implies to call
the function *seresye:start/1*, giving the name of the engine to be
created

Then, we have to add the rules to the engine by using the function
*seresye:add_rule/2*: it takes two arguments, the name of the engine
and a tuple representing the function in the form *{Module,
FuncName}*; obviously the function *Module:FuncName* must be
exported. Function *add_rule* has to be called for each rule that has
to be added; for this reason, the code above has an iteration over the
list of rules written before.

Finally, we populate the inference engine with a set of sample facts
by giving them, in a list, to the function *seresye:assert/2*.  To test
our rules, we considered the relationships in the Figure below and
assert only the facts for *male*, *female* and *parent*.

Testing the application
-----------------------

The final complete code of our AI application is thus the following:


    %%%
    %%% relatives.erl
    %%%
    -module (relatives).
    -export([father/3, grandfather/3, grandmother/3,
             mother/3, brother/4, sister/4, start/0]).

    %%
    %% if (X is female) and (X is Y's parent) then (X is Y's mother)
    %%
    mother(Engine, {female, X}, {parent, X, Y}) ->
      seresye:assert(Engine, {mother, X, Y}).

    %%
    %% if (X is male) and (X is Y's parent) then (X is Y's father)
    %%
    father(Engine, {male, X}, {parent, X, Y}) ->
      seresye:assert(Engine, {father, X, Y}).

    %%
    %% if (Y and Z have the same parent X) and (Z is female)
    %%    then (Z is Y's sister)
    %%
    sister(Engine, {parent, X, Y}, {parent, X, Z}, {female, Z}) when Y =/= Z ->
      seresye:assert(Engine, {sister, Z, Y}).

    %%
    %% if (Y and Z have the same parent X) and (Z is male)
    %%    then (Z is Y's brother)
    %%
    brother(Engine, {parent, X, Y}, {parent, X, Z}, {male, Z}) when Y =/= Z ->
      seresye:assert(Engine, {brother, Z, Y}).

    %%
    %% if (X is Y's father) and (Y is Z's parent)
    %%    then (X is Z's grandfather)
    %%
    grandfather (Engine, {father, X, Y}, {parent, Y, Z}) ->
      seresye:assert (Engine, {grandfather, X, Z}).

    %%
    %% if (X is Y's mother) and (Y is Z's parent)
    %%    then (X is Z's grandmother)
    %%
    grandmother(Engine, {mother, X, Y}, {parent, Y, Z}) ->
      seresye:assert(Engine, {grandmother, X, Z}).

    start () ->
      application:start(seresye),
      seresye:start (relatives),
      seresye:add_rules(relatives, ?MODULE)

      seresye:assert (relatives,
                     [{male, bob},
                      {male, corrado},
                      {male, mark},
                      {male, caesar},
                      {female, alice},
                      {female, sara},
                      {female, jane},
                      {female, anna},
                      {parent, jane, bob},
                      {parent, corrado, bob},
                      {parent, jane, mark},
                      {parent, corrado, mark},
                      {parent, jane, alice},
                      {parent, corrado, alice},
                      {parent, bob, caesar},
                      {parent, bob, anna},
                      {parent, sara, casear},
                      {parent, sara, anna}]),
      ok.

Now it's time to test our application:


    Erlang (BEAM) emulator version 5.5 [source] [async-threads:0] [hipe]

    Eshell V5.5  (abort with ^G)
    1> c(relatives).
    {ok,relatives}
    2> relatives:start().
    ok
    3>

Following the call to function *relatives:start/0*, the engine is
created and populated; if no errors occurred, the rules should have
been processed and the new facts derived. To check this, we can use
the function *seresye:get_kb/1*, which returns the list of facts
asserted into the knowledge base of a given engine:


    4> seresye:get_kb(relatives).
    [{brother,bob,mark},
     {sister,alice,bob},
     {sister,alice,mark},
     {brother,bob,alice},
     {brother,mark,alice},
     {grandmother,jane,caesar},
     {grandfather,corrado,caesar},
     {grandmother,jane,anna},
     {grandfather,corrado,anna},
     {sister,anna,caesar},
     {brother,caesar,anna},
     {sister,anna,casear},
     {mother,sara,anna},
     {mother,sara,casear},
     {parent,sara,anna},
     {father,bob,anna},
     {parent,sara,casear},
     {father,bob,caesar},
     {parent,bob,anna},
     {father,corrado,alice},
     {parent,bob,caesar},
     {mother,jane,alice},
     {parent,corrado,alice},
     {father,corrado,mark},
     {parent,jane,alice},
     {mother,jane,mark},
     {parent,corrado|...},
     {brother|...},
     {...}|...]
    5>

The presence of facts representing concepts like *father*, *sister*,
etc., proves that the rules seems to be working as expected.

We can however query the knowledge base using specific fact templates.
For example, if we want to know who are Alice's brothers, we can use
the function *seresye:query_kb/2* as follows:


    6> seresye:query_kb(relatives, {brother, '_', alice}).
    [{brother,bob,alice},{brother,mark,alice}]
    7>

The facts returned conform to the relationships depicted in the figure
above, thus proving that the rules written are really working.

As the example shows, function *seresye:query_kb/2* takes the engine
name as the first argument, while, for the second parameter, a tuple
has to be specified, representing the fact template to be matched; in
such a tuple, the atom *'_'* plays the role of a wildcard. However, to
specify a more complex matching, a *fun* can be used as a tuple
element; this *fun* has to return a boolean value which indicates if
the element matches the template. For example, to select both Alice's
and Anna's brothers, we can use the following function call:


    7> seresye:query_kb(relatives, {brother, '_', fun (X) -> (X == alice) or (X == anna) end}).
    [{brother,bob,alice},{brother,mark,alice},{brother,caesar,anna}]
    8>


Conclusions
-----------

This HowTo not only shows how to use the SERESYE engine to write an AI
application, but also highlights the versatility of the Erlang language:
the characteristics of functional and symbolic programming, together with
the possibility of performing *introspection* of function declaration,
can be successfully exploited for application domains which are completely
new for Erlang but can surely be very interesting.


================================================
FILE: do-gh-pages
================================================
#!/bin/sh

PARENT_SHA=$(git show-ref -s refs/heads/gh-pages)
DOC_SHA=$(git ls-tree -d HEAD doc | awk '{print $3}')
NEW_COMMIT=$(echo "Auto-update docs." | git commit-tree $DOC_SHA -p $PARENT_SHA)
git update-ref refs/heads/gh-pages $NEW_COMMIT


================================================
FILE: doc/CNAME
================================================
seresye.org

================================================
FILE: doc/_layouts/default.html
================================================
<!DOCTYPE html>
<html lang='en'>
  <head>
    <title>{{ page.title }}</title>
    <meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
    <!--[if lt IE 9]><script type='text/javascript' src='assets/javascript/html5.js'></script><![endif]-->
    <script type='text/javascript' src='assets/javascript/prettify.js'></script>
    <link rel='stylesheet' type='text/css' href='assets/css/skeleton/stylesheets/base.css' />x
    <link rel='stylesheet' type='text/css' href='assets/css/skeleton/stylesheets/skeleton.css' />
    <link rel='stylesheet' type='text/css' href='assets/css/prettify.css' />
    <link rel='stylesheet' type='text/css' href='assets/css/style.css' />
    <link rel='stylesheet' type='text/css' href='assets/css/code.css' />
  </head>

  <body onload='prettyPrint()'>
    <div class='container'>
      <header class='sixteen columns'>
        <div class='nine columns alpha'>
          <h1>SERESYE - {{ page.title }}</h1>
        </div>

        <div class='six columns offset-by-one omega'>
          <a href='https://github.com/downloads/afiniate/seresye'
             class='download-button'>
            Download
            <span>Latest version from GitHub</span>
          </a>
        </div>
      </header>

      <div class="menu sixteen columns">
        <ul>
          <li><a href="/seresye/">Home</a></li>
          <li><a href="/seresye/Domain_Of_Relatives_Example.pdf">
              Domain of Relatives Example (out of date)</a></li>
          <li><a href="/seresye/Eresye_Paper.pdf">
              Eresye Paper (out of date)</a></li>
        </ul>
        <br style="clear:left"/>
      </div>

      <div class='sixteen columns'>

        {{content}}

      </div>

      <div class='sixteen columns'>


      </div>
    </div>

    <footer>
      <div class='container'>
        <div class='ten columns offset-by-three repo-author'>
          <img src='http://www.afiniate.com/uploads/9/1/6/3/9163759/3030558.png?364'
               class='repo-author-logo' />
          <a href="http://www.twitter.com/afiniate">
            <img src="http://twitter-badges.s3.amazonaws.com/twitter-a.png"
                 alt="Follow Afiniate on Twitter"/>
          </a>
          <p>
            Afiniate has proven expertise in delivering innovative,
            mission-critical enterprise solutions, including
            large-scale distributed systems to Fortune 500 companies
            like Amazon.com and leading edge high-frequency trading
            systems to private brokerages like PEAK6 Investments.

            We are focused on applying that expertise in developing
            intelligence and analytic systems for the banking
            industry, and using that technology to help already
            successful financial institutions to fully leverage their
            valuable, but underutilized, data in ways that drive
            increased revenue, improved operational efficiencies,
            insight-based decision making, and enhanced customer
            satisfaction.
          </p>
        </div>

        <div class='sixteen columns credits'>
          <p>GitHub release template built with HTML5, CSS3 and JS
            by <a href='http://fublo.net'>Fublo</a></p>
        </div>
      </div>
    </footer>

    <a href='https://github.com/afiniate/seresye'
       class='github-ribbon'><img src='assets/images/github-ribbons/red.png'
                                  /></a>
  </body>
</html>


================================================
FILE: doc/assets/css/code.css
================================================
.highlight .hll { background-color: #ffffcc }
.highlight  { background: #ffffff; }
.highlight .c { color: #999988; font-style: italic } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { font-weight: bold } /* Keyword */
.highlight .o { font-weight: bold } /* Operator */
.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #999999 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { font-weight: bold } /* Keyword.Constant */
.highlight .kd { font-weight: bold } /* Keyword.Declaration */
.highlight .kn { font-weight: bold } /* Keyword.Namespace */
.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
.highlight .kr { font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #009999 } /* Literal.Number */
.highlight .s { color: #bb8844 } /* Literal.String */
.highlight .na { color: #008080 } /* Name.Attribute */
.highlight .nb { color: #999999 } /* Name.Builtin */
.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
.highlight .no { color: #008080 } /* Name.Constant */
.highlight .ni { color: #800080 } /* Name.Entity */
.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
.highlight .nn { color: #555555 } /* Name.Namespace */
.highlight .nt { color: #000080 } /* Name.Tag */
.highlight .nv { color: #008080 } /* Name.Variable */
.highlight .ow { font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mf { color: #009999 } /* Literal.Number.Float */
.highlight .mh { color: #009999 } /* Literal.Number.Hex */
.highlight .mi { color: #009999 } /* Literal.Number.Integer */
.highlight .mo { color: #009999 } /* Literal.Number.Oct */
.highlight .sb { color: #bb8844 } /* Literal.String.Backtick */
.highlight .sc { color: #bb8844 } /* Literal.String.Char */
.highlight .sd { color: #bb8844 } /* Literal.String.Doc */
.highlight .s2 { color: #bb8844 } /* Literal.String.Double */
.highlight .se { color: #bb8844 } /* Literal.String.Escape */
.highlight .sh { color: #bb8844 } /* Literal.String.Heredoc */
.highlight .si { color: #bb8844 } /* Literal.String.Interpol */
.highlight .sx { color: #bb8844 } /* Literal.String.Other */
.highlight .sr { color: #808000 } /* Literal.String.Regex */
.highlight .s1 { color: #bb8844 } /* Literal.String.Single */
.highlight .ss { color: #bb8844 } /* Literal.String.Symbol */
.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #008080 } /* Name.Variable.Class */
.highlight .vg { color: #008080 } /* Name.Variable.Global */
.highlight .vi { color: #008080 } /* Name.Variable.Instance */
.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */


================================================
FILE: doc/assets/css/prettify.css
================================================
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}

================================================
FILE: doc/assets/css/skeleton/404.html
================================================
<!DOCTYPE html>
<!--[if lt IE 7 ]><html class="ie ie6" lang="en"> <![endif]-->
<!--[if IE 7 ]><html class="ie ie7" lang="en"> <![endif]-->
<!--[if IE 8 ]><html class="ie ie8" lang="en"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!--><html lang="en"> <!--<![endif]-->
<head>

	<!-- Basic Page Needs
  ================================================== -->
	<meta charset="utf-8">
	<title>Your Page Title Here :)</title>
	<meta name="description" content="">
	<meta name="author" content="">
	<!--[if lt IE 9]>
		<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
	<![endif]-->

	<!-- Mobile Specific Metas
  ================================================== -->
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

	<!-- CSS
  ================================================== -->
	<link rel="stylesheet" href="stylesheets/base.css">
	<link rel="stylesheet" href="stylesheets/skeleton.css">
	<link rel="stylesheet" href="stylesheets/layout.css">

	<!-- Favicons
	================================================== -->
	<link rel="shortcut icon" href="images/favicon.ico">
	<link rel="apple-touch-icon" href="images/apple-touch-icon.png">
	<link rel="apple-touch-icon" sizes="72x72" href="images/apple-touch-icon-72x72.png">
	<link rel="apple-touch-icon" sizes="114x114" href="images/apple-touch-icon-114x114.png">

</head>
<body>

	<!-- Primary Page Layout
	================================================== -->
	<div class="container">
		<h1 style="margin-top: 100px; text-align:center">Sorry. Couldn't Find That Page!</h1>
	</div>

<!-- End Document
================================================== -->
</body>
</html>

================================================
FILE: doc/assets/css/skeleton/index.html
================================================
<!DOCTYPE html>
<!--[if lt IE 7 ]><html class="ie ie6" lang="en"> <![endif]-->
<!--[if IE 7 ]><html class="ie ie7" lang="en"> <![endif]-->
<!--[if IE 8 ]><html class="ie ie8" lang="en"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!--><html lang="en"> <!--<![endif]-->
<head>

	<!-- Basic Page Needs
  ================================================== -->
	<meta charset="utf-8">
	<title>Your Page Title Here :)</title>
	<meta name="description" content="">
	<meta name="author" content="">
	<!--[if lt IE 9]>
		<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
	<![endif]-->

	<!-- Mobile Specific Metas
  ================================================== -->
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

	<!-- CSS
  ================================================== -->
	<link rel="stylesheet" href="stylesheets/base.css">
	<link rel="stylesheet" href="stylesheets/skeleton.css">
	<link rel="stylesheet" href="stylesheets/layout.css">

	<!-- Favicons
	================================================== -->
	<link rel="shortcut icon" href="images/favicon.ico">
	<link rel="apple-touch-icon" href="images/apple-touch-icon.png">
	<link rel="apple-touch-icon" sizes="72x72" href="images/apple-touch-icon-72x72.png">
	<link rel="apple-touch-icon" sizes="114x114" href="images/apple-touch-icon-114x114.png">

</head>
<body>



	<!-- Primary Page Layout
	================================================== -->

	<!-- Delete everything in this .container and get started on your own site! -->

	<div class="container">
		<div class="sixteen columns">
			<h1 class="remove-bottom" style="margin-top: 40px">Skeleton</h1>
			<h5>Version 1.1</h5>
			<hr />
		</div>
		<div class="one-third column">
			<h3>About Skeleton?</h3>
			<p>Skeleton is a small collection of well-organized CSS &amp; JS files that can help you rapidly develop sites that look beautiful at any size, be it a 17" laptop screen or an iPhone. It's based on a responsive grid, but also provides very basic CSS for typography, buttons, tabs, forms and media queries. Go ahead, resize this super basic page to see the grid in action.</p>
		</div>
		<div class="one-third column">
			<h3>Three Core Principles</h3>
			<p>Skeleton is built on three core principles:</p>
			<ul class="square">
				<li><strong>A Responsive Grid Down To Mobile</strong>: Elegant scaling from a browser to tablets to mobile.</li>
				<li><strong>Fast to Start</strong>: It's a tool for rapid development with best practices</li>
				<li><strong>Style Agnostic</strong>: It provides the most basic, beautiful styles, but is meant to be overwritten.</li>
			</ul>
		</div>
		<div class="one-third column">
			<h3>Docs &amp; Support</h3>
			<p>The easiest way to really get started with Skeleton is to check out the full docs and info at <a href="http://www.getskeleton.com">www.getskeleton.com.</a>. Skeleton is also open-source and has a <a href="https://github.com/dhgamache/skeleton">project on git</a>, so check that out if you want to report bugs or create a pull request. If you have any questions, thoughts, concerns or feedback, please don't hesitate to email me at <a href="mailto:hi@getskeleton.com">hi@getskeleton.com</a>.</p>
		</div>

	</div><!-- container -->



	<!-- JS
	================================================== -->
	<script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
	<script src="javascripts/tabs.js"></script>

<!-- End Document
================================================== -->
</body>
</html>

================================================
FILE: doc/assets/css/skeleton/javascripts/tabs.js
================================================
/*
* Skeleton V1.1
* Copyright 2011, Dave Gamache
* www.getskeleton.com
* Free to use under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
* 8/17/2011
*/


$(document).ready(function() {

	/* Tabs Activiation
	================================================== */

	var tabs = $('ul.tabs');

	tabs.each(function(i) {

		//Get all tabs
		var tab = $(this).find('> li > a');
		tab.click(function(e) {

			//Get Location of tab's content
			var contentLocation = $(this).attr('href');

			//Let go if not a hashed one
			if(contentLocation.charAt(0)=="#") {

				e.preventDefault();

				//Make Tab Active
				tab.removeClass('active');
				$(this).addClass('active');

				//Show Tab Content & add active class
				$(contentLocation).show().addClass('active').siblings().hide().removeClass('active');

			}
		});
	});
});

================================================
FILE: doc/assets/css/skeleton/robots.txt
================================================
# www.robotstxt.org/
# www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449

User-agent: *



================================================
FILE: doc/assets/css/skeleton/stylesheets/base.css
================================================
/*
* Skeleton V1.1
* Copyright 2011, Dave Gamache
* www.getskeleton.com
* Free to use under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
* 8/17/2011
*/


/* Table of Content
==================================================
	#Reset & Basics
	#Basic Styles
	#Site Styles
	#Typography
	#Links
	#Lists
	#Images
	#Buttons
	#Tabs
	#Forms
	#Misc */


/* #Reset & Basics (Inspired by E. Meyers)
================================================== */
	html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
		margin: 0;
		padding: 0;
		border: 0;
		font-size: 100%;
		font: inherit;
		vertical-align: baseline; }
	article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
		display: block; }
	body {
		line-height: 1; }
	ol, ul {
		list-style: none; }
	blockquote, q {
		quotes: none; }
	blockquote:before, blockquote:after,
	q:before, q:after {
		content: '';
		content: none; }
	table {
		border-collapse: collapse;
		border-spacing: 0; }


/* #Basic Styles
================================================== */
	body {
		background: #fff;
		font: 14px/21px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
		color: #444;
		-webkit-font-smoothing: antialiased; /* Fix for webkit rendering */
		-webkit-text-size-adjust: 100%;
 }


/* #Typography
================================================== */
	h1, h2, h3, h4, h5, h6 {
		color: #181818;
		font-family: "Georgia", "Times New Roman", Helvetica, Arial, sans-serif;
		font-weight: normal; }
	h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { font-weight: inherit; }
	h1 { font-size: 46px; line-height: 50px; margin-bottom: 14px;}
	h2 { font-size: 35px; line-height: 40px; margin-bottom: 10px; }
	h3 { font-size: 28px; line-height: 34px; margin-bottom: 8px; }
	h4 { font-size: 21px; line-height: 30px; margin-bottom: 4px; }
	h5 { font-size: 17px; line-height: 24px; }
	h6 { font-size: 14px; line-height: 21px; }
	.subheader { color: #777; }

	p { margin: 0 0 20px 0; }
	p img { margin: 0; }
	p.lead { font-size: 21px; line-height: 27px; color: #777;  }

	em { font-style: italic; }
	strong { font-weight: bold; color: #333; }
	small { font-size: 80%; }

/*	Blockquotes  */
	blockquote, blockquote p { font-size: 17px; line-height: 24px; color: #777; font-style: italic; }
	blockquote { margin: 0 0 20px; padding: 9px 20px 0 19px; border-left: 1px solid #ddd; }
	blockquote cite { display: block; font-size: 12px; color: #555; }
	blockquote cite:before { content: "\2014 \0020"; }
	blockquote cite a, blockquote cite a:visited, blockquote cite a:visited { color: #555; }

	hr { border: solid #ddd; border-width: 1px 0 0; clear: both; margin: 10px 0 30px; height: 0; }


/* #Links
================================================== */
	a, a:visited { color: #333; text-decoration: underline; outline: 0; }
	a:hover, a:focus { color: #000; }
	p a, p a:visited { line-height: inherit; }


/* #Lists
================================================== */
	ul, ol { margin-bottom: 20px; }
	ul { list-style: none outside; }
	ol { list-style: decimal; }
	ol, ul.square, ul.circle, ul.disc { margin-left: 30px; }
	ul.square { list-style: square outside; }
	ul.circle { list-style: circle outside; }
	ul.disc { list-style: disc outside; }
	ul ul, ul ol,
	ol ol, ol ul { margin: 4px 0 5px 30px; font-size: 90%;  }
	ul ul li, ul ol li,
	ol ol li, ol ul li { margin-bottom: 6px; }
	li { line-height: 18px; margin-bottom: 12px; }
	ul.large li { line-height: 21px; }
	li p { line-height: 21px; }

/* #Images
================================================== */

	img.scale-with-grid {
		max-width: 100%;
		height: auto; }


/* #Buttons
================================================== */

	a.button,
	button,
	input[type="submit"],
	input[type="reset"],
	input[type="button"] {
		background: #eee; /* Old browsers */
		background: -moz-linear-gradient(top, rgba(255,255,255,.2) 0%, rgba(0,0,0,.2) 100%); /* FF3.6+ */
		background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.2)), color-stop(100%,rgba(0,0,0,.2))); /* Chrome,Safari4+ */
		background: -webkit-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* Chrome10+,Safari5.1+ */
		background: -o-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* Opera11.10+ */
		background: -ms-linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* IE10+ */
		background: linear-gradient(top, rgba(255,255,255,.2) 0%,rgba(0,0,0,.2) 100%); /* W3C */
	  border: 1px solid #aaa;
	  border-top: 1px solid #ccc;
	  border-left: 1px solid #ccc;
	  padding: 4px 12px;
	  -moz-border-radius: 3px;
	  -webkit-border-radius: 3px;
	  border-radius: 3px;
	  color: #444;
	  display: inline-block;
	  font-size: 11px;
	  font-weight: bold;
	  text-decoration: none;
	  text-shadow: 0 1px rgba(255, 255, 255, .75);
	  cursor: pointer;
	  margin-bottom: 20px;
	  line-height: 21px;
	  font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif; }

	a.button:hover,
	button:hover,
	input[type="submit"]:hover,
	input[type="reset"]:hover,
	input[type="button"]:hover {
		color: #222;
		background: #ddd; /* Old browsers */
		background: -moz-linear-gradient(top, rgba(255,255,255,.3) 0%, rgba(0,0,0,.3) 100%); /* FF3.6+ */
		background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.3)), color-stop(100%,rgba(0,0,0,.3))); /* Chrome,Safari4+ */
		background: -webkit-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* Chrome10+,Safari5.1+ */
		background: -o-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* Opera11.10+ */
		background: -ms-linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* IE10+ */
		background: linear-gradient(top, rgba(255,255,255,.3) 0%,rgba(0,0,0,.3) 100%); /* W3C */
	  border: 1px solid #888;
	  border-top: 1px solid #aaa;
	  border-left: 1px solid #aaa; }

  a.button:active,
  button:active,
	input[type="submit"]:active,
	input[type="reset"]:active,
	input[type="button"]:active {
		border: 1px solid #666;
		background: #ccc; /* Old browsers */
		background: -moz-linear-gradient(top, rgba(255,255,255,.35) 0%, rgba(10,10,10,.4) 100%); /* FF3.6+ */
		background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,.35)), color-stop(100%,rgba(10,10,10,.4))); /* Chrome,Safari4+ */
		background: -webkit-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* Chrome10+,Safari5.1+ */
		background: -o-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* Opera11.10+ */
		background: -ms-linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* IE10+ */
		background: linear-gradient(top, rgba(255,255,255,.35) 0%,rgba(10,10,10,.4) 100%); /* W3C */ }

	.button.full-width,
	button.full-width,
	input[type="submit"].full-width,
	input[type="reset"].full-width,
	input[type="button"].full-width {
		width: 100%;
		padding-left: 0 !important;
		padding-right: 0 !important;
		text-align: center; }


/* #Tabs (activate in tabs.js)
================================================== */
	ul.tabs {
		display: block;
		margin: 0 0 20px 0;
		padding: 0;
		border-bottom: solid 1px #ddd; }
	ul.tabs li {
		display: block;
		width: auto;
		height: 30px;
		padding: 0;
		float: left;
		margin-bottom: 0; }
	ul.tabs li a {
		display: block;
		text-decoration: none;
		width: auto;
		height: 29px;
		padding: 0px 20px;
		line-height: 30px;
		border: solid 1px #ddd;
		border-width: 1px 1px 0 0;
		margin: 0;
		background: #f5f5f5;
		font-size: 13px; }
	ul.tabs li a.active {
		background: #fff;
		height: 30px;
		position: relative;
		top: -4px;
		padding-top: 4px;
		border-left-width: 1px;
		margin: 0 0 0 -1px;
		color: #111;
		-moz-border-radius-topleft: 2px;
		-webkit-border-top-left-radius: 2px;
		border-top-left-radius: 2px;
		-moz-border-radius-topright: 2px;
		-webkit-border-top-right-radius: 2px;
		border-top-right-radius: 2px; }
	ul.tabs li:first-child a.active {
		margin-left: 0; }
	ul.tabs li:first-child a {
		border-width: 1px 1px 0 1px;
		-moz-border-radius-topleft: 2px;
		-webkit-border-top-left-radius: 2px;
		border-top-left-radius: 2px; }
	ul.tabs li:last-child a {
		-moz-border-radius-topright: 2px;
		-webkit-border-top-right-radius: 2px;
		border-top-right-radius: 2px; }

	ul.tabs-content { margin: 0; display: block; }
	ul.tabs-content > li { display:none; }
	ul.tabs-content > li.active { display: block; }

	/* Clearfixing tabs for beautiful stacking */
	ul.tabs:before,
	ul.tabs:after {
	  content: '\0020';
	  display: block;
	  overflow: hidden;
	  visibility: hidden;
	  width: 0;
	  height: 0; }
	ul.tabs:after {
	  clear: both; }
	ul.tabs {
	  zoom: 1; }


/* #Forms
================================================== */

	form {
		margin-bottom: 20px; }
	fieldset {
		margin-bottom: 20px; }
	input[type="text"],
	input[type="password"],
	input[type="email"],
	textarea,
	select {
		border: 1px solid #ccc;
		padding: 6px 4px;
		outline: none;
		-moz-border-radius: 2px;
		-webkit-border-radius: 2px;
		border-radius: 2px;
		font: 13px "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
		color: #777;
		margin: 0;
		width: 210px;
		max-width: 100%;
		display: block;
		margin-bottom: 20px;
		background: #fff; }
	select {
		padding: 0; }
	input[type="text"]:focus,
	input[type="password"]:focus,
	input[type="email"]:focus,
	textarea:focus {
		border: 1px solid #aaa;
 		color: #444;
 		-moz-box-shadow: 0 0 3px rgba(0,0,0,.2);
		-webkit-box-shadow: 0 0 3px rgba(0,0,0,.2);
		box-shadow:  0 0 3px rgba(0,0,0,.2); }
	textarea {
		min-height: 60px; }
	label,
	legend {
		display: block;
		font-weight: bold;
		font-size: 13px;  }
	select {
		width: 220px; }
	input[type="checkbox"] {
		display: inline; }
	label span,
	legend span {
		font-weight: normal;
		font-size: 13px;
		color: #444; }

/* #Misc
================================================== */
	.remove-bottom { margin-bottom: 0 !important; }
	.half-bottom { margin-bottom: 10px !important; }
	.add-bottom { margin-bottom: 20px !important; }




================================================
FILE: doc/assets/css/skeleton/stylesheets/layout.css
================================================
/*
* Skeleton V1.1
* Copyright 2011, Dave Gamache
* www.getskeleton.com
* Free to use under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
* 8/17/2011
*/

/* Table of Content
==================================================
	#Site Styles
	#Page Styles
	#Media Queries
	#Font-Face */

/* #Site Styles
================================================== */

/* #Page Styles
================================================== */

/* #Media Queries
================================================== */

	/* Smaller than standard 960 (devices and browsers) */
	@media only screen and (max-width: 959px) {}

	/* Tablet Portrait size to standard 960 (devices and browsers) */
	@media only screen and (min-width: 768px) and (max-width: 959px) {}

	/* All Mobile Sizes (devices and browser) */
	@media only screen and (max-width: 767px) {}

	/* Mobile Landscape Size to Tablet Portrait (devices and browsers) */
	@media only screen and (min-width: 480px) and (max-width: 767px) {}

	/* Mobile Portrait Size to Mobile Landscape Size (devices and browsers) */
	@media only screen and (max-width: 479px) {}


/* #Font-Face
================================================== */
/* 	This is the proper syntax for an @font-face file
		Just create a "fonts" folder at the root,
		copy your FontName into code below and remove
		comment brackets */

/*	@font-face {
	    font-family: 'FontName';
	    src: url('../fonts/FontName.eot');
	    src: url('../fonts/FontName.eot?iefix') format('eot'),
	         url('../fonts/FontName.woff') format('woff'),
	         url('../fonts/FontName.ttf') format('truetype'),
	         url('../fonts/FontName.svg#webfontZam02nTh') format('svg');
	    font-weight: normal;
	    font-style: normal; }
*/

================================================
FILE: doc/assets/css/skeleton/stylesheets/skeleton.css
================================================
/*
* Skeleton V1.1
* Copyright 2011, Dave Gamache
* www.getskeleton.com
* Free to use under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
* 8/17/2011
*/


/* Table of Contents
==================================================
    #Base 960 Grid
    #Tablet (Portrait)
    #Mobile (Portrait)
    #Mobile (Landscape)
    #Clearing */



/* #Base 960 Grid
================================================== */

    .container                                  { position: relative; width: 960px; margin: 0 auto; padding: 0; }
    .column, .columns                           { float: left; display: inline; margin-left: 10px; margin-right: 10px; }
    .row                                        { margin-bottom: 20px; }

    /* Nested Column Classes */
    .column.alpha, .columns.alpha               { margin-left: 0; }
    .column.omega, .columns.omega               { margin-right: 0; }

    /* Base Grid */
    .container .one.column                      { width: 40px;  }
    .container .two.columns                     { width: 100px; }
    .container .three.columns                   { width: 160px; }
    .container .four.columns                    { width: 220px; }
    .container .five.columns                    { width: 280px; }
    .container .six.columns                     { width: 340px; }
    .container .seven.columns                   { width: 400px; }
    .container .eight.columns                   { width: 460px; }
    .container .nine.columns                    { width: 520px; }
    .container .ten.columns                     { width: 580px; }
    .container .eleven.columns                  { width: 640px; }
    .container .twelve.columns                  { width: 700px; }
    .container .thirteen.columns                { width: 760px; }
    .container .fourteen.columns                { width: 820px; }
    .container .fifteen.columns                 { width: 880px; }
    .container .sixteen.columns                 { width: 940px; }

    .container .one-third.column                { width: 300px; }
    .container .two-thirds.column               { width: 620px; }

    /* Offsets */
    .container .offset-by-one                   { padding-left: 60px;  }
    .container .offset-by-two                   { padding-left: 120px; }
    .container .offset-by-three                 { padding-left: 180px; }
    .container .offset-by-four                  { padding-left: 240px; }
    .container .offset-by-five                  { padding-left: 300px; }
    .container .offset-by-six                   { padding-left: 360px; }
    .container .offset-by-seven                 { padding-left: 420px; }
    .container .offset-by-eight                 { padding-left: 480px; }
    .container .offset-by-nine                  { padding-left: 540px; }
    .container .offset-by-ten                   { padding-left: 600px; }
    .container .offset-by-eleven                { padding-left: 660px; }
    .container .offset-by-twelve                { padding-left: 720px; }
    .container .offset-by-thirteen              { padding-left: 780px; }
    .container .offset-by-fourteen              { padding-left: 840px; }
    .container .offset-by-fifteen               { padding-left: 900px; }



/* #Tablet (Portrait)
================================================== */

    /* Note: Design for a width of 768px */

    @media only screen and (min-width: 768px) and (max-width: 959px) {
        .container                                  { width: 768px; }
        .container .column,
        .container .columns                         { margin-left: 10px; margin-right: 10px;  }
        .column.alpha, .columns.alpha               { margin-left: 0; margin-right: 10px; }
        .column.omega, .columns.omega               { margin-right: 0; margin-left: 10px; }

        .container .one.column                      { width: 28px; }
        .container .two.columns                     { width: 76px; }
        .container .three.columns                   { width: 124px; }
        .container .four.columns                    { width: 172px; }
        .container .five.columns                    { width: 220px; }
        .container .six.columns                     { width: 268px; }
        .container .seven.columns                   { width: 316px; }
        .container .eight.columns                   { width: 364px; }
        .container .nine.columns                    { width: 412px; }
        .container .ten.columns                     { width: 460px; }
        .container .eleven.columns                  { width: 508px; }
        .container .twelve.columns                  { width: 556px; }
        .container .thirteen.columns                { width: 604px; }
        .container .fourteen.columns                { width: 652px; }
        .container .fifteen.columns                 { width: 700px; }
        .container .sixteen.columns                 { width: 748px; }

        .container .one-third.column                { width: 236px; }
        .container .two-thirds.column               { width: 492px; }

        /* Offsets */
        .container .offset-by-one                   { padding-left: 48px; }
        .container .offset-by-two                   { padding-left: 96px; }
        .container .offset-by-three                 { padding-left: 144px; }
        .container .offset-by-four                  { padding-left: 192px; }
        .container .offset-by-five                  { padding-left: 240px; }
        .container .offset-by-six                   { padding-left: 288px; }
        .container .offset-by-seven                 { padding-left: 336px; }
        .container .offset-by-eight                 { padding-left: 348px; }
        .container .offset-by-nine                  { padding-left: 432px; }
        .container .offset-by-ten                   { padding-left: 480px; }
        .container .offset-by-eleven                { padding-left: 528px; }
        .container .offset-by-twelve                { padding-left: 576px; }
        .container .offset-by-thirteen              { padding-left: 624px; }
        .container .offset-by-fourteen              { padding-left: 672px; }
        .container .offset-by-fifteen               { padding-left: 720px; }
    }


/*  #Mobile (Portrait)
================================================== */

    /* Note: Design for a width of 320px */

    @media only screen and (max-width: 767px) {
        .container { width: 300px; }
        .columns, .column { margin: 0; }

        .container .one.column,
        .container .two.columns,
        .container .three.columns,
        .container .four.columns,
        .container .five.columns,
        .container .six.columns,
        .container .seven.columns,
        .container .eight.columns,
        .container .nine.columns,
        .container .ten.columns,
        .container .eleven.columns,
        .container .twelve.columns,
        .container .thirteen.columns,
        .container .fourteen.columns,
        .container .fifteen.columns,
        .container .sixteen.columns,
        .container .one-third.column,
        .container .two-thirds.column  { width: 300px; }

        /* Offsets */
        .container .offset-by-one,
        .container .offset-by-two,
        .container .offset-by-three,
        .container .offset-by-four,
        .container .offset-by-five,
        .container .offset-by-six,
        .container .offset-by-seven,
        .container .offset-by-eight,
        .container .offset-by-nine,
        .container .offset-by-ten,
        .container .offset-by-eleven,
        .container .offset-by-twelve,
        .container .offset-by-thirteen,
        .container .offset-by-fourteen,
        .container .offset-by-fifteen { padding-left: 0; }

    }


/* #Mobile (Landscape)
================================================== */

    /* Note: Design for a width of 480px */

    @media only screen and (min-width: 480px) and (max-width: 767px) {
        .container { width: 420px; }
        .columns, .column { margin: 0; }

        .container .one.column,
        .container .two.columns,
        .container .three.columns,
        .container .four.columns,
        .container .five.columns,
        .container .six.columns,
        .container .seven.columns,
        .container .eight.columns,
        .container .nine.columns,
        .container .ten.columns,
        .container .eleven.columns,
        .container .twelve.columns,
        .container .thirteen.columns,
        .container .fourteen.columns,
        .container .fifteen.columns,
        .container .sixteen.columns,
        .container .one-third.column,
        .container .two-thirds.column { width: 420px; }
    }


/* #Clearing
================================================== */

    /* Self Clearing Goodness */
    .container:after { content: "\0020"; display: block; height: 0; clear: both; visibility: hidden; }

    /* Use clearfix class on parent to clear nested columns,
    or wrap each row of columns in a <div class="row"> */
    .clearfix:before,
    .clearfix:after,
    .row:before,
    .row:after {
      content: '\0020';
      display: block;
      overflow: hidden;
      visibility: hidden;
      width: 0;
      height: 0; }
    .row:after,
    .clearfix:after {
      clear: both; }
    .row,
    .clearfix {
      zoom: 1; }

    /* You can also use a <br class="clear" /> to clear columns */
    .clear {
      clear: both;
      display: block;
      overflow: hidden;
      visibility: hidden;
      width: 0;
      height: 0;
    }




================================================
FILE: doc/assets/css/style.css
================================================
/**
 * A clean concise theme for your GitHub projects
 *
 * Licenced under GPL v3
 * http://www.gnu.org/licenses/gpl.html
 **/

/* Page */
body {
    background: #333333 url('../images/page-background.png') repeat top left;
    font-family: arial,sans-serif;
}

/* Header */
header {
    padding-top: 50px;
    padding-bottom: 28px;
}

/* Footer */
footer {
    background-color: #FFFFFF;
    margin-top: 50px;
    -webkit-box-shadow: -10px 0 15px #000000;
    -moz-box-shadow: -10px 0 15px #000000;
    box-shadow: -10px 0 15px #000000;
}

div.credits {
    padding-top: 9px;
    margin-top: 30px;
    margin-bottom: 25px;
    border-top: 1px solid #DDD2B2;
    text-align: center;
}

footer p table {
    color: #333333;
}

div.repo-author {
    padding-top: 30px;
}

/* Text */
p, strong, li {
    color: #CCCCCC;
    font-size: 14px;
}

strong {
    font-weight: bold;
    color: #EEEEEE;
}

a {
    color: #0075B6;
    text-decoration: none;
}

a:visited {
    color: #0075B6;
}

a:hover {
    text-decoration: underline;
}

h1, h2 {
    font-family: georgia,serif;
}

h1 {
    font-style: italic;
    color: #FFFFFF;
    font-size: 50px;
    margin: 0;
}

h2 {
    color: #CCCCCC;
    font-size: 25px;
    line-height: 23px;
    padding-top: 15px;
}

h3, h4, h5 {
    color: #FFFFFF;
    font-weight: bold;
    font-family: inherit;
}


/* Useful classes and styles */
a.github-ribbon {
    position: absolute;
    top: 0;
    left: 0;
    border: 0;
}

a.download-button {
    display: block;
    padding: 15px 20px 10px 20px;
    color: #FFFFFF;
    text-decoration: none;
    font-size: 28px;
    font-weight: bold;
    background: #33A700 url('../images/github-logo.png') no-repeat 92% 50%;
    border: 2px solid #339410;
    -webkit-box-shadow: 3px 3px 5px #000000;
    -moz-box-shadow: 3px 3px 5px #000000;
    box-shadow: 3px 3px 5px #000000;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    border-radius: 5px;
    -webkit-transition: 350ms;
    -moz-transition: 350ms;
    -o-transition: 350ms;
    transition: 350ms;
}

a.download-button:hover {
    background-color: #267C00;
    background-position: 90% 50%;
}

a.download-button span {
    font-size: 14px;
    display: block;
    margin-top: 2px;
}

div.highlight {
    margin-top: 15px;
    min-height: 220px;
    border: 3px solid #FFFFFF;
    background-color: #CCCC99;
    display: block;
    padding: 20px;
    font-family: monospace;
    -webkit-box-shadow: 3px 3px 5px #000000;
    -moz-box-shadow: 3px 3px 5px #000000;
    box-shadow: 3px 3px 5px #000000;
    overflow-x: auto;
}

dl {
    margin-top: 15px;
    min-height: 220px;
    border: 3px solid #FFFFFF;
    background-color: #CCCC99;
    display: block;
    padding: 20px;
    font-family: monospace;
    -webkit-box-shadow: 3px 3px 5px #000000;
    -moz-box-shadow: 3px 3px 5px #000000;
    box-shadow: 3px 3px 5px #000000;
    overflow-x: auto;
}
dt {
    font-weight: bold
}


code {
    margin-top: 15px;
    min-height: 50px;
    border: 3px solid #FFFFFF;
    background-color: #CCCC99;
    display: block;
    padding: 20px;
    font-family: monospace;
    -webkit-box-shadow: 3px 3px 5px #000000;
    -moz-box-shadow: 3px 3px 5px #000000;
    box-shadow: 3px 3px 5px #000000;
    overflow-x: auto;
}

pre.prettyprint {
    border: 0;
    padding: 0;
    margin: 0;
}

img.repo-author-logo {
    float: left;
    margin-right: 15px;
}

.menu {
    width: 100%;
    border-bottom: 2px solid #77746C;
    border-top: 2px solid #77746C;
    margin-bottom: 28px;
}

.menu ul {
    margin: 0;
    padding: 0;
    float: left;
}

.menu ul li {
    display: inline;
}

.menu ul li a {
    float: left;
    text-decoration: none;
    color: white;
    padding: 10.5px 11px;
}

.menu ul li a:visited {
    color: white;
}

.menu ul li a:hover, .menu ul li .current {
    color: #fff;
    background-color:#0b75b2;
}

/* Media queries */
/* Hide the ribbon when we are on a phone, screen is too small */
@media only screen and (max-width: 479px) {
    a.github-ribbon {
        display: none;
    }
}


================================================
FILE: doc/assets/javascript/html5.js
================================================
// html5shiv @rem remysharp.com/html5-enabling-script
// iepp v1.6.2 @jon_neal iecss.com/print-protector
// Dual licensed under the MIT or GPL Version 2 licenses
/*@cc_on(function(a,b){function r(a){var b=-1;while(++b<f)a.createElement(e[b])}if(!(!window.attachEvent||!b.createStyleSheet||!function(){var a=document.createElement("div");a.innerHTML="<elem></elem>";return a.childNodes.length!==1}())){a.iepp=a.iepp||{};var c=a.iepp,d=c.html5elements||"abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",e=d.split("|"),f=e.length,g=new RegExp("(^|\\s)("+d+")","gi"),h=new RegExp("<(/*)("+d+")","gi"),i=/^\s*[\{\}]\s*$/,j=new RegExp("(^|[^\\n]*?\\s)("+d+")([^\\n]*)({[\\n\\w\\W]*?})","gi"),k=b.createDocumentFragment(),l=b.documentElement,m=l.firstChild,n=b.createElement("body"),o=b.createElement("style"),p=/print|all/,q;c.getCSS=function(a,b){if(a+""===undefined)return"";var d=-1,e=a.length,f,g=[];while(++d<e){f=a[d];if(f.disabled)continue;b=f.media||b,p.test(b)&&g.push(c.getCSS(f.imports,b),f.cssText),b="all"}return g.join("")},c.parseCSS=function(a){var b=[],c;while((c=j.exec(a))!=null)b.push(((i.exec(c[1])?"\n":c[1])+c[2]+c[3]).replace(g,"$1.iepp_$2")+c[4]);return b.join("\n")},c.writeHTML=function(){var a=-1;q=q||b.body;while(++a<f){var c=b.getElementsByTagName(e[a]),d=c.length,g=-1;while(++g<d)c[g].className.indexOf("iepp_")<0&&(c[g].className+=" iepp_"+e[a])}k.appendChild(q),l.appendChild(n),n.className=q.className,n.id=q.id,n.innerHTML=q.innerHTML.replace(h,"<$1font")},c._beforePrint=function(){o.styleSheet.cssText=c.parseCSS(c.getCSS(b.styleSheets,"all")),c.writeHTML()},c.restoreHTML=function(){n.innerHTML="",l.removeChild(n),l.appendChild(q)},c._afterPrint=function(){c.restoreHTML(),o.styleSheet.cssText=""},r(b),r(k);if(c.disablePP)return;m.insertBefore(o,m.firstChild),o.media="print",o.className="iepp-printshim",a.attachEvent("onbeforeprint",c._beforePrint),a.attachEvent("onafterprint",c._afterPrint)}})(this,document);@*/


================================================
FILE: doc/assets/javascript/lang-apollo.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["com",/^#[^\n\r]*/,null,"#"],["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"']],[["kwd",/^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/,
null],["typ",/^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[ES]?BANK=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[!-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["apollo","agc","aea"]);


================================================
FILE: doc/assets/javascript/lang-clj.js
================================================
/*
 Copyright (C) 2011 Google Inc.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/
var a=null;
PR.registerLangHandler(PR.createSimpleLexer([["opn",/^[([{]+/,a,"([{"],["clo",/^[)\]}]+/,a,")]}"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:def|if|do|let|quote|var|fn|loop|recur|throw|try|monitor-enter|monitor-exit|defmacro|defn|defn-|macroexpand|macroexpand-1|for|doseq|dosync|dotimes|and|or|when|not|assert|doto|proxy|defstruct|first|rest|cons|defprotocol|deftype|defrecord|reify|defmulti|defmethod|meta|with-meta|ns|in-ns|create-ns|import|intern|refer|alias|namespace|resolve|ref|deref|refset|new|set!|memfn|to-array|into-array|aset|gen-class|reduce|map|filter|find|nil?|empty?|hash-map|hash-set|vec|vector|seq|flatten|reverse|assoc|dissoc|list|list?|disj|get|union|difference|intersection|extend|extend-type|extend-protocol|prn)\b/,a],
["typ",/^:[\dA-Za-z-]+/]]),["clj"]);


================================================
FILE: doc/assets/javascript/lang-css.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);


================================================
FILE: doc/assets/javascript/lang-go.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \xa0"],["pln",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])+(?:'|$)|`[^`]*(?:`|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\/\*[\S\s]*?\*\/)/],["pln",/^(?:[^"'/`]|\/(?![*/]))+/]]),["go"]);


================================================
FILE: doc/assets/javascript/lang-hs.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^\n\f\r'\\]|\\[^&])'?/,null,"'"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^(?:--+[^\n\f\r]*|{-(?:[^-]|-+[^}-])*-})/],["kwd",/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^\d'A-Za-z]|$)/,
null],["pln",/^(?:[A-Z][\w']*\.)*[A-Za-z][\w']*/],["pun",/^[^\d\t-\r "'A-Za-z]+/]]),["hs"]);


================================================
FILE: doc/assets/javascript/lang-lisp.js
================================================
var a=null;
PR.registerLangHandler(PR.createSimpleLexer([["opn",/^\(+/,a,"("],["clo",/^\)+/,a,")"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \xa0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/,a],
["lit",/^[+-]?(?:[#0]x[\da-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[de][+-]?\d+)?)/i],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[_a-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/i],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["cl","el","lisp","scm"]);


================================================
FILE: doc/assets/javascript/lang-lua.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \xa0"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$))/,null,"\"'"]],[["com",/^--(?:\[(=*)\[[\S\s]*?(?:]\1]|$)|[^\n\r]*)/],["str",/^\[(=*)\[[\S\s]*?(?:]\1]|$)/],["kwd",/^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],
["pln",/^[_a-z]\w*/i],["pun",/^[^\w\t\n\r \xa0][^\w\t\n\r "'+=\xa0-]*/]]),["lua"]);


================================================
FILE: doc/assets/javascript/lang-ml.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \xa0"],["com",/^#(?:if[\t\n\r \xa0]+(?:[$_a-z][\w']*|``[^\t\n\r`]*(?:``|$))|else|endif|light)/i,null,"#"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])(?:'|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\(\*[\S\s]*?\*\))/],["kwd",/^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/],
["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^(?:[_a-z][\w']*[!#?]?|``[^\t\n\r`]*(?:``|$))/i],["pun",/^[^\w\t\n\r "'\xa0]+/]]),["fs","ml"]);


================================================
FILE: doc/assets/javascript/lang-n.js
================================================
var a=null;
PR.registerLangHandler(PR.createSimpleLexer([["str",/^(?:'(?:[^\n\r'\\]|\\.)*'|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,a,'"'],["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,a,"#"],["pln",/^\s+/,a," \r\n\t\xa0"]],[["str",/^@"(?:[^"]|"")*(?:"|$)/,a],["str",/^<#[^#>]*(?:#>|$)/,a],["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,a],["com",/^\/\/[^\n\r]*/,a],["com",/^\/\*[\S\s]*?(?:\*\/|$)/,
a],["kwd",/^(?:abstract|and|as|base|catch|class|def|delegate|enum|event|extern|false|finally|fun|implements|interface|internal|is|macro|match|matches|module|mutable|namespace|new|null|out|override|params|partial|private|protected|public|ref|sealed|static|struct|syntax|this|throw|true|try|type|typeof|using|variant|virtual|volatile|when|where|with|assert|assert2|async|break|checked|continue|do|else|ensures|for|foreach|if|late|lock|new|nolate|otherwise|regexp|repeat|requires|return|surroundwith|unchecked|unless|using|while|yield)\b/,
a],["typ",/^(?:array|bool|byte|char|decimal|double|float|int|list|long|object|sbyte|short|string|ulong|uint|ufloat|ulong|ushort|void)\b/,a],["lit",/^@[$_a-z][\w$@]*/i,a],["typ",/^@[A-Z]+[a-z][\w$@]*/,a],["pln",/^'?[$_a-z][\w$@]*/i,a],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,a,"0123456789"],["pun",/^.[^\s\w"-$'./@`]*/,a]]),["n","nemerle"]);


================================================
FILE: doc/assets/javascript/lang-proto.js
================================================
PR.registerLangHandler(PR.sourceDecorator({keywords:"bytes,default,double,enum,extend,extensions,false,group,import,max,message,option,optional,package,repeated,required,returns,rpc,service,syntax,to,true",types:/^(bool|(double|s?fixed|[su]?int)(32|64)|float|string)\b/,cStyleComments:!0}),["proto"]);


================================================
FILE: doc/assets/javascript/lang-scala.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \xa0"],["str",/^"(?:""(?:""?(?!")|[^"\\]|\\.)*"{0,3}|(?:[^\n\r"\\]|\\.)*"?)/,null,'"'],["lit",/^`(?:[^\n\r\\`]|\\.)*`?/,null,"`"],["pun",/^[!#%&(--:-@[-^{-~]+/,null,"!#%&()*+,-:;<=>?@[\\]^{|}~"]],[["str",/^'(?:[^\n\r'\\]|\\(?:'|[^\n\r']+))'/],["lit",/^'[$A-Z_a-z][\w$]*(?![\w$'])/],["kwd",/^(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|object|override|package|private|protected|requires|return|sealed|super|throw|trait|try|type|val|var|while|with|yield)\b/],
["lit",/^(?:true|false|null|this)\b/],["lit",/^(?:0(?:[0-7]+|x[\da-f]+)l?|(?:0|[1-9]\d*)(?:(?:\.\d+)?(?:e[+-]?\d+)?f?|l?)|\\.\d+(?:e[+-]?\d+)?f?)/i],["typ",/^[$_]*[A-Z][\d$A-Z_]*[a-z][\w$]*/],["pln",/^[$A-Z_a-z][\w$]*/],["com",/^\/(?:\/.*|\*(?:\/|\**[^*/])*(?:\*+\/?)?)/],["pun",/^(?:\.+|\/)/]]),["scala"]);


================================================
FILE: doc/assets/javascript/lang-sql.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \xa0"],["str",/^(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,null,"\"'"]],[["com",/^(?:--[^\n\r]*|\/\*[\S\s]*?(?:\*\/|$))/],["kwd",/^(?:add|all|alter|and|any|as|asc|authorization|backup|begin|between|break|browse|bulk|by|cascade|case|check|checkpoint|close|clustered|coalesce|collate|column|commit|compute|constraint|contains|containstable|continue|convert|create|cross|current|current_date|current_time|current_timestamp|current_user|cursor|database|dbcc|deallocate|declare|default|delete|deny|desc|disk|distinct|distributed|double|drop|dummy|dump|else|end|errlvl|escape|except|exec|execute|exists|exit|fetch|file|fillfactor|for|foreign|freetext|freetexttable|from|full|function|goto|grant|group|having|holdlock|identity|identitycol|identity_insert|if|in|index|inner|insert|intersect|into|is|join|key|kill|left|like|lineno|load|match|merge|national|nocheck|nonclustered|not|null|nullif|of|off|offsets|on|open|opendatasource|openquery|openrowset|openxml|option|or|order|outer|over|percent|plan|precision|primary|print|proc|procedure|public|raiserror|read|readtext|reconfigure|references|replication|restore|restrict|return|revoke|right|rollback|rowcount|rowguidcol|rule|save|schema|select|session_user|set|setuser|shutdown|some|statistics|system_user|table|textsize|then|to|top|tran|transaction|trigger|truncate|tsequal|union|unique|update|updatetext|use|user|using|values|varying|view|waitfor|when|where|while|with|writetext)(?=[^\w-]|$)/i,
null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^[_a-z][\w-]*/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'+\xa0-]*/]]),["sql"]);


================================================
FILE: doc/assets/javascript/lang-tex.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \xa0"],["com",/^%[^\n\r]*/,null,"%"]],[["kwd",/^\\[@-Za-z]+/],["kwd",/^\\./],["typ",/^[$&]/],["lit",/[+-]?(?:\.\d+|\d+(?:\.\d*)?)(cm|em|ex|in|pc|pt|bp|mm)/i],["pun",/^[()=[\]{}]+/]]),["latex","tex"]);


================================================
FILE: doc/assets/javascript/lang-vb.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0\u2028\u2029]+/,null,"\t\n\r \xa0

"],["str",/^(?:["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})(?:["\u201c\u201d]c|$)|["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})*(?:["\u201c\u201d]|$))/i,null,'"“”'],["com",/^['\u2018\u2019].*/,null,"'‘’"]],[["kwd",/^(?:addhandler|addressof|alias|and|andalso|ansi|as|assembly|auto|boolean|byref|byte|byval|call|case|catch|cbool|cbyte|cchar|cdate|cdbl|cdec|char|cint|class|clng|cobj|const|cshort|csng|cstr|ctype|date|decimal|declare|default|delegate|dim|directcast|do|double|each|else|elseif|end|endif|enum|erase|error|event|exit|finally|for|friend|function|get|gettype|gosub|goto|handles|if|implements|imports|in|inherits|integer|interface|is|let|lib|like|long|loop|me|mod|module|mustinherit|mustoverride|mybase|myclass|namespace|new|next|not|notinheritable|notoverridable|object|on|option|optional|or|orelse|overloads|overridable|overrides|paramarray|preserve|private|property|protected|public|raiseevent|readonly|redim|removehandler|resume|return|select|set|shadows|shared|short|single|static|step|stop|string|structure|sub|synclock|then|throw|to|try|typeof|unicode|until|variant|wend|when|while|with|withevents|writeonly|xor|endif|gosub|let|variant|wend)\b/i,
null],["com",/^rem.*/i],["lit",/^(?:true\b|false\b|nothing\b|\d+(?:e[+-]?\d+[dfr]?|[dfilrs])?|(?:&h[\da-f]+|&o[0-7]+)[ils]?|\d*\.\d+(?:e[+-]?\d+)?[dfr]?|#\s+(?:\d+[/-]\d+[/-]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:am|pm))?)?|\d+:\d+(?::\d+)?(\s*(?:am|pm))?)\s+#)/i],["pln",/^(?:(?:[a-z]|_\w)\w*|\[(?:[a-z]|_\w)\w*])/i],["pun",/^[^\w\t\n\r "'[\]\xa0\u2018\u2019\u201c\u201d\u2028\u2029]+/],["pun",/^(?:\[|])/]]),["vb","vbs"]);


================================================
FILE: doc/assets/javascript/lang-vhdl.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \xa0"]],[["str",/^(?:[box]?"(?:[^"]|"")*"|'.')/i],["com",/^--[^\n\r]*/],["kwd",/^(?:abs|access|after|alias|all|and|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|mod|nand|new|next|nor|not|null|of|on|open|or|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|rem|report|return|rol|ror|select|severity|shared|signal|sla|sll|sra|srl|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with|xnor|xor)(?=[^\w-]|$)/i,
null],["typ",/^(?:bit|bit_vector|character|boolean|integer|real|time|string|severity_level|positive|natural|signed|unsigned|line|text|std_u?logic(?:_vector)?)(?=[^\w-]|$)/i,null],["typ",/^'(?:active|ascending|base|delayed|driving|driving_value|event|high|image|instance_name|last_active|last_event|last_value|left|leftof|length|low|path_name|pos|pred|quiet|range|reverse_range|right|rightof|simple_name|stable|succ|transaction|val|value)(?=[^\w-]|$)/i,null],["lit",/^\d+(?:_\d+)*(?:#[\w.\\]+#(?:[+-]?\d+(?:_\d+)*)?|(?:\.\d+(?:_\d+)*)?(?:e[+-]?\d+(?:_\d+)*)?)/i],
["pln",/^(?:[a-z]\w*|\\[^\\]*\\)/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'\xa0-]*/]]),["vhdl","vhd"]);


================================================
FILE: doc/assets/javascript/lang-wiki.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\d\t a-gi-z\xa0]+/,null,"\t \xa0abcdefgijklmnopqrstuvwxyz0123456789"],["pun",/^[*=[\]^~]+/,null,"=*~^[]"]],[["lang-wiki.meta",/(?:^^|\r\n?|\n)(#[a-z]+)\b/],["lit",/^[A-Z][a-z][\da-z]+[A-Z][a-z][^\W_]+\b/],["lang-",/^{{{([\S\s]+?)}}}/],["lang-",/^`([^\n\r`]+)`/],["str",/^https?:\/\/[^\s#/?]*(?:\/[^\s#?]*)?(?:\?[^\s#]*)?(?:#\S*)?/i],["pln",/^(?:\r\n|[\S\s])[^\n\r#*=A-[^`h{~]*/]]),["wiki"]);
PR.registerLangHandler(PR.createSimpleLexer([["kwd",/^#[a-z]+/i,null,"#"]],[]),["wiki.meta"]);


================================================
FILE: doc/assets/javascript/lang-xq.js
================================================
PR.registerLangHandler(PR.createSimpleLexer([["var pln",/^\$[\w-]+/,null,"$"]],[["pln",/^[\s=][<>][\s=]/],["lit",/^@[\w-]+/],["tag",/^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["com",/^\(:[\S\s]*?:\)/],["pln",/^[(),/;[\]{}]$/],["str",/^(?:"(?:[^"\\{]|\\[\S\s])*(?:"|$)|'(?:[^'\\{]|\\[\S\s])*(?:'|$))/,null,"\"'"],["kwd",/^(?:xquery|where|version|variable|union|typeswitch|treat|to|then|text|stable|sortby|some|self|schema|satisfies|returns|return|ref|processing-instruction|preceding-sibling|preceding|precedes|parent|only|of|node|namespace|module|let|item|intersect|instance|in|import|if|function|for|follows|following-sibling|following|external|except|every|else|element|descending|descendant-or-self|descendant|define|default|declare|comment|child|cast|case|before|attribute|assert|ascending|as|ancestor-or-self|ancestor|after|eq|order|by|or|and|schema-element|document-node|node|at)\b/],
["typ",/^(?:xs:yearMonthDuration|xs:unsignedLong|xs:time|xs:string|xs:short|xs:QName|xs:Name|xs:long|xs:integer|xs:int|xs:gYearMonth|xs:gYear|xs:gMonthDay|xs:gDay|xs:float|xs:duration|xs:double|xs:decimal|xs:dayTimeDuration|xs:dateTime|xs:date|xs:byte|xs:boolean|xs:anyURI|xf:yearMonthDuration)\b/,null],["fun pln",/^(?:xp:dereference|xinc:node-expand|xinc:link-references|xinc:link-expand|xhtml:restructure|xhtml:clean|xhtml:add-lists|xdmp:zip-manifest|xdmp:zip-get|xdmp:zip-create|xdmp:xquery-version|xdmp:word-convert|xdmp:with-namespaces|xdmp:version|xdmp:value|xdmp:user-roles|xdmp:user-last-login|xdmp:user|xdmp:url-encode|xdmp:url-decode|xdmp:uri-is-file|xdmp:uri-format|xdmp:uri-content-type|xdmp:unquote|xdmp:unpath|xdmp:triggers-database|xdmp:trace|xdmp:to-json|xdmp:tidy|xdmp:subbinary|xdmp:strftime|xdmp:spawn-in|xdmp:spawn|xdmp:sleep|xdmp:shutdown|xdmp:set-session-field|xdmp:set-response-encoding|xdmp:set-response-content-type|xdmp:set-response-code|xdmp:set-request-time-limit|xdmp:set|xdmp:servers|xdmp:server-status|xdmp:server-name|xdmp:server|xdmp:security-database|xdmp:security-assert|xdmp:schema-database|xdmp:save|xdmp:role-roles|xdmp:role|xdmp:rethrow|xdmp:restart|xdmp:request-timestamp|xdmp:request-status|xdmp:request-cancel|xdmp:request|xdmp:redirect-response|xdmp:random|xdmp:quote|xdmp:query-trace|xdmp:query-meters|xdmp:product-edition|xdmp:privilege-roles|xdmp:privilege|xdmp:pretty-print|xdmp:powerpoint-convert|xdmp:platform|xdmp:permission|xdmp:pdf-convert|xdmp:path|xdmp:octal-to-integer|xdmp:node-uri|xdmp:node-replace|xdmp:node-kind|xdmp:node-insert-child|xdmp:node-insert-before|xdmp:node-insert-after|xdmp:node-delete|xdmp:node-database|xdmp:mul64|xdmp:modules-root|xdmp:modules-database|xdmp:merging|xdmp:merge-cancel|xdmp:merge|xdmp:md5|xdmp:logout|xdmp:login|xdmp:log-level|xdmp:log|xdmp:lock-release|xdmp:lock-acquire|xdmp:load|xdmp:invoke-in|xdmp:invoke|xdmp:integer-to-octal|xdmp:integer-to-hex|xdmp:http-put|xdmp:http-post|xdmp:http-options|xdmp:http-head|xdmp:http-get|xdmp:http-delete|xdmp:hosts|xdmp:host-status|xdmp:host-name|xdmp:host|xdmp:hex-to-integer|xdmp:hash64|xdmp:hash32|xdmp:has-privilege|xdmp:groups|xdmp:group-serves|xdmp:group-servers|xdmp:group-name|xdmp:group-hosts|xdmp:group|xdmp:get-session-field-names|xdmp:get-session-field|xdmp:get-response-encoding|xdmp:get-response-code|xdmp:get-request-username|xdmp:get-request-user|xdmp:get-request-url|xdmp:get-request-protocol|xdmp:get-request-path|xdmp:get-request-method|xdmp:get-request-header-names|xdmp:get-request-header|xdmp:get-request-field-names|xdmp:get-request-field-filename|xdmp:get-request-field-content-type|xdmp:get-request-field|xdmp:get-request-client-certificate|xdmp:get-request-client-address|xdmp:get-request-body|xdmp:get-current-user|xdmp:get-current-roles|xdmp:get|xdmp:function-name|xdmp:function-module|xdmp:function|xdmp:from-json|xdmp:forests|xdmp:forest-status|xdmp:forest-restore|xdmp:forest-restart|xdmp:forest-name|xdmp:forest-delete|xdmp:forest-databases|xdmp:forest-counts|xdmp:forest-clear|xdmp:forest-backup|xdmp:forest|xdmp:filesystem-file|xdmp:filesystem-directory|xdmp:exists|xdmp:excel-convert|xdmp:eval-in|xdmp:eval|xdmp:estimate|xdmp:email|xdmp:element-content-type|xdmp:elapsed-time|xdmp:document-set-quality|xdmp:document-set-property|xdmp:document-set-properties|xdmp:document-set-permissions|xdmp:document-set-collections|xdmp:document-remove-properties|xdmp:document-remove-permissions|xdmp:document-remove-collections|xdmp:document-properties|xdmp:document-locks|xdmp:document-load|xdmp:document-insert|xdmp:document-get-quality|xdmp:document-get-properties|xdmp:document-get-permissions|xdmp:document-get-collections|xdmp:document-get|xdmp:document-forest|xdmp:document-delete|xdmp:document-add-properties|xdmp:document-add-permissions|xdmp:document-add-collections|xdmp:directory-properties|xdmp:directory-locks|xdmp:directory-delete|xdmp:directory-create|xdmp:directory|xdmp:diacritic-less|xdmp:describe|xdmp:default-permissions|xdmp:default-collections|xdmp:databases|xdmp:database-restore-validate|xdmp:database-restore-status|xdmp:database-restore-cancel|xdmp:database-restore|xdmp:database-name|xdmp:database-forests|xdmp:database-backup-validate|xdmp:database-backup-status|xdmp:database-backup-purge|xdmp:database-backup-cancel|xdmp:database-backup|xdmp:database|xdmp:collection-properties|xdmp:collection-locks|xdmp:collection-delete|xdmp:collation-canonical-uri|xdmp:castable-as|xdmp:can-grant-roles|xdmp:base64-encode|xdmp:base64-decode|xdmp:architecture|xdmp:apply|xdmp:amp-roles|xdmp:amp|xdmp:add64|xdmp:add-response-header|xdmp:access|trgr:trigger-set-recursive|trgr:trigger-set-permissions|trgr:trigger-set-name|trgr:trigger-set-module|trgr:trigger-set-event|trgr:trigger-set-description|trgr:trigger-remove-permissions|trgr:trigger-module|trgr:trigger-get-permissions|trgr:trigger-enable|trgr:trigger-disable|trgr:trigger-database-online-event|trgr:trigger-data-event|trgr:trigger-add-permissions|trgr:remove-trigger|trgr:property-content|trgr:pre-commit|trgr:post-commit|trgr:get-trigger-by-id|trgr:get-trigger|trgr:document-scope|trgr:document-content|trgr:directory-scope|trgr:create-trigger|trgr:collection-scope|trgr:any-property-content|thsr:set-entry|thsr:remove-term|thsr:remove-synonym|thsr:remove-entry|thsr:query-lookup|thsr:lookup|thsr:load|thsr:insert|thsr:expand|thsr:add-synonym|spell:suggest-detailed|spell:suggest|spell:remove-word|spell:make-dictionary|spell:load|spell:levenshtein-distance|spell:is-correct|spell:insert|spell:double-metaphone|spell:add-word|sec:users-collection|sec:user-set-roles|sec:user-set-password|sec:user-set-name|sec:user-set-description|sec:user-set-default-permissions|sec:user-set-default-collections|sec:user-remove-roles|sec:user-privileges|sec:user-get-roles|sec:user-get-description|sec:user-get-default-permissions|sec:user-get-default-collections|sec:user-doc-permissions|sec:user-doc-collections|sec:user-add-roles|sec:unprotect-collection|sec:uid-for-name|sec:set-realm|sec:security-version|sec:security-namespace|sec:security-installed|sec:security-collection|sec:roles-collection|sec:role-set-roles|sec:role-set-name|sec:role-set-description|sec:role-set-default-permissions|sec:role-set-default-collections|sec:role-remove-roles|sec:role-privileges|sec:role-get-roles|sec:role-get-description|sec:role-get-default-permissions|sec:role-get-default-collections|sec:role-doc-permissions|sec:role-doc-collections|sec:role-add-roles|sec:remove-user|sec:remove-role-from-users|sec:remove-role-from-role|sec:remove-role-from-privileges|sec:remove-role-from-amps|sec:remove-role|sec:remove-privilege|sec:remove-amp|sec:protect-collection|sec:privileges-collection|sec:privilege-set-roles|sec:privilege-set-name|sec:privilege-remove-roles|sec:privilege-get-roles|sec:privilege-add-roles|sec:priv-doc-permissions|sec:priv-doc-collections|sec:get-user-names|sec:get-unique-elem-id|sec:get-role-names|sec:get-role-ids|sec:get-privilege|sec:get-distinct-permissions|sec:get-collection|sec:get-amp|sec:create-user-with-role|sec:create-user|sec:create-role|sec:create-privilege|sec:create-amp|sec:collections-collection|sec:collection-set-permissions|sec:collection-remove-permissions|sec:collection-get-permissions|sec:collection-add-permissions|sec:check-admin|sec:amps-collection|sec:amp-set-roles|sec:amp-remove-roles|sec:amp-get-roles|sec:amp-doc-permissions|sec:amp-doc-collections|sec:amp-add-roles|search:unparse|search:suggest|search:snippet|search:search|search:resolve-nodes|search:resolve|search:remove-constraint|search:parse|search:get-default-options|search:estimate|search:check-options|prof:value|prof:reset|prof:report|prof:invoke|prof:eval|prof:enable|prof:disable|prof:allowed|ppt:clean|pki:template-set-request|pki:template-set-name|pki:template-set-key-type|pki:template-set-key-options|pki:template-set-description|pki:template-in-use|pki:template-get-version|pki:template-get-request|pki:template-get-name|pki:template-get-key-type|pki:template-get-key-options|pki:template-get-id|pki:template-get-description|pki:need-certificate|pki:is-temporary|pki:insert-trusted-certificates|pki:insert-template|pki:insert-signed-certificates|pki:insert-certificate-revocation-list|pki:get-trusted-certificate-ids|pki:get-template-ids|pki:get-template-certificate-authority|pki:get-template-by-name|pki:get-template|pki:get-pending-certificate-requests-xml|pki:get-pending-certificate-requests-pem|pki:get-pending-certificate-request|pki:get-certificates-for-template-xml|pki:get-certificates-for-template|pki:get-certificates|pki:get-certificate-xml|pki:get-certificate-pem|pki:get-certificate|pki:generate-temporary-certificate-if-necessary|pki:generate-temporary-certificate|pki:generate-template-certificate-authority|pki:generate-certificate-request|pki:delete-template|pki:delete-certificate|pki:create-template|pdf:make-toc|pdf:insert-toc-headers|pdf:get-toc|pdf:clean|p:status-transition|p:state-transition|p:remove|p:pipelines|p:insert|p:get-by-id|p:get|p:execute|p:create|p:condition|p:collection|p:action|ooxml:runs-merge|ooxml:package-uris|ooxml:package-parts-insert|ooxml:package-parts|msword:clean|mcgm:polygon|mcgm:point|mcgm:geospatial-query-from-elements|mcgm:geospatial-query|mcgm:circle|math:tanh|math:tan|math:sqrt|math:sinh|math:sin|math:pow|math:modf|math:log10|math:log|math:ldexp|math:frexp|math:fmod|math:floor|math:fabs|math:exp|math:cosh|math:cos|math:ceil|math:atan2|math:atan|math:asin|math:acos|map:put|map:map|map:keys|map:get|map:delete|map:count|map:clear|lnk:to|lnk:remove|lnk:insert|lnk:get|lnk:from|lnk:create|kml:polygon|kml:point|kml:interior-polygon|kml:geospatial-query-from-elements|kml:geospatial-query|kml:circle|kml:box|gml:polygon|gml:point|gml:interior-polygon|gml:geospatial-query-from-elements|gml:geospatial-query|gml:circle|gml:box|georss:point|georss:geospatial-query|georss:circle|geo:polygon|geo:point|geo:interior-polygon|geo:geospatial-query-from-elements|geo:geospatial-query|geo:circle|geo:box|fn:zero-or-one|fn:years-from-duration|fn:year-from-dateTime|fn:year-from-date|fn:upper-case|fn:unordered|fn:true|fn:translate|fn:trace|fn:tokenize|fn:timezone-from-time|fn:timezone-from-dateTime|fn:timezone-from-date|fn:sum|fn:subtract-dateTimes-yielding-yearMonthDuration|fn:subtract-dateTimes-yielding-dayTimeDuration|fn:substring-before|fn:substring-after|fn:substring|fn:subsequence|fn:string-to-codepoints|fn:string-pad|fn:string-length|fn:string-join|fn:string|fn:static-base-uri|fn:starts-with|fn:seconds-from-time|fn:seconds-from-duration|fn:seconds-from-dateTime|fn:round-half-to-even|fn:round|fn:root|fn:reverse|fn:resolve-uri|fn:resolve-QName|fn:replace|fn:remove|fn:QName|fn:prefix-from-QName|fn:position|fn:one-or-more|fn:number|fn:not|fn:normalize-unicode|fn:normalize-space|fn:node-name|fn:node-kind|fn:nilled|fn:namespace-uri-from-QName|fn:namespace-uri-for-prefix|fn:namespace-uri|fn:name|fn:months-from-duration|fn:month-from-dateTime|fn:month-from-date|fn:minutes-from-time|fn:minutes-from-duration|fn:minutes-from-dateTime|fn:min|fn:max|fn:matches|fn:lower-case|fn:local-name-from-QName|fn:local-name|fn:last|fn:lang|fn:iri-to-uri|fn:insert-before|fn:index-of|fn:in-scope-prefixes|fn:implicit-timezone|fn:idref|fn:id|fn:hours-from-time|fn:hours-from-duration|fn:hours-from-dateTime|fn:floor|fn:false|fn:expanded-QName|fn:exists|fn:exactly-one|fn:escape-uri|fn:escape-html-uri|fn:error|fn:ends-with|fn:encode-for-uri|fn:empty|fn:document-uri|fn:doc-available|fn:doc|fn:distinct-values|fn:distinct-nodes|fn:default-collation|fn:deep-equal|fn:days-from-duration|fn:day-from-dateTime|fn:day-from-date|fn:data|fn:current-time|fn:current-dateTime|fn:current-date|fn:count|fn:contains|fn:concat|fn:compare|fn:collection|fn:codepoints-to-string|fn:codepoint-equal|fn:ceiling|fn:boolean|fn:base-uri|fn:avg|fn:adjust-time-to-timezone|fn:adjust-dateTime-to-timezone|fn:adjust-date-to-timezone|fn:abs|feed:unsubscribe|feed:subscription|feed:subscribe|feed:request|feed:item|feed:description|excel:clean|entity:enrich|dom:set-pipelines|dom:set-permissions|dom:set-name|dom:set-evaluation-context|dom:set-domain-scope|dom:set-description|dom:remove-pipeline|dom:remove-permissions|dom:remove|dom:get|dom:evaluation-context|dom:domains|dom:domain-scope|dom:create|dom:configuration-set-restart-user|dom:configuration-set-permissions|dom:configuration-set-evaluation-context|dom:configuration-set-default-domain|dom:configuration-get|dom:configuration-create|dom:collection|dom:add-pipeline|dom:add-permissions|dls:retention-rules|dls:retention-rule-remove|dls:retention-rule-insert|dls:retention-rule|dls:purge|dls:node-expand|dls:link-references|dls:link-expand|dls:documents-query|dls:document-versions-query|dls:document-version-uri|dls:document-version-query|dls:document-version-delete|dls:document-version-as-of|dls:document-version|dls:document-update|dls:document-unmanage|dls:document-set-quality|dls:document-set-property|dls:document-set-properties|dls:document-set-permissions|dls:document-set-collections|dls:document-retention-rules|dls:document-remove-properties|dls:document-remove-permissions|dls:document-remove-collections|dls:document-purge|dls:document-manage|dls:document-is-managed|dls:document-insert-and-manage|dls:document-include-query|dls:document-history|dls:document-get-permissions|dls:document-extract-part|dls:document-delete|dls:document-checkout-status|dls:document-checkout|dls:document-checkin|dls:document-add-properties|dls:document-add-permissions|dls:document-add-collections|dls:break-checkout|dls:author-query|dls:as-of-query|dbk:convert|dbg:wait|dbg:value|dbg:stopped|dbg:stop|dbg:step|dbg:status|dbg:stack|dbg:out|dbg:next|dbg:line|dbg:invoke|dbg:function|dbg:finish|dbg:expr|dbg:eval|dbg:disconnect|dbg:detach|dbg:continue|dbg:connect|dbg:clear|dbg:breakpoints|dbg:break|dbg:attached|dbg:attach|cvt:save-converted-documents|cvt:part-uri|cvt:destination-uri|cvt:basepath|cvt:basename|cts:words|cts:word-query-weight|cts:word-query-text|cts:word-query-options|cts:word-query|cts:word-match|cts:walk|cts:uris|cts:uri-match|cts:train|cts:tokenize|cts:thresholds|cts:stem|cts:similar-query-weight|cts:similar-query-nodes|cts:similar-query|cts:shortest-distance|cts:search|cts:score|cts:reverse-query-weight|cts:reverse-query-nodes|cts:reverse-query|cts:remainder|cts:registered-query-weight|cts:registered-query-options|cts:registered-query-ids|cts:registered-query|cts:register|cts:query|cts:quality|cts:properties-query-query|cts:properties-query|cts:polygon-vertices|cts:polygon|cts:point-longitude|cts:point-latitude|cts:point|cts:or-query-queries|cts:or-query|cts:not-query-weight|cts:not-query-query|cts:not-query|cts:near-query-weight|cts:near-query-queries|cts:near-query-options|cts:near-query-distance|cts:near-query|cts:highlight|cts:geospatial-co-occurrences|cts:frequency|cts:fitness|cts:field-words|cts:field-word-query-weight|cts:field-word-query-text|cts:field-word-query-options|cts:field-word-query-field-name|cts:field-word-query|cts:field-word-match|cts:entity-highlight|cts:element-words|cts:element-word-query-weight|cts:element-word-query-text|cts:element-word-query-options|cts:element-word-query-element-name|cts:element-word-query|cts:element-word-match|cts:element-values|cts:element-value-ranges|cts:element-value-query-weight|cts:element-value-query-text|cts:element-value-query-options|cts:element-value-query-element-name|cts:element-value-query|cts:element-value-match|cts:element-value-geospatial-co-occurrences|cts:element-value-co-occurrences|cts:element-range-query-weight|cts:element-range-query-value|cts:element-range-query-options|cts:element-range-query-operator|cts:element-range-query-element-name|cts:element-range-query|cts:element-query-query|cts:element-query-element-name|cts:element-query|cts:element-pair-geospatial-values|cts:element-pair-geospatial-value-match|cts:element-pair-geospatial-query-weight|cts:element-pair-geospatial-query-region|cts:element-pair-geospatial-query-options|cts:element-pair-geospatial-query-longitude-name|cts:element-pair-geospatial-query-latitude-name|cts:element-pair-geospatial-query-element-name|cts:element-pair-geospatial-query|cts:element-pair-geospatial-boxes|cts:element-geospatial-values|cts:element-geospatial-value-match|cts:element-geospatial-query-weight|cts:element-geospatial-query-region|cts:element-geospatial-query-options|cts:element-geospatial-query-element-name|cts:element-geospatial-query|cts:element-geospatial-boxes|cts:element-child-geospatial-values|cts:element-child-geospatial-value-match|cts:element-child-geospatial-query-weight|cts:element-child-geospatial-query-region|cts:element-child-geospatial-query-options|cts:element-child-geospatial-query-element-name|cts:element-child-geospatial-query-child-name|cts:element-child-geospatial-query|cts:element-child-geospatial-boxes|cts:element-attribute-words|cts:element-attribute-word-query-weight|cts:element-attribute-word-query-text|cts:element-attribute-word-query-options|cts:element-attribute-word-query-element-name|cts:element-attribute-word-query-attribute-name|cts:element-attribute-word-query|cts:element-attribute-word-match|cts:element-attribute-values|cts:element-attribute-value-ranges|cts:element-attribute-value-query-weight|cts:element-attribute-value-query-text|cts:element-attribute-value-query-options|cts:element-attribute-value-query-element-name|cts:element-attribute-value-query-attribute-name|cts:element-attribute-value-query|cts:element-attribute-value-match|cts:element-attribute-value-geospatial-co-occurrences|cts:element-attribute-value-co-occurrences|cts:element-attribute-range-query-weight|cts:element-attribute-range-query-value|cts:element-attribute-range-query-options|cts:element-attribute-range-query-operator|cts:element-attribute-range-query-element-name|cts:element-attribute-range-query-attribute-name|cts:element-attribute-range-query|cts:element-attribute-pair-geospatial-values|cts:element-attribute-pair-geospatial-value-match|cts:element-attribute-pair-geospatial-query-weight|cts:element-attribute-pair-geospatial-query-region|cts:element-attribute-pair-geospatial-query-options|cts:element-attribute-pair-geospatial-query-longitude-name|cts:element-attribute-pair-geospatial-query-latitude-name|cts:element-attribute-pair-geospatial-query-element-name|cts:element-attribute-pair-geospatial-query|cts:element-attribute-pair-geospatial-boxes|cts:document-query-uris|cts:document-query|cts:distance|cts:directory-query-uris|cts:directory-query-depth|cts:directory-query|cts:destination|cts:deregister|cts:contains|cts:confidence|cts:collections|cts:collection-query-uris|cts:collection-query|cts:collection-match|cts:classify|cts:circle-radius|cts:circle-center|cts:circle|cts:box-west|cts:box-south|cts:box-north|cts:box-east|cts:box|cts:bearing|cts:arc-intersection|cts:and-query-queries|cts:and-query-options|cts:and-query|cts:and-not-query-positive-query|cts:and-not-query-negative-query|cts:and-not-query|css:get|css:convert|cpf:success|cpf:failure|cpf:document-set-state|cpf:document-set-processing-status|cpf:document-set-last-updated|cpf:document-set-error|cpf:document-get-state|cpf:document-get-processing-status|cpf:document-get-last-updated|cpf:document-get-error|cpf:check-transition|alert:spawn-matching-actions|alert:rule-user-id-query|alert:rule-set-user-id|alert:rule-set-query|alert:rule-set-options|alert:rule-set-name|alert:rule-set-description|alert:rule-set-action|alert:rule-remove|alert:rule-name-query|alert:rule-insert|alert:rule-id-query|alert:rule-get-user-id|alert:rule-get-query|alert:rule-get-options|alert:rule-get-name|alert:rule-get-id|alert:rule-get-description|alert:rule-get-action|alert:rule-action-query|alert:remove-triggers|alert:make-rule|alert:make-log-action|alert:make-config|alert:make-action|alert:invoke-matching-actions|alert:get-my-rules|alert:get-all-rules|alert:get-actions|alert:find-matching-rules|alert:create-triggers|alert:config-set-uri|alert:config-set-trigger-ids|alert:config-set-options|alert:config-set-name|alert:config-set-description|alert:config-set-cpf-domain-names|alert:config-set-cpf-domain-ids|alert:config-insert|alert:config-get-uri|alert:config-get-trigger-ids|alert:config-get-options|alert:config-get-name|alert:config-get-id|alert:config-get-description|alert:config-get-cpf-domain-names|alert:config-get-cpf-domain-ids|alert:config-get|alert:config-delete|alert:action-set-options|alert:action-set-name|alert:action-set-module-root|alert:action-set-module-db|alert:action-set-module|alert:action-set-description|alert:action-remove|alert:action-insert|alert:action-get-options|alert:action-get-name|alert:action-get-module-root|alert:action-get-module-db|alert:action-get-module|alert:action-get-description|zero-or-one|years-from-duration|year-from-dateTime|year-from-date|upper-case|unordered|true|translate|trace|tokenize|timezone-from-time|timezone-from-dateTime|timezone-from-date|sum|subtract-dateTimes-yielding-yearMonthDuration|subtract-dateTimes-yielding-dayTimeDuration|substring-before|substring-after|substring|subsequence|string-to-codepoints|string-pad|string-length|string-join|string|static-base-uri|starts-with|seconds-from-time|seconds-from-duration|seconds-from-dateTime|round-half-to-even|round|root|reverse|resolve-uri|resolve-QName|replace|remove|QName|prefix-from-QName|position|one-or-more|number|not|normalize-unicode|normalize-space|node-name|node-kind|nilled|namespace-uri-from-QName|namespace-uri-for-prefix|namespace-uri|name|months-from-duration|month-from-dateTime|month-from-date|minutes-from-time|minutes-from-duration|minutes-from-dateTime|min|max|matches|lower-case|local-name-from-QName|local-name|last|lang|iri-to-uri|insert-before|index-of|in-scope-prefixes|implicit-timezone|idref|id|hours-from-time|hours-from-duration|hours-from-dateTime|floor|false|expanded-QName|exists|exactly-one|escape-uri|escape-html-uri|error|ends-with|encode-for-uri|empty|document-uri|doc-available|doc|distinct-values|distinct-nodes|default-collation|deep-equal|days-from-duration|day-from-dateTime|day-from-date|data|current-time|current-dateTime|current-date|count|contains|concat|compare|collection|codepoints-to-string|codepoint-equal|ceiling|boolean|base-uri|avg|adjust-time-to-timezone|adjust-dateTime-to-timezone|adjust-date-to-timezone|abs)\b/],
["pln",/^[\w:-]+/],["pln",/^[\t\n\r \xa0]+/]]),["xq","xquery"]);


================================================
FILE: doc/assets/javascript/lang-yaml.js
================================================
var a=null;
PR.registerLangHandler(PR.createSimpleLexer([["pun",/^[:>?|]+/,a,":|>?"],["dec",/^%(?:YAML|TAG)[^\n\r#]+/,a,"%"],["typ",/^&\S+/,a,"&"],["typ",/^!\S*/,a,"!"],["str",/^"(?:[^"\\]|\\.)*(?:"|$)/,a,'"'],["str",/^'(?:[^']|'')*(?:'|$)/,a,"'"],["com",/^#[^\n\r]*/,a,"#"],["pln",/^\s+/,a," \t\r\n"]],[["dec",/^(?:---|\.\.\.)(?:[\n\r]|$)/],["pun",/^-/],["kwd",/^\w+:[\n\r ]/],["pln",/^\w+/]]),["yaml","yml"]);


================================================
FILE: doc/assets/javascript/prettify.js
================================================
var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();


================================================
FILE: doc/index.md
================================================
---
layout: default
title: Swarm oriented ERlang Expert SYstem Engine
---

Introduction
------------

SERESYE is a Rete based rules engine written in Erlang, descended
directly from the Eresye project by Francesca Gangemi and Corrado
Santoro. In the following article we will describe how to use the
system.

A rule-based system is composed of a **knowledge base**, which stores
a set of *facts* representing the 'universe of discourse' of a given
application, and a set of **production rules**, which are used to
infer knowledge and/or reason about the knowledge. A rule is activated
when one or more facts match the template(s) given in the rule
declaration: in such a case, the body of the rule contains a code that
is thus executed

In SERESYE, *facts* are expressed by means of Erlang tuples or records,
while rules are written using standard Erlang function clauses, whose
declaration reports, in the clause head, the facts or fact templates
that have to be matched for the rule to be activated and executed.

For more information about SERESYE please refer to the paper docs directory.

For more information about rule-based inference engines and expert
systems, you can refer to the book: *S. Russell and
P. Norvig. **Artificial Intelligence: A Modern Approach/2E.** Prentice
Hall, 2003.*

To write an AI application with SERESYE the following steps have to be
performed:

1. Identify your universe of discourse and determine the facts that
   have to be used to represent such a world;

2. Identify the rules that you need and write them by using, e.g.
   first-order-logic predicates or even natural language;

3. Implement the system by writing your rules as Erlang function
   clauses, according to the modality required by SERESYE.


The Application: the Domain of Relatives
----------------------------------------

We will design a system able to derive new knowledge using some
inference rules and starting from a small set; as a sample
application, we chose the domain of relatives: we will start from some
base concepts, such as *parent*, *male* and *female*, and then, by
means of a proper set of rules, we will derive the concepts of
*mother*, *father*, *sister*, *brother*, *grandmother* and
*grandfather*.

According to the list above, we will first derive the facts that will be
used to represent our concepts. Given the set of relationships above, they
will be represented by means of the following facts:

<table border="1" align="center">
<thead>
  <tr>
    <td><p>#</p></td>
    <td><p>Concept</p></td>
    <td><p>Fact / Erlang tuple</p></td>
  </tr>
</thead>
<tbody>
  <tr>
    <td><p>1</p></td>
    <td><p>X is male</p></td>
    <td><p><tt>{male, X}</tt></p></td>
  </tr>
  <tr>
    <td><p>2</p></td>
    <td><p>X is female</p></td>
    <td><p><tt>{female, X}</tt></p></td>
  </tr>
  <tr>
    <td><p>3</p></td>
    <td><p>X is Y's parent</p></td>
    <td><p><tt>{parent, X, Y}</tt></p></td>
  </tr>
  <tr>
    <td><p>4</p></td>
    <td><p>X is Y's mother</p></td>
    <td><p><tt>{mother, X, Y}</tt></p></td>
  </tr>
  <tr>
    <td><p>5</p></td>
    <td><p>X is Y's father</p></td>
    <td><p><tt>{father, X, Y}</tt></p></td>
  </tr>
  <tr>
    <td><p>6</p></td>
    <td><p>X is Y's sister</p></td>
    <td><p><tt>{sister, X, Y}</tt></p></td>
  </tr>
  <tr>
    <td><p>7</p></td>
    <td><p>X is Y's brother</p></td>
    <td><p><tt>{brother, X, Y}</tt></p></td>
  </tr>
  <tr>
    <td><p>8</p></td>
    <td><p>X is Y's grandmother</p></td>
    <td><p><tt>{grandmother, X, Y}</tt></p></td>
  </tr>
  <tr>
    <td><p>9</p></td>
    <td><p>X is Y's grandfather</p></td>
    <td><p><tt>{grandfather, X, Y}</tt></p></td>
  </tr>
</tbody>
</table>

Concepts 1, 2 and 3 will be used as a base to derive the other ones.

Deriving new concepts by means of rules
---------------------------------------

#### Concept: mother

The rule to derive the concept of mother is quite
straightforward:

    if X is female and X is Y's parent then X is Y's mother.

From the point of view of SERESYE, since knowledge is stored in the
*knowledge base* of the engine, the rule above is translated into the
following one: *if the facts {female, X} and {parent, X, Y} are
*asserted* in the knowledge base, then we assert the fact {mother, X,
Y}.

The rule *mother* can be thus written as follows:

    %%
    %% if (X is female) and (X is Y's parent) then (X is Y's mother)
    %%
    mother (Engine, {female, X}, {parent, X, Y}) ->
      seresye:assert (Engine, {mother, X, Y}).


#### Concept: father

This concept can be easily derived by means of the following rule:

    %%
    %% if (X is male) and (X is Y's parent) then (X is Y's father)
    %%
    father (Engine, {male, X}, {parent, X, Y}) ->
      seresye:assert (Engine, {father, X, Y}).


#### Concept: sister

 This concept can be expressed by the following rule:

    if Y and Z have the same parent and Z is female, then Z
    is the Y's sister.

The SERESYE rule used to map this concept is:

    %%
    %% if (Y and Z have the same parent X) and (Z is female)
    %%    then (Z is Y's sister)
    %%
    sister (Engine, {parent, X, Y}, {parent, X, Z}, {female, Z}) when Y =/= Z ->
      seresye:assert (Engine, {sister, Z, Y}).


Please note the guard, which is needed to ensure that when Y and Z are
bound to the same value, the rule is not activated (indeed this is
possible since the same fact can match both the first and second
'parent' pattern).

#### Concept: brother

Given the previous one, this concept is now quite simple to
implement:


    %%
    %% if (Y and Z have the same parent X) and (Z is male)
    %%    then (Z is Y's brother)
    %%
    brother (Engine, {parent, X, Y}, {parent, X, Z}, {male, Z}) when Y =/= Z ->
      seresye:assert (Engine, {brother, Z, Y}).


#### Concepts: grandmother and grandfather

The former concept can be expressed by means of the rule:

    if X is Y's mother and Y is Z's parent, then X is Z's
    grandmother.</u>* The latter concept is now obvious.

Both can be implemented using the following SERESYE rules:

    %%
    %% if (X is Y's mother) and (Y is Z's parent)
    %%    then (X is Z's grandmother)
    %%
    grandmother (Engine, {mother, X, Y}, {parent, Y, Z}) ->
      seresye:assert (Engine, {grandmother, X, Z}).

    %%
    %% if (X is Y's father) and (Y is Z's parent)
    %%    then (X is Z's grandfather)
    %%
    grandfather (Engine, {father, X, Y}, {parent, Y, Z}) ->
      seresye:assert (Engine, {grandfather, X, Z}).


Instantiating the Engine and Populating the Knowledge Base
----------------------------------------------------------

After writing the rules, we need to:

- define the rules to seresye
- instantiate the engine;
- populate the knowledge base with a set of initial facts.

We define the rules to SERESYE by defined a 'rules' attribute at the
start of the module.

    %%%
    %%% relatives.erl
    %%%
    -module (relatives).

    -export([father/3, grandfather/3, grandmother/3,
             mother/3, brother/4, sister/4, start/0]).

    -rules([mother, father, brother, sister, grandfather,
            grandmother]).

We continue on to instantiate the engine and popoulate the knowledge
base in the function *start* below:

    start () ->
      application:start(seresye) % Only if it is not already started
      seresye:start(relatives),
      seresye:add_rules(relatives, ?MODULE)

      seresye:assert(relatives,
                     [{male, bob}, {male, corrado}, {male, mark}, {male, caesar},
                      {female, alice}, {female, sara}, {female, jane}, {female, anna},
                      {parent, jane, bob}, {parent, corrado, bob},
                      {parent, jane, mark}, {parent, corrado, mark},
                      {parent, jane, alice}, {parent, corrado, alice},
                      {parent, bob, caesar}, {parent, bob, anna},
                      {parent, sara, casear}, {parent, sara, anna}]),
      ok.

As the listing reports, creating a new SERESYE engine implies to call
the function *seresye:start/1*, giving the name of the engine to be
created

Then, we have to add the rules to the engine by using the function
*seresye:add_rule/2*: it takes two arguments, the name of the engine
and a tuple representing the function in the form *{Module,
FuncName}*; obviously the function *Module:FuncName* must be
exported. Function *add_rule* has to be called for each rule that has
to be added; for this reason, the code above has an iteration over the
list of rules written before.

Finally, we populate the inference engine with a set of sample facts
by giving them, in a list, to the function *seresye:assert/2*.  To test
our rules, we considered the relationships in the Figure below and
assert only the facts for *male*, *female* and *parent*.

Testing the application
-----------------------

The final complete code of our AI application is thus the following:


    %%%
    %%% relatives.erl
    %%%
    -module (relatives).
    -export([father/3, grandfather/3, grandmother/3,
             mother/3, brother/4, sister/4, start/0]).

    %%
    %% if (X is female) and (X is Y's parent) then (X is Y's mother)
    %%
    mother(Engine, {female, X}, {parent, X, Y}) ->
      seresye:assert(Engine, {mother, X, Y}).

    %%
    %% if (X is male) and (X is Y's parent) then (X is Y's father)
    %%
    father(Engine, {male, X}, {parent, X, Y}) ->
      seresye:assert(Engine, {father, X, Y}).

    %%
    %% if (Y and Z have the same parent X) and (Z is female)
    %%    then (Z is Y's sister)
    %%
    sister(Engine, {parent, X, Y}, {parent, X, Z}, {female, Z}) when Y =/= Z ->
      seresye:assert(Engine, {sister, Z, Y}).

    %%
    %% if (Y and Z have the same parent X) and (Z is male)
    %%    then (Z is Y's brother)
    %%
    brother(Engine, {parent, X, Y}, {parent, X, Z}, {male, Z}) when Y =/= Z ->
      seresye:assert(Engine, {brother, Z, Y}).

    %%
    %% if (X is Y's father) and (Y is Z's parent)
    %%    then (X is Z's grandfather)
    %%
    grandfather (Engine, {father, X, Y}, {parent, Y, Z}) ->
      seresye:assert (Engine, {grandfather, X, Z}).

    %%
    %% if (X is Y's mother) and (Y is Z's parent)
    %%    then (X is Z's grandmother)
    %%
    grandmother(Engine, {mother, X, Y}, {parent, Y, Z}) ->
      seresye:assert(Engine, {grandmother, X, Z}).

    start () ->
      application:start(seresye),
      seresye:start (relatives),
      seresye:add_rules(relatives, ?MODULE)

      seresye:assert (relatives,
                     [{male, bob},
                      {male, corrado},
                      {male, mark},
                      {male, caesar},
                      {female, alice},
                      {female, sara},
                      {female, jane},
                      {female, anna},
                      {parent, jane, bob},
                      {parent, corrado, bob},
                      {parent, jane, mark},
                      {parent, corrado, mark},
                      {parent, jane, alice},
                      {parent, corrado, alice},
                      {parent, bob, caesar},
                      {parent, bob, anna},
                      {parent, sara, casear},
                      {parent, sara, anna}]),
      ok.

Now it's time to test our application:


    Erlang (BEAM) emulator version 5.5 [source] [async-threads:0] [hipe]

    Eshell V5.5  (abort with ^G)
    1> c(relatives).
    {ok,relatives}
    2> relatives:start().
    ok
    3>

Following the call to function *relatives:start/0*, the engine is
created and populated; if no errors occurred, the rules should have
been processed and the new facts derived. To check this, we can use
the function *seresye:get_kb/1*, which returns the list of facts
asserted into the knowledge base of a given engine:


    4> seresye:get_kb(relatives).
    [{brother,bob,mark},
     {sister,alice,bob},
     {sister,alice,mark},
     {brother,bob,alice},
     {brother,mark,alice},
     {grandmother,jane,caesar},
     {grandfather,corrado,caesar},
     {grandmother,jane,anna},
     {grandfather,corrado,anna},
     {sister,anna,caesar},
     {brother,caesar,anna},
     {sister,anna,casear},
     {mother,sara,anna},
     {mother,sara,casear},
     {parent,sara,anna},
     {father,bob,anna},
     {parent,sara,casear},
     {father,bob,caesar},
     {parent,bob,anna},
     {father,corrado,alice},
     {parent,bob,caesar},
     {mother,jane,alice},
     {parent,corrado,alice},
     {father,corrado,mark},
     {parent,jane,alice},
     {mother,jane,mark},
     {parent,corrado|...},
     {brother|...},
     {...}|...]
    5>

The presence of facts representing concepts like *father*, *sister*,
etc., proves that the rules seems to be working as expected.

We can however query the knowledge base using specific fact templates.
For example, if we want to know who are Alice's brothers, we can use
the function *seresye:query_kb/2* as follows:


    6> seresye:query_kb(relatives, {brother, '_', alice}).
    [{brother,bob,alice},{brother,mark,alice}]
    7>

The facts returned conform to the relationships depicted in the figure
above, thus proving that the rules written are really working.

As the example shows, function *seresye:query_kb/2* takes the engine
name as the first argument, while, for the second parameter, a tuple
has to be specified, representing the fact template to be matched; in
such a tuple, the atom *'_'* plays the role of a wildcard. However, to
specify a more complex matching, a *fun* can be used as a tuple
element; this *fun* has to return a boolean value which indicates if
the element matches the template. For example, to select both Alice's
and Anna's brothers, we can use the following function call:


    7> seresye:query_kb(relatives, {brother, '_', fun (X) -> (X == alice) or (X == anna) end}).
    [{brother,bob,alice},{brother,mark,alice},{brother,caesar,anna}]
    8>


Conclusions
-----------

This HowTo not only shows how to use the SERESYE engine to write an AI
application, but also highlights the versatility of the Erlang language:
the characteristics of functional and symbolic programming, together with
the possibility of performing *introspection* of function declaration,
can be successfully exploited for application domains which are completely
new for Erlang but can surely be very interesting.


================================================
FILE: examples/seresye_phil.erl
================================================
%%%  SERESYE, an ERlang Expert SYstem Engine
%%%
%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro
%%% All rights reserved.
%%%
%%% You may use this file under the terms of the BSD License. See the
%%% license distributed with this project or
%%% http://www.opensource.org/licenses/bsd-license.php%
-module(seresye_phil).

-export([start/0, phil_spawn/1, philosopher/2, think/1, eat/1]).

-define(N_PHIL, 5).

start() ->
    application:start(seresye),
    seresye:start(restaurant),
    phil_spawn(0).

phil_spawn(?N_PHIL) -> ok;
phil_spawn(N) ->
    seresye:assert(restaurant, {fork, N}),
    spawn(phil, philosopher, [N, init]),
    if N < (?N_PHIL) - 1 ->
           seresye:assert(restaurant, {room_ticket, N});
       true -> ok
    end,
    phil_spawn(N + 1).

philosopher(N, init) -> new_seed(), philosopher(N, ok);
philosopher(N, X) ->
    think(N),
    Ticket = seresye:wait_and_retract(restaurant,
                                     {room_ticket, '_'}),
    seresye:wait_and_retract(restaurant, {fork, N}),
    seresye:wait_and_retract(restaurant,
                            {fork, (N + 1) rem (?N_PHIL)}),
    eat(N),
    seresye:assert(restaurant, {fork, N}),
    seresye:assert(restaurant,
                  {fork, (N + 1) rem (?N_PHIL)}),
    seresye:assert(restaurant, Ticket),
    philosopher(N, X).

think(N) ->
    io:format("~w: thinking ...~n", [N]),
    timer:sleep(random:uniform(10) * 1000).

eat(N) ->
    io:format("~w: eating ...~n", [N]),
    timer:sleep(random:uniform(10) * 1000).

new_seed() ->
    {_, _, X} = erlang:now(),
    {H, M, S} = time(),
    H1 = H * X rem 32767,
    M1 = M * X rem 32767,
    S1 = S * X rem 32767,
    put(random_seed, {H1, M1, S1}).


================================================
FILE: examples/seresye_prodcons.erl
================================================
%%%  ERESYE, an ERlang Expert SYstem Engine
%%%
%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro
%%% All rights reserved.
%%%
%%% You may use this file under the terms of the BSD License. See the
%%% license distributed with this project or
%%% http://www.opensource.org/licenses/bsd-license.php
-module(seresye_prodcons).

-export([start/0, prod/1, cons/1, cons_1/1]).

start() ->
    application:start(seresye),
    eresye:start(pc),
    spawn(prodcons, cons_1, [1]),
    spawn(prodcons, cons_1, [2]),
    spawn(prodcons, cons_1, [3]),
    spawn(prodcons, prod, [0]),
    ok.

prod(20) -> ok;
prod(Index) ->
    eresye:assert(pc, {item, Index}), prod(Index + 1).

cons(20) -> ok;
cons(Index) ->
    Fact = eresye:retract(pc,
                          {item, fun (X) -> X == Index end}),
    io:format("Consumer ~p~n", [Fact]),
    cons(Index + 1).

cons_1(N) ->
    Fact = eresye:wait_and_retract(pc, {item, '_'}),
    io:format("~w: Consumer ~p~n", [N, Fact]),
    timer:sleep(random:uniform(500)),
    cons_1(N).


================================================
FILE: examples/seresyee_auto.erl
================================================
%%%  SERESYE, an ERlang Expert SYstem Engine
%%%
%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro
%%% All rights reserved.
%%%
%%% You may use this file under the terms of the BSD License. See the
%%% license distributed with this project or
%%% http://www.opensource.org/licenses/bsd-license.php
%%% ======================================================
%%%   Automotive Expert System
%%%
%%%     This expert system diagnoses some simple
%%%     problems with a car.
%%%
%%%     It is a bare translation of the same example
%%%     provided in CLIPS Version 6.0
%%%
%%%     To execute, type 'auto:start().'
%%% ======================================================
-module(seresyee_auto).

-export([determine_battery_state/2,
         determine_conductivity_test/4, determine_engine_state/2,
         determine_gas_level/3, determine_knocking/2,
         determine_low_output/2, determine_misfiring/2,
         determine_point_surface_state_1/3,
         determine_point_surface_state_2/2,
         determine_rotation_state/2, determine_sluggishness/2,
         no_repairs/2, normal_engine_state_conclusions/2,
         print_repair/3, start/0,
         unsatisfactory_engine_state_conclusions/2]).

-neg_rule({determine_engine_state, [{'working-state', engine, '__IGNORE_UNDERSCORE__'},
                                    {repair, '__IGNORE_UNDERSCORE__'}]}).

-include_lib("seresye/include/seresye.hrl").

%% **********************
%% * ENGINE STATE RULES *
%% **********************
normal_engine_state_conclusions(Engine,
                                {'working-state', engine, normal}) ->
    seresye_engine:assert(Engine,
                         [{repair, "No repair needed."},
                          {'spark-state', engine, normal},
                          {'charge-state', battery, charged},
                          {'rotation-state', engine, rotates}]).

unsatisfactory_engine_state_conclusions(Engine,
                                        {'working-state', engine,
                                         unsatisfactory}) ->
    seresye_engine:assert(Engine,
                         [{'charge-state', battery, charged},
                          {'rotation-state', engine, rotates}]).

%% ***************
%% * QUERY RULES *
%% ***************
determine_engine_state(Engine, {start, _})
  when not {rule, [{'working-state', engine, _}, {repair, _}]} ->
    case ask_yn('Does the engine start (yes/no)? ') of
        true ->
            case ask_yn('Does the engine run normally (yes/no)? ')
            of
                true ->
                    seresye_engine:assert(Engine,
                                         {'working-state', engine, normal});
                _ ->
                    seresye_engine:assert(Engine,
                                         {'working-state', engine, unsatisfactory})
            end;
        _ ->
            seresye_engine:assert(Engine,
                                 {'working-state', engine, 'does-not-start'})
    end.

determine_rotation_state(Engine,
                         {'working-state', engine, 'does-not-start'})
  when not
       {rule, [{'rotation-state', engine, _}, {repair, _}]} ->
    case ask_yn('Does the engine rotate (yes/no)? ') of
        true ->
            seresye_engine:assert(Engine,
                                 [{'rotation-state', engine, rotates},
                                  {'spark-state', engine, 'irregular-spark'}]);
        _ ->
            seresye_engine:assert(Engine,
                                 [{'rotation-state', engine, 'does-not-rotate'},
                                  {'spark-state', engine, 'does-not-spark'}])
    end.

determine_sluggishness(Engine,
                       {'working-state', engine, unsatisfactory})
  when not {rule, [{repair, _}]} ->
    case ask_yn('Is the engine sluggish (yes/no)? ') of
        true ->
            seresye_engine:assert(Engine, {repair, "Clean the fuel line."});
        _ -> Engine
    end.

determine_misfiring(Engine,
                    {'working-state', engine, unsatisfactory})
  when not {rule, [{repair, _}]} ->
    case ask_yn('Does the engine misfire (yes/no)? ') of
        true ->
            seresye_engine:assert(Engine,
                                 [{repair, "Point gap adjustment."},
                                  {'spark-state', engine, 'irregular-spark'}]);
        _ -> Engine
    end.

determine_knocking(E,
                   {'working-state', engine, unsatisfactory})
  when not {rule, [{repair, _}]} ->
    case ask_yn('Does the engine knock (yes/no)? ') of
        true ->
            seresye_engine:assert(E, {repair, "Timing adjustment."});
        _ -> E
    end.

determine_low_output(E,
                     {'working-state', engine, unsatisfactory})
  when not {rule, [{symptom, engine, _}, {repair, _}]} ->
    case
        ask_yn('Is the output of the engine low (yes/no)? ')
    of
        true ->
            seresye_engine:assert(E, {symptom, engine, 'low-output'});
        _ ->
            seresye_engine:assert(E, {symptom, engine, 'not-low-output'})
    end.

determine_gas_level(E,
                    {'working-state', engine, 'does-not-start'},
                    {'rotation-state', engine, rotates})
  when not {rule, [{repair, _}]} ->
    case
        ask_yn('Does the tank have any gas in it (yes/no)? ')
    of
        false -> seresye_engine:assert(E, {repair, "Add gas."});
        _ -> E
    end.

determine_battery_state(E,
                        {'rotation-state', engine, 'does-not-rotate'})
  when not
       {rule, [{'charge-state', battery, _}, {repair, _}]} ->
    case ask_yn('Is the battery charged (yes/no)? ') of
        true ->
            seresye_engine:assert(E, {'charge-state', battery, charged});
        _ ->
            seresye_engine:assert(E,
                                 [{repair, "Charge the battery."},
                                  {'charge-state', battery, dead}])
    end.

determine_point_surface_state_1(E,
                                {'working-state', engine, 'does-not-start'},
                                {'spark-state', engine, 'irregular-spark'})
  when not {rule, [{repair, _}]} ->
    dpss(E).

determine_point_surface_state_2(E,
                                {symptom, engine, 'low-output'})
  when not {rule, [{repair, _}]} ->
    dpss(E).

dpss(E) ->
    case
        ask_question('What is the surface state of the points (normal/burned/contaminated)? ')
    of
        [$b, $u, $r, $n, $e, $d | _] ->
            seresye_engine:assert(E, {repair, "Replace the points."});
        [$c, $o, $n, $t, $a, $m, $i, $n, $a, $t, $e, $d | _] ->
            seresye_engine:assert(E, {repair, "Clean the points."});
        _ -> E
    end.

determine_conductivity_test(E,
                            {'working-state', engine, 'does-not-start'},
                            {'spark-state', engine, 'does-not-spark'},
                            {'charge-state', battery, charged})
  when not {rule, [{repair, _}]}; true ->
    case
        ask_yn('Is the conductivity test for the ignition coil positive (yes/no)? ')
    of
        true ->
            seresye_engine:assert(E,
                                 {repair, "Repair the distributor lead wire."});
        _ ->
            seresye_engine:assert(E, {repair, "Replace the ignition coil."})
    end.

no_repairs(E, {start, _})
  when not {rule, [{repair, _}]}, true ->
    seresye_engine:assert(E,
                         {repair, "Take your car to a mechanic."}).

print_repair(E, {repair, X}, {start, _}) ->
    io:format("Suggested Repair: ~p~n", [X]), E.

ask_yn(Prompt) ->
    [Response | _] = io:get_line(Prompt),
    case Response of
        $y -> true;
        _ -> false
    end.

ask_question(Prompt) -> io:get_line(Prompt).

start() ->
    Engine0 = seresye_engine:new(),
    %% Rules with high priority (10)
    Engine2 = lists:foldl(fun (Rule, Engine1) ->
                                  seresye_engine:add_rule(Engine1, {?MODULE, Rule}, 10)
                          end,
                          Engine0,
                          [normal_engine_state_conclusions,
                           unsatisfactory_engine_state_conclusions,
                           print_repair]),
    %% Rules with normal priority (0)
    Engine3 = lists:foldl(fun (Rule, Engine1) ->
                                  seresye_engine:add_rule(Engine1, {?MODULE, Rule})
                          end,
                          Engine2,
                          [determine_engine_state, determine_rotation_state,
                           determine_sluggishness, determine_misfiring,
                           determine_knocking, determine_low_output,
                           determine_gas_level, determine_battery_state,
                           determine_point_surface_state_1,
                           determine_point_surface_state_2,
                           determine_conductivity_test]),
    %% Rules with low priority (-10)
    Engine4 = seresye_engine:add_rule(Engine3,
                                     {?MODULE, no_repairs}, -10),
    seresye_engine:assert(Engine4, {start, ok}).


================================================
FILE: features/seresyet_12.feature
================================================
Feature: Support explicit state passing in an seresye system
  In order to make callbacks more easily accessible and less prone to requiring side effects
  As an Erlang Developer
  I want to be able to have my own per engine state
  and have that state be passed to my rules when they execute

  Scenario: Retrievable  state gets passed to rules
    Given a seresye engine that is initialized with state
    And initialized with data
    When seresye propagation is complete
    Then the per engine state is retrievable
    And contains the data populated by the rules


================================================
FILE: features/seresyet_13.feature
================================================
Feature: Support defining rules via module attributes
  In order to seresye more usable
  As an Erlang Developer
  I want to be able define my rules via rule attributes in the module file itself

  Scenario: Rules are defined in the attribute itself
    Given a seresye engine that is initialized with data
    And rules from a module with rules defined via attributes
    When when seresye propagation is complete
    Then the engine runs normally
    And contains the data populated by the rules


================================================
FILE: include/seresye.hrl
================================================
%% Parse transforms for automatic creating negative specs for rules in
%% a rules file. though the user can write them in a spec it is much
%% nicer to write them in a when clause and let the transform do its
%% work.
-compile({parse_transform, seresye_autoneg}).
-compile({parse_transform, seresye_transform}).


================================================
FILE: rebar.config
================================================
{deps, 
  [
   {edown, ".*", {git, "https://github.com/uwiger/edown.git", {branch, "master"}}},
   {erlware_commons, ".*", {git, "https://github.com/erlware/erlware_commons.git", {branch, "master"}}},
   {parse_trans, ".*", {git, "https://github.com/esl/parse_trans.git", {branch, "master"}}}
]}.


================================================
FILE: sinan.config
================================================
{project_name, seresye}.
{project_vsn, "0.0.4"}.

{compile_args, [debug_info, warnings_as_errors,
               {warn_format, 2}, warn_export_all,
               warn_export_vars, warn_shadow_vars, warn_obsolete_guard,
               warn_unused_import]}.

{ignore_dirs,  ["_",
                ".",
                "features"]}.


================================================
FILE: src/internal.hrl
================================================
-record(seresye, {kb, alfa, join, agenda, pending_actions, client_state, fired_rule, hooks = []}).


================================================
FILE: src/seresye.app.src
================================================
%% -*- mode: Erlang; fill-column: 75; comment-column: 50; -*-

{application, seresye,
 [{description, "SERESYE means Swarm oriented ERlang Expert SYstem Engine. It is a library "
   "to write expert systems and rule processing engines using the Erlang "
   "programming language"},
  {vsn, "0.0.4"},
  {modules, []},
  {registered, []},
  {applications, [kernel, stdlib, erlware_commons]},
  {mod, {seresye_app, []}}]}.


================================================
FILE: src/seresye.erl
================================================
%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine
%%%
%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro
%%% All rights reserved.
%%%
%%% You may use this file under the terms of the BSD License. See the
%%% license distributed with this project or
%%% http://www.opensource.org/licenses/bsd-license.php
-module(seresye).

%%====================================================================
%% External exports
%%====================================================================

-export([start/0, start/1, start/2, stop/1, get_engine/1,
         add_rules/2, add_rule/2, add_rule/3, assert/2, get_kb/1,
         get_rules_fired/1, get_client_state/1,
         set_hooks/2, get_fired_rule/1,
         set_client_state/2, query_kb/2, serialize/1, 
         remove_rule/2, retract/2]).

%% gen_server callbacks
-export([start_link/0, start_link/1, start_link/2, init/1, handle_call/3,
         handle_cast/2, handle_info/2, terminate/2, code_change/3]).

%%====================================================================
%% External functions
%%====================================================================
start() ->
    seresye_sup:start_engine().

start(Name) ->
    seresye_sup:start_engine(Name).

start(Name, ClientState) ->
    seresye_sup:start_engine(Name, ClientState).

set_hooks(Name, Hooks) when is_list(Hooks) ->
    gen_server:cast(Name, {set_hooks, Hooks}).

set_client_state(Name, NewState) ->
    gen_server:cast(Name, {set_client_state, NewState}).

get_client_state(Name) ->
    gen_server:call(Name, get_client_state).

stop(EngineName) ->
    (catch gen_server:call(EngineName, stop)),
    ok.

get_engine(EngineName) ->
    gen_server:call(EngineName, get_engine).

%% @doc Insert a fact in the KB.
%% It also checks if the fact verifies any condition,
%% if this is the case the fact is also inserted in the alpha-memory
assert(Name, Facts) ->
    gen_server:call(Name, {assert, Facts}, infinity).

%% @doc removes a 'fact' in the Knowledge Base and if something occurs
%% Condition is also deleted from the corresponding alpha-memory
retract(Name, Facts) ->
    gen_server:call(Name, {retract, Facts}, infinity).

add_rules(Name, RuleList)
  when is_list(RuleList) orelse is_atom(RuleList) ->
    gen_server:call(Name, {add_rules, RuleList}).

add_rule(Name, Fun) ->
    gen_server:call(Name, {add_rule, Fun}).

add_rule(Name, Rule, Salience) ->
    gen_server:call(Name, {add_rule, Rule, Salience}).

remove_rule(Name, Rule) ->
    gen_server:call(Name, {remove_rule, Rule}).

get_rules_fired(Name) ->
    gen_server:call(Name, get_rules_fired).

get_fired_rule(Name) ->
    gen_server:call(Name, get_fired_rule).    

get_kb(Name) ->
    gen_server:call(Name, get_kb).

query_kb(Name, Pattern) ->
    gen_server:call(Name, {query_kb, Pattern}).

serialize(Name) ->
    gen_server:call(Name, serialize).

%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
start_link() ->
    gen_server:start_link(?MODULE, [], []).

start_link(Name) when is_atom(Name) ->
    gen_server:start_link({local, Name}, ?MODULE, [], []);

start_link(ClientState) when not is_atom(ClientState) ->
    gen_server:start_link(?MODULE, [ClientState], []).

start_link(ClientState, Name) when is_atom(Name) ->
    gen_server:start_link({local, Name}, ?MODULE, [ClientState], []).


init([]) ->
    {ok, seresye_engine:new()};
init([Engine]) when element(1, Engine) == seresye ->
    {ok, seresye_engine:restore(Engine)};
init([ClientState]) ->
    {ok, seresye_engine:new(ClientState)}.


handle_call(get_client_state, _From, State) ->
    Reply =
        try
            {ok, seresye_engine:get_client_state(State)}
        catch
            Type:Reason ->
                {error, {Type, Reason}}
        end,
    {reply, Reply, State};
handle_call(stop, _From, State) ->
    {stop, normal, State};
handle_call({assert, Facts}, _From, State0) ->
    {Reply, State1} =
        try
            {ok, seresye_engine:assert(State0, Facts)}
        catch
            Type:Reason ->
                {{error, {Type, Reason}}, State0}
        end,
    {reply, Reply, State1};
handle_call({retract, Facts}, _From, State0) ->
    {Reply, State1} =
        try
            {ok, seresye_engine:retract(State0, Facts)}
        catch
            Type:Reason ->
                {{error, {Type, Reason}}, State0}
        end,
    {reply, Reply, State1};
handle_call({add_rules, Rules}, _From, State0) ->
    {Reply, State1} =
        try
            {ok, seresye_engine:add_rules(State0, Rules)}
        catch
            Type:Reason ->
                {{error, {Type, Reason}}, State0}
        end,
    {reply, Reply, State1};
handle_call({add_rule, Rule}, _From, State0) ->
    {Reply, State1} =
        try
            {ok, seresye_engine:add_rule(State0, Rule)}
        catch
            Type:Reason ->
                {{error, {Type, Reason}}, State0}
        end,
    {reply, Reply, State1};
handle_call({add_rule, Rule, Salience}, _From, State0) ->
    {Reply, State1} =
        try
            {ok, seresye_engine:add_rule(State0, Rule, Salience)}
        catch
            Type:Reason ->
                {{error, {Type, Reason}}, State0}
        end,
    {reply, Reply, State1};
handle_call({remove_rule, Rule}, _From, State0) ->
    {Reply, State1} =
        try
            {ok, seresye_engine:remove_rule(State0, Rule)}
        catch
            Type:Reason ->
                {{error, {Type, Reason}}, State0}
        end,
    {reply, Reply, State1};
handle_call(get_rules_fired, _From, State0) ->
    Reply =
        try
            seresye_engine:get_rules_fired(State0)
        catch
            Type:Reason ->
                {error, {Type, Reason}}
        end,
    {reply, Reply, State0};
handle_call(get_fired_rule, _From, State0) ->
    Reply =
        try
            seresye_engine:get_fired_rule(State0)
        catch
            Type:Reason ->
                {error, {Type, Reason}}
        end,
    {reply, Reply, State0};
handle_call(get_engine, _From, State0) ->
    {reply, State0, State0};
handle_call(get_kb, _From, State0) ->
    Reply =
        try
            seresye_engine:get_kb(State0)
        catch
            Type:Reason ->
                {error, {Type, Reason}}
        end,
    {reply, Reply, State0};
handle_call({query_kb, Pattern}, _From, State0) ->
    Reply =
        try
            seresye_engine:query_kb(State0, Pattern)
        catch
            Type:Reason ->
                {error, {Type, Reason}}
        end,
    {reply, Reply, State0};

handle_call(serialize, _From, State) ->
    Reply = seresye_engine:serialize(State),
    {reply, Reply, State}.

handle_cast({set_hooks, Hooks}, State) ->
    {noreply, seresye_engine:set_hooks(State, Hooks)};

handle_cast({set_client_state, CS}, State) ->
    {noreply, seresye_engine:set_client_state(State, CS)}.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.


================================================
FILE: src/seresye_agenda.erl
================================================
%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine
%%%
%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro
%%% Copyright (c) 2011 Afiniate, Inc.
%%% All rights reserved.
%%%
%%% You may use this file under the terms of the BSD License. See the
%%% license distributed with this project or
%%% http://www.opensource.org/licenses/bsd-license.php
-module(seresye_agenda).

-export([new/1, add_activation/3, add_activation/4,
         breadth_order/2, clear_agenda/1, delete_activation/2,
         delete_rule/2, depth_order/2, fifo_order/2,
         get_activation/2, get_activation_from_name/2,
         get_activation_salience/2, get_first_activation/1,
         get_number_of_activations/1, get_rules_fired/1,
         get_strategy/1, pop_rule/1,
         set_activation_salience/3, set_rule_salience/3,
         set_strategy/2]).

-include("internal.hrl").

-record(agenda, {rules_fired, strategy, rule_list,
                 exec_state, id, pending_actions}).

%%====================================================================
%% External functions
%%====================================================================
new(Seresye) ->
    Seresye#seresye{agenda=#agenda{rules_fired=0,
                                 strategy=depth,
                                 rule_list=[],
                                 exec_state=nil,
                                 pending_actions=[],
                                 id=0}}.

add_activation(Agenda, Rule, Args) ->
    add_activation(Agenda, Rule, Args, 0).

add_activation(EngineState0 = #seresye{agenda=
                                          Agenda0 = #agenda{strategy=Strategy,
                                                            rule_list=RuleList0,
                                                            id=Id}},
               Rule, Args, Salience) ->
    RuleList1 = case Strategy of
                    depth ->
                        depth_add(RuleList0, Rule, Args, Salience, Id);
                    breadth ->
                        breadth_add(RuleList0, Rule, Args, Salience, Id);
                    fifo ->
                        fifo_add(RuleList0, Rule, Args, Salience, Id)
                  end,
    Agenda1 = Agenda0#agenda{rule_list=RuleList1, id=Id + 1},

    execute_pending(after_activation_schedule(EngineState0#seresye{agenda=Agenda1})).


%% @doc Remove all activation from Agenda,
%% returns an empty agenda with same past strategy
clear_agenda(EngineState = #seresye{agenda=Agenda0}) ->
    EngineState#seresye{agenda=Agenda0#agenda{rule_list=[], id=0}}.

get_strategy(#seresye{agenda=#agenda{strategy=Strategy}}) ->
    Strategy.

set_strategy(EngineState = #seresye{agenda=Agenda0 = #agenda{rule_list=RuleList0}}, NewStrategy) ->
    RuleList1 = case NewStrategy of
                    depth ->
                        lists:sort(fun depth_order/2, RuleList0);
                    breadth ->
                        lists:sort(fun breadth_order/2,
                                   RuleList0);
                    fifo ->
                        lists:sort(fun fifo_order/2, RuleList0);
                    _ ->
                        erlang:throw({seresye, {invalid_strategy, NewStrategy}})

                end,
    EngineState#seresye{agenda=Agenda0#agenda{strategy=NewStrategy, rule_list=RuleList1}}.

get_rules_fired(#seresye{agenda=#agenda{rules_fired=Fired}}) ->
    Fired.

%% @doc Remove activation with id='Id' or
%% all activation whose id is in the list passed as argument
delete_activation(EngineState, []) -> EngineState;
delete_activation(EngineState = #seresye{agenda=Agenda0 = #agenda{rule_list=RuleList0}},
                 Id)
  when not is_list(Id) ->
    EngineState#seresye{agenda=Agenda0#agenda{rule_list=lists:keydelete(Id, 4, RuleList0)}};
delete_activation(EngineState, [Id | OtherId]) ->
    EngineState1 = delete_activation(EngineState, Id),
    delete_activation(EngineState1, OtherId).

%% @doc Remove all activation associated with rule 'Rule' from the agenda,
%% returns the modified agenda
delete_rule(EngineState = #seresye{agenda=Agenda0 = #agenda{rule_list=RuleList0}}, Rule) ->
    ActList = proplists:lookup_all(Rule, RuleList0),
    RuleList1 = lists:foldl(fun (X, R1) ->
                                    lists:delete(X, R1)
                            end,
                            RuleList0, ActList),
    EngineState#seresye{agenda=Agenda0#agenda{rule_list=RuleList1}}.

%% @doc Returns the Id of activation associated to rule 'Rule' and
%% arguments 'Args', false if it not present
get_activation(#seresye{agenda=#agenda{rule_list=RuleList0}}, {Rule, Args}) ->
    ActList = proplists:lookup_all(Rule, RuleList0),
    case lists:keysearch(Args, 2, ActList) of
        {value, {_, _, _, Id}} -> Id;
        false -> false
    end.

%% @doc Returns the Id of first activation associated to rule 'Rule',
%% false if 'Rule' is not present in the agenda
get_activation_from_name(#seresye{agenda=#agenda{rule_list=RuleList0}}, Rule) ->
    case lists:keysearch(Rule, 1, RuleList0) of
        {value, {_, _, _, Id}} -> Id;
        false -> false
    end.

%% @doc Return the Id associated to first activation in the agenda
%% false if agenda is empty
get_first_activation(#seresye{agenda=#agenda{rule_list=[First | _]}}) ->
    element(4, First).

%% @doc Return the salience value of activation with id='Id'
%% false if Id is not present in the agenda
get_activation_salience(#seresye{agenda=#agenda{rule_list=RuleList0, id=NextId}}, Id) ->
    case NextId < Id of
        true -> false;
        false ->
            case lists:keysearch(Id, 4, RuleList0) of
                {value, {_, _, Salience, _}} -> Salience;
                false -> false
            end
    end.

%% @doc Sets the salience value of activation with id='Id',
%% returns the modified agenda
set_activation_salience(EngineState =
                            #seresye{agenda=Agenda0 =
                                        #agenda{rule_list=RuleList0, strategy=Strategy}}, Id, NewSalience)
  when is_number(NewSalience) and not is_list(Id) ->
    RuleList2 =
        case lists:keysearch(Id, 4, RuleList0) of
            {value, {Rule, Args, _Salience, Id}} ->
                RuleList1 = lists:keyreplace(Id, 4, RuleList0,
                                             {Rule, Args, NewSalience, Id}),
                order(RuleList1, Strategy);
            false ->
                RuleList0
        end,
    EngineState#seresye{agenda=Agenda0#agenda{rule_list=RuleList2}};
set_activation_salience(_EngineState, Id, NewSalience)
  when not is_list(Id) ->
    erlang:throw({seresye, {invalid_salience, NewSalience}});
set_activation_salience(EngineState0, [Id | OtherId],
                        NewSalience) ->
    EngineState1 = set_activation_salience(EngineState0, Id, NewSalience),
    set_activation_salience(EngineState1, OtherId, NewSalience).

%% @doc Sets the salience value of all activations associated to rule 'Rule',
%% returns the modified agenda
set_rule_salience(EngineState0 =
                    #seresye{agenda=#agenda{rule_list=RuleList0}}, Rule, NewSalience) ->
    ActList = proplists:lookup_all(Rule, RuleList0),
    IdList = [Id || {_, _, _, Id} <- ActList],
    set_activation_salience(EngineState0, IdList,
                            NewSalience).


%%====================================================================
%% Internal functions
%%====================================================================
execute_pending(EngineState0 = #seresye{agenda = Agenda0 = #agenda{pending_actions=[PA | Rest]}}) ->
    EngineState1 = PA(EngineState0#seresye{agenda=Agenda0#agenda{pending_actions=Rest}}),
    execute_pending(EngineState1);
execute_pending(EngineState0 = #seresye{agenda = #agenda{pending_actions=[]}}) ->
    EngineState0.

after_activation_schedule(EngineState0 =
                              #seresye{agenda=Agenda0 =
                                          #agenda{rule_list=RuleList0,
                                                  exec_state=ExecState0,
                                                  pending_actions=PA0,
                                                  rules_fired=RF0}}) ->
    {ExecState1, RuleList1, PA1, RF1} =
        if
            ExecState0 == active -> {ExecState0, RuleList0, PA0, RF0};
            true ->
                {RuleToExecute, RL} = pop_rule(RuleList0),
                if
                    RuleToExecute == false ->
                        {nil, RL, PA0, RF0};
                    true ->
                        {active, RL, PA0 ++ [fun(EngineState) ->
                                                     exec(EngineState, RuleToExecute)
                                             end], RF0 + 1}
                end
        end,
    EngineState0#seresye{agenda=Agenda0#agenda{exec_state=ExecState1,
                                              rule_list=RuleList1,
                                              pending_actions=PA1,
                                              rules_fired=RF1}}.

after_execution_schedule(EngineState0 =
                             #seresye{agenda=Agenda0 =
                                         #agenda{rule_list=RuleList0,
                                                 pending_actions=PA0,
                                                 rules_fired=RF0}}) ->
  {RuleToExecute, RL} = pop_rule(RuleList0),
  {ExecState1, RuleList1, PA1, RF1} =
    if
      RuleToExecute == false -> {nil, RL, PA0, RF0};
      true ->
        {active, RL, PA0 ++ [fun(EngineState) ->
                                     exec(EngineState, RuleToExecute)
                             end], RF0 + 1}
    end,
    EngineState0#seresye{agenda=Agenda0#agenda{exec_state=ExecState1,
                                              rule_list=RuleList1,
                                              pending_actions=PA1,
                                              rules_fired=RF1}}.

%% @doc Remove the first activation, returns the rule,
%% function arguments and the modified agenda
pop_rule([]) -> {false, []};
pop_rule([Activation | NewRuleList]) ->
    {Activation, NewRuleList}.

depth_add(RuleList, Rule, Args, Salience, Id) ->
    {L1, L2} = lists:splitwith(fun ({_, _, S, _}) ->
                                       S > Salience
                               end,
                               RuleList),
    L1 ++ [{Rule, Args, Salience, Id} | L2].

breadth_add(RuleList, Rule, Args, Salience, Id) ->
    {L1, L2} = lists:splitwith(fun ({_, _, S, _}) ->
                                       S >= Salience
                               end,
                               RuleList),
    L1 ++ [{Rule, Args, Salience, Id} | L2].

fifo_add(RuleList, Rule, Args, Salience, Id) ->
    RuleList ++ [{Rule, Args, Salience, Id}].

get_number_of_activations({_Strategy, RuleList, _NextId}) ->
    length(RuleList).

order(ActionList, Strategy) ->
    case Strategy of
        breadth ->
            lists:sort(fun breadth_order/2, ActionList);
        depth -> lists:sort(fun depth_order/2, ActionList);
        fifo -> lists:sort(fun fifo_order/2, ActionList);
        _Other -> ActionList
    end.

%% @doc define when an Act1 comes before Act2 in breadth strategy
breadth_order(Act1, Act2)
  when element(3, Act1) > element(3, Act2) ->
    true;
breadth_order(Act1, Act2)
  when element(3, Act1) < element(3, Act2) ->
    false;
breadth_order(Act1, Act2)
  when element(4, Act1) > element(4, Act2) ->
    false;
breadth_order(_Act1, _Act2) -> true.

%% @doc define when an Act1 comes before Act2 in depth strategy
depth_order(Act1, Act2)
  when element(3, Act1) > element(3, Act2) ->
    true;
depth_order(Act1, Act2)
  when element(3, Act1) < element(3, Act2) ->
    false;
depth_order(Act1, Act2)
  when element(4, Act1) < element(4, Act2) ->
    false;
depth_order(_Act1, _Act2) -> true.

%% @doc define when an Act1 comes before Act2 in fifo strategy
fifo_order(Act1, Act2)
  when element(4, Act1) > element(4, Act2) ->
    false;
fifo_order(_Act1, _Act2) -> true.

%%====================================================================
%% Executor functions
%%====================================================================
exec(EngineState0, R) ->
    {Mod, Fun} = case R of
                     {{M, F}, _, _, _} -> {M, F};
                     _ -> {'_', '_'}
                 end,
    EngineState2 =
        case catch execute_rule(EngineState0, R) of
            {'EXIT', {function_clause, [{Mod, Fun, _} | _]}} -> EngineState0;
            {'EXIT', {function_clause, [{Mod, Fun, _, _Location} | _]}} -> EngineState0;
            {'EXIT', Reason} ->
                erlang:throw({seresye, {rule_execution,
                                       [R, Reason]}});
            EngineState1 -> EngineState1
        end,
    after_execution_schedule(EngineState2).


%% Fun = {Module, Function} or
%% Fun = fun (...)
execute_rule(EngineState, {{M,F}, Args, X1, X2}) ->
    L = length(Args) + 1,
    execute_rule(EngineState, {fun M:F/L, Args, X1, X2});
execute_rule(EngineState, {Fun, Args, _, _}) when is_function(Fun) ->
    case proplists:get_value(before_rule, EngineState#seresye.hooks) of
        BF when is_function(BF) ->
            BF(EngineState, Fun, Args);
        _ ->
            ignore
    end,
    Result = apply(Fun, [EngineState#seresye { fired_rule = {Fun, Args} } | Args]),
    case proplists:get_value(after_rule, EngineState#seresye.hooks) of
        AF when is_function(AF) ->
            AF(Result, Fun, Args);
        _ ->
            ignore
    end,
    Result#seresye{ fired_rule = undefined }.



================================================
FILE: src/seresye_app.erl
================================================
%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine
%%%
%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro
%%% Copyright (c) 2011 Afiniate, Inc.
%%% All rights reserved.
%%%
%%% You may use this file under the terms of the BSD License. See the
%%% license distributed with this project or
%%% http://www.opensource.org/licenses/bsd-license.php
-module(seresye_app).

-behaviour(application).

%% Application callbacks
-export([start/2, stop/1]).

%%%===================================================================
%%% Application callbacks
%%%===================================================================

start(_StartType, _StartArgs) ->
    case seresye_sup:start_link() of
        {ok, Pid} ->
            {ok, Pid};
        Error ->
            Error
                end.

stop(_State) ->
    ok.


================================================
FILE: src/seresye_autoneg.erl
================================================
%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine
%%%
%%% Copyright (c) 2011, Afiniate, Inc.
%%% All rights reserved.
%%%
%%% You may use this file under the terms of the BSD License. See the
%%% license distributed with this project or
%%% http://www.opensource.org/licenses/bsd-license.php
-module(seresye_autoneg).

-export([parse_transform/2]).

parse_transform(Forms, _Options) ->
    {Head, NewAttributes, Body} =
        lists:foldl(fun parse_forms/2, {[], [], []}, Forms),
    lists:reverse(Head) ++ NewAttributes ++ lists:reverse(Body).

parse_forms({function,Line,FunName, Arity, Clauses0}, {Head, Attrs0, Body}) ->
    {_, Clauses2, Attrs2} =
        lists:foldl(fun(Clause0, {ClauseCount, Clauses1, Attrs1}) ->
                            case parse_clause(Clause0) of
                                {false, Clause1} ->
                                    {ClauseCount + 1,
                                     [Clause1 | Clauses1],
                                     Attrs1};
                                {NewDetail, Clause1} ->
                                    {ClauseCount + 1,
                                     [Clause1 | Clauses1],
                                     [{ClauseCount, NewDetail} | Attrs1]}
                            end
                end, {0, [], []}, Clauses0),

    {Head, lists:map(fun({CC, Detail0}) ->
                             {attribute, Line, rule_neg, {FunName, CC, Detail0}}
                     end, Attrs2) ++ Attrs0,
     [{function, Line, FunName, Arity, lists:reverse(Clauses2)} | Body]};
parse_forms(F = {attribute,_,file,_}, {Head, Attrs0, Body}) ->
    {[F | Head], Attrs0, Body};
parse_forms(F = {attribute,_,module,_}, {Head, Attrs, Body}) ->
    {[F | Head], Attrs, Body};
parse_forms(El, {Head, Attrs, Body}) ->
    {Head, Attrs, [El |Body]}.

parse_clause({clause,Line, Args,
              [[{op,_,'not',
                 {tuple, _,
                  [{atom,_,rule}, Neg]}} | AR] | OR],
              Body}) ->
    NewGuards = case AR of
                    [] ->
                        OR;
                    _ ->
                        [AR | OR]
                end,
    {rewrite_negs(Neg), {clause, Line, Args, NewGuards, Body}};
parse_clause(Clause) ->
    {false, Clause}.

rewrite_negs({tuple, L, Elements}) ->
    {tuple, L, lists:map(fun rewrite_negs/1, Elements)};
rewrite_negs(C = {cons, _, _, _}) ->
    rewrite_cons(C);
rewrite_negs({var, Line, '_'}) ->
    {atom, Line, '___IGNORE___'};
rewrite_negs(Else) ->
    Else.

rewrite_cons({cons, Line, Element, nil}) ->
    {cons, Line, rewrite_negs(Element), nil};
rewrite_cons({cons, Line, E1, Rest}) ->
    {cons, Line, rewrite_negs(E1), rewrite_negs(Rest)}.


================================================
FILE: src/seresye_engine.erl
================================================
%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine
%%%
%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro
%%% Copyright (c) 2011 Afiniate, Inc.
%%% All rights reserved.
%%%
%%% You may use this file under the terms of the BSD License. See the
%%% license distributed with this project or
%%% http://www.opensource.org/licenses/bsd-license.php
-module(seresye_engine).

-ifdef(debug).
-define(LOG(F, X), io:format(F, X)).
-else.
-define(LOG(F, X), true).
-endif.

%%====================================================================
%% Include files
%%====================================================================
-include("internal.hrl").

%%====================================================================
%% External exports
%%====================================================================

-export([new/0, new/1, serialize/1, restore/1, cleanup/1,
         set_hooks/2, get_fired_rule/1,
         add_rules/2, add_rule/2, add_rule/3, assert/2, get_kb/1,
         get_rules_fired/1, get_client_state/1, set_client_state/2,
         query_kb/2, remove_rule/2, retract/2]).

%%====================================================================
%% External functions
%%====================================================================
new() ->
    new([]).

new(ClientState) ->
    seresye_agenda:new(#seresye{kb=[], alfa=[],
                              join=seresye_tree_list:new(),
                              pending_actions=[],
                              client_state=ClientState}).

set_hooks(EngineState, Hooks) when is_list(Hooks) ->
    EngineState#seresye{ hooks = Hooks }.

set_client_state(EngineState, NewState) ->
    EngineState#seresye{client_state=NewState}.

get_client_state(#seresye{client_state=State}) ->
    State.

cleanup(#seresye{ alfa = Alfa0, join = Join0 }) ->
    [ begin (catch ets:delete(Tab)), Tab end || {_, Tab, _} <- Alfa0 ] ++
    [ begin (catch ets:delete(Tab)), Tab end || {{Tab, _}, _, _, _, _} <- Join0, is_integer(Tab) ].         

restore(#seresye{ alfa = Alfa0, join = Join0 } = Engine) ->
    TabCache = ets:new(tab_cache, []),
    Alfa = [ {Cond, restore_tab(TabCache, Tab), Alfa_fun}
             || {Cond, Tab, Alfa_fun} <- Alfa0 ],
    Join = [ {case Key of
                  {Tab,V} when element(1,Tab) == ets_table ->
                      {restore_tab(TabCache, Tab), V};
                  _ ->
                      Key
              end, Beta, Children, Parent, Pos} ||
               {Key, Beta, Children, Parent, Pos} <- Join0 ],
    ets:delete(TabCache),
    Engine#seresye{ alfa = Alfa, join = Join }.

serialize(#seresye{ alfa = Alfa0, join = Join0 } = Engine) ->
    Alfa = [ {Cond, serialize_tab(Tab), Alfa_fun} 
             || {Cond, Tab, Alfa_fun} <- Alfa0 ],
    Join = [ {case Key of
                  {Tab,V} when is_integer(Tab) ->
                      {serialize_tab(Tab), V};
                  _ ->
                      Key
              end, Beta, Children, Parent, Pos} ||
               {Key, Beta, Children, Parent, Pos} <- Join0 ],
    Engine#seresye{ alfa = Alfa, join = Join }.
                 
% where
serialize_tab(Tab) ->
    case ets:info(Tab) of
        undefined ->
            Tab;
        Info ->
            {ets_table, Tab, Info, ets:tab2list(Tab)}
    end.
restore_tab(Cache, {ets_table, Tab, Info, Content}) ->
    case ets:lookup(Cache, Tab) of
        [{Tab, NewTab}] ->
            NewTab;
        [] ->
            NewTab = ets:new(proplists:get_value(name, Info),
                             [ proplists:get_value(Opt, Info) ||
                                 Opt <- [type,protection] ] ++
                             [ {Opt, proplists:get_value(Opt, Info)} || 
                                 Opt <- [keypos] ]),
            ets:insert(NewTab, Content),
            ets:insert(Cache, {Tab, NewTab}),
            NewTab
    end;
restore_tab(_Cache, Tab) ->
    Tab.


%% @doc Insert a fact in the KB.
%% It also checks if the fact verifies any condition,
%% if this is the case the fact is also inserted in the alpha-memory
assert(EngineState0, Facts) when is_list(Facts) ->
    lists:foldl(fun(Fact, EngineState1) ->
                        assert(EngineState1, Fact)
                end, EngineState0, Facts);
assert(EngineState = #seresye{kb=Kb, alfa=Alfa}, Fact) when is_tuple(Fact) ->
    execute_pending(case lists:member(Fact, Kb) of
                        false ->
                            Kb1 = [Fact | Kb],
                            check_cond(EngineState#seresye{kb=Kb1}, Alfa,
                                       {Fact, plus});
                        true -> EngineState
                    end).

%% @doc removes a 'fact' in the Knowledge Base and if something occurs
%% Condition is also deleted from the corresponding alpha-memory
retract(EngineState0, Facts) when is_list(Facts) ->
    lists:foldl(fun(Fact, EngineState1) ->
                        retract(EngineState1, Fact)
                end, EngineState0, Facts);
retract(EngineState = #seresye{kb=Kb, alfa=Alfa}, Fact) when is_tuple(Fact) ->
    execute_pending(case lists:member(Fact, Kb) of
                        true ->
                            Kb1 = Kb -- [Fact],
                            check_cond(EngineState#seresye{kb=Kb1}, Alfa,
                                       {Fact, minus});
                        false -> EngineState
                    end).


add_rules(EngineState0, RulesList) when is_list(RulesList) ->
    lists:foldl(fun(Rule, EngineState1) ->
                        add_rule(EngineState1, Rule)
                end, EngineState0, RulesList);
add_rules(EngineState0, Module) when is_atom(Module) ->
    AST = get_abstract_code(Module),
    case get_rules(Module, AST) of
        [] ->
            erlang:throw({seresye, {no_rules_specified, Module}});
        RulesList ->
            lists:foldl(fun(Rule, EngineState1) ->
                                add_rule(EngineState1, Rule)
                        end, EngineState0, RulesList)
    end.

add_rule(EngineState, {Module, Fun, ClauseID, Salience}) ->
    add_rule(EngineState, {Module, Fun}, ClauseID, Salience);
add_rule(EngineState, Fun) ->
    add_rule(EngineState, Fun, 0).

add_rule(EngineState, {Module, Fun, ClauseID}, Salience) ->
    add_rule(EngineState, {Module, Fun}, ClauseID, Salience);
add_rule(EngineState, {Module, Fun}, Salience) ->
    add_rule(EngineState, {Module, Fun}, 0, Salience).

add_rule(EngineState0, {Module, Fun}, ClauseID, Salience) ->
    AST = get_abstract_code(Module),
    case get_conds(Fun, ClauseID, AST) of
        error -> erlang:throw({seresye, {error_extracting_conditions, Fun}});
        CondsList ->
            execute_pending(
              lists:foldl(fun (X, EngineState1) ->
                                  case X of
                                      {error, Msg} ->
                                          erlang:throw({seresye, {error_adding_rule,
                                                         [Module, Fun, Msg]}});
                                      {PConds, NConds} ->
                                          ?LOG(">> PConds=~p~n", [PConds]),
                                          ?LOG(">> NConds=~p~n", [NConds]),
                                          add_rule__(EngineState1,
                                                     {{Module, Fun}, Salience},
                                                     {PConds, NConds})
                                  end
                          end,
                          EngineState0,
                          CondsList))
    end.

remove_rule(EngineState0, Rule) ->
    execute_pending(remove_prod(seresye_agenda:delete_rule(EngineState0, Rule), Rule)).

get_fired_rule(#seresye{ fired_rule = Rule }) ->
    Rule.

get_rules_fired(EngineState) ->
    seresye_agenda:get_rules_fired(EngineState).

get_kb(#seresye{kb=Kb}) ->
    Kb.

query_kb(EngineState, Pattern) when is_tuple(Pattern) ->
    PList = tuple_to_list(Pattern),
    PatternSize = length(PList),
    FunList = [if is_function(X) -> X;
                  X == '_' -> fun (_) -> true end;
                  true -> fun (Z) -> Z == X end
               end
               || X <- PList],
    MatchFunction = fun (P) ->
                            FunPatPairs = lists:zip(FunList, tuple_to_list(P)),
                            FunEval = [F(X) || {F, X} <- FunPatPairs],
                            MatchResult = lists:foldr(fun (X, Y) -> X and Y end,
                                                      true, FunEval),
                            MatchResult
                    end,
    KB = [X
          || X <- get_kb(EngineState), size(X) == PatternSize],
    lists:filter(MatchFunction, KB);

query_kb(Name, F) when is_function(F) ->
    lists:filter(F, get_kb(Name)).

%%====================================================================
%% Internal functions
%%====================================================================
execute_pending(EngineState0 = #seresye{pending_actions=[PA | Rest]}) ->
    EngineState1 = PA(EngineState0#seresye{pending_actions=Rest}),
    execute_pending(EngineState1);
execute_pending(EngineState0 = #seresye{pending_actions=[]}) ->
    EngineState0.

add_rule__(EngineState0 = #seresye{join=Join},
           Rule,
           {PConds, NConds}) when is_tuple(Rule)->
    Root = seresye_tree_list:get_root(Join),
    case NConds of
        [] ->
            make_struct(EngineState0, Rule, PConds, [], Root,
                        nil);
        _ ->
            {EngineState1, Np_node} = make_struct(EngineState0, Rule, NConds, [],
                                                  Root, ng),
            Root1 = seresye_tree_list:refresh(Root,
                                             EngineState1#seresye.join),
            make_struct(EngineState1, Rule, PConds, [], Root1,
                        {Np_node, NConds})
    end.

%% @doc initializes the memory with a new alpha-present the facts
%% In the Knowledge Base that satisfy the condition Cond
initialize_alfa(_, _, []) -> nil;
initialize_alfa(Cond, Tab, [Fact | Other_fact]) ->
    Fun = prepare_match_alpha_fun(Cond),
    case Fun(Fact) of
        Fact ->
            ets:insert(Tab, Fact),
            initialize_alfa(Cond, Tab, Other_fact);
        false -> initialize_alfa(Cond, Tab, Other_fact)
    end.

prepare_match_alpha_fun(Cond) ->
    Expr =
        [{'fun',1,
          {clauses,[{clause,1,
                     [{match,1,Cond,{var,1,'X__x__X'}}],
                     [],
                     [{var,1,'X__x__X'}]},
                    {clause,1,[{var,1,'_'}],[],[{atom,1,false}]}]}}],
    eval(Expr).

get_abstract_code(Module) ->
    case beam_lib:chunks(code:which(Module), [abstract_code]) of
        {error, beam_lib, {file_error, File, enoent}} ->
            erlang:throw({seresye,
                          {unable_to_find_file, Module, File}});
        {ok, {Module, [{abstract_code,no_abstract_code}]}} ->
            erlang:throw({seresye,
                          {no_abstract_code, Module,
                           "module must be compiled with +debug_info"}});
        {ok, {Module, [{abstract_code, {raw_abstract_v1, Forms}}]}} ->
            Forms
    end.

get_conds(FunName, ClauseID, AST) ->
    Records = get_records(AST, []),
    case search_fun(FunName, AST) of
        {error, Reason} ->
            erlang:throw({seresye, {error_parsing_forms,
                                   FunName, Reason}});
        {ok, CL} ->
            if ClauseID > 0 ->
                    [read_clause(FunName, ClauseID,
                                 lists:nth(ClauseID, CL), Records, AST)];
               true ->
                    [read_clause(FunName, ClauseID, Clause, Records, AST) ||
                        Clause <- CL]
            end
    end.

get_records([], Acc) ->
    Acc;
get_records([{attribute, _, record,
              {RecordName, RecordFields}}
             | Tail],
            Acc) ->
    NewAcc = [{RecordName,
               get_record_fields(RecordFields, [])}
              | Acc],
    get_records(Tail, NewAcc);
get_records([_ | Tail], Acc) ->
    get_records(Tail, Acc).

get_record_fields([], Acc) -> lists:reverse(Acc);
get_record_fields([{typed_record_field, RecordField, _T} | Tail], Acc) ->
    get_record_fields([RecordField | Tail], Acc);
get_record_fields([{record_field, _,
                    {atom, _, FieldName}, {nil, _}}
                   | Tail],
                  Acc) ->
    NewAcc = [{FieldName, {nil, []}} | Acc],
    get_record_fields(Tail, NewAcc);
get_record_fields([{record_field, _,
                    {atom, _, FieldName}, {Type, _, DefaultValue}}
                   | Tail],
                  Acc) ->
    NewAcc = [{FieldName, {Type, DefaultValue}} | Acc],
    get_record_fields(Tail, NewAcc);
get_record_fields([{record_field, _,
                    {atom, _, FieldName}}
                   | Tail],
                  Acc) ->
    NewAcc = [{FieldName, {atom, undefined}} | Acc],
    get_record_fields(Tail, NewAcc).


get_rules(Module, AST) ->
    get_rules(Module, AST, []).

get_rules(_Module, [], Acc) ->
    lists:reverse(Acc);
get_rules(Module, [{attribute, _, rule, Rule} | Rest], Acc) ->
    get_rules(Module, Rest, [resolve_rule(Module, Rule) | Acc]);
get_rules(Module, [{attribute, _, rules, RuleList0} | Rest], Acc)
  when is_list(RuleList0) ->
    RuleList1 = [resolve_rule(Module, Rule) || Rule <- RuleList0],
    get_rules(Module, Rest, RuleList1 ++ Acc);
get_rules(Module, [_ | Rest], Acc) ->
    get_rules(Module, Rest, Acc).


resolve_rule(Module, Rule) when is_atom(Rule) ->
    {Module, Rule, 0, 0};
resolve_rule(Module, {Rule, Salience}) ->
    {Module, Rule, 0, Salience};
resolve_rule(Module, {Rule, Salience, ClauseID}) ->
    {Module, Rule, ClauseID, Salience};
resolve_rule(Module, Rule) ->
    erlang:throw({seresye, {invalid_rule_definition, Module, Rule}}).


search_fun([], _) ->
    {error, "function not found"};
search_fun(Func, [{function, _, Func, _, ClauseList} | _Rest]) ->
    {ok, ClauseList};
search_fun( Func, [_Tuple | Rest]) ->
    search_fun(Func, Rest).

read_clause(FunName, ClauseID, Clause, RecordList, AST) ->
    {clause, _, ParamList, _, _} = Clause,
    PosConds = read_parameters(ParamList, RecordList),
    {PosConds, get_neg_conds(FunName, ClauseID, AST)}.

get_neg_conds(FunName0, ClauseID0, AST) ->
    lists:foldl(fun({attribute,_,rule_neg, {FunName1, ClauseID1, Detail}}, _)
                   when ClauseID0 == ClauseID1, FunName0 == FunName1 ->
                        neg_to_list(rewrite_negs(Detail), []);
                   (_, Acc) ->
                        Acc
                end, [], AST).

neg_to_list({cons, _, C1, Rest}, Acc) ->
    neg_to_list(Rest, [C1 | Acc]);
neg_to_list({nil, _}, Acc) ->
    lists:reverse(Acc).


rewrite_negs({tuple, _, Elements}) ->
    {tuple, 0, lists:map(fun rewrite_negs/1, Elements)};
rewrite_negs(C = {cons, _, _, _}) ->
    rewrite_cons(C);
rewrite_negs({atom, _, '___IGNORE___'}) ->
    {var, 0, '_'};
rewrite_negs(Else) ->
    remove_line_numbers(Else).

rewrite_cons({cons, _, Element, nil}) ->
    {cons, 0, rewrite_negs(Element), nil};
rewrite_cons({cons, _, E1, Rest}) ->
    {cons, 0, rewrite_negs(E1), rewrite_negs(Rest)}.

read_parameters([{var, _, _} | Tail], RecordList) ->
    extract_parameters(Tail, RecordList, []).

extract_parameters([], _, Acc) ->
    lists:reverse(Acc);
extract_parameters([{match, _, {record, _, _, _} = R,
                     {var, _, _}}
                    | Tail],
                   RecordList,
                   Acc) ->
    extract_parameters([R | Tail], RecordList, Acc);
extract_parameters([{match, _, Condition,
                     {var, _, _}}
                    | Tail],
                   RecordList,
                   Acc) ->
    extract_parameters(Tail, RecordList, [remove_line_numbers(Condition) | Acc]);
extract_parameters([{match, _, {var, _, _},
                     {record, _, _, _} = R}
                    | Tail],
                   RecordList,
                   Acc) ->
    extract_parameters([R | Tail], RecordList, Acc);
extract_parameters([{match, _, {var, _, _},
                     Condition}
                    | Tail],
                   RecordList,
                   Acc) ->
    extract_parameters(Tail, RecordList, [remove_line_numbers(Condition) | Acc]);
extract_parameters([{record, _, RecordName, Condition}
                    | Tail],
                   RecordList,
                   Acc) ->
    RecordDefinition = get_record_def(RecordName,
                                      RecordList),
    RecordDefaults = make_record_default(RecordDefinition,
                                         []),
    Pattern = {tuple, 0, [{atom, 0, RecordName}
                          | make_record_pattern(Condition, RecordDefaults,
                                                RecordDefinition)]},
    extract_parameters(Tail, RecordList, [Pattern | Acc]);
extract_parameters([{tuple, L, Elements}| Tail], RecordList, Acc) ->
    Pattern = {tuple, L, 
               extract_parameters(Elements, RecordList, [])},
    extract_parameters(Tail, RecordList, [Pattern | Acc]);
extract_parameters([Condition | Tail], RecordList, Acc) ->
    extract_parameters(Tail, RecordList, [remove_line_numbers(Condition) | Acc]).

%% @doc removing the line numbers make it easier to compare conditions
%% for equality
%% Note since OTP 24 (https://github.com/erlang/otp/pull/3006)
%% abstract code contains location conforming to
%% {Line :: integer(), Column :: integer()} format,
%% therefore additional clauses have been added
remove_line_numbers(Values) when is_list(Values) ->
    lists:map(fun remove_line_numbers/1, Values);
remove_line_numbers({op, _, Op, T1, T2}) ->
    {op, 0, Op, remove_line_numbers(T1), remove_line_numbers(T2)};
remove_line_numbers({Type, {L,C}}) % >= OTP24
  when is_integer(L), is_integer(C), is_atom(Type) ->
    remove_line_numbers({Type, L});
remove_line_numbers({Type, L})
  when is_integer(L), is_atom(Type) ->
    {Type, 0};
remove_line_numbers({string, _, String}) ->
    {string, 0, String};
remove_line_numbers({Type, {L, C}, Values}) % >= OTP24
  when is_integer(L), is_integer(C), is_atom(Type), is_list(Values) ->
    remove_line_numbers({Type, L, Values});
remove_line_numbers({Type, L, Values})
  when is_integer(L), is_atom(Type), is_list(Values) ->
    {Type, 0, lists:map(fun remove_line_numbers/1, Values)};
remove_line_numbers({Type, {L, C}, Value}) % >= OTP24
  when is_integer(L), is_integer(C), is_atom(Type) ->
    remove_line_numbers({Type, L, Value});
remove_line_numbers({Type, L, Value})
  when is_integer(L), is_atom(Type) ->
    {Type, 0, Value};
remove_line_numbers({Type, {L, C}, C1, C2})
  when is_integer(L), is_integer(C), is_atom(Type) ->
    remove_line_numbers({Type, L, C1, C2});
remove_line_numbers({Type, L, C1, C2}) % >= OTP24
  when is_integer(L), is_atom(Type) ->
    {Type, 0, remove_line_numbers(C1), remove_line_numbers(C2)}.




get_record_def(_, []) -> nil;
get_record_def(Name, [{Name, Definition} | _Rest]) ->
    Definition;
get_record_def(Name, [_ | Rest]) ->
    get_record_def(Name, Rest).

make_record_default([], Acc) -> lists:reverse(Acc);
make_record_default([{_,_} | Tail], Acc) ->
    make_record_default(Tail, [{var, 0, '_'} | Acc]).

make_record_pattern([], Pattern, _RecordDefinition) ->
    Pattern;
make_record_pattern([{record_field, _,
                      {atom, _, FieldName}, MatchValue}
                     | Tail],
                    Pattern, RecordDefinition) ->
    FieldPosition = get_record_field_pos(FieldName,
                                         RecordDefinition, 1),
    NewPattern = lists:sublist(Pattern, FieldPosition - 1)
        ++
        [MatchValue] ++
        lists:sublist(Pattern, FieldPosition + 1,
                      length(Pattern) - FieldPosition),
    make_record_pattern(Tail, NewPattern, RecordDefinition).

get_record_field_pos(Name, [], _) ->
    exit({bad_record_field, Name});
get_record_field_pos(Name, [{Name, _} | _], Index) ->
    Index;
get_record_field_pos(Name, [{Name} | _], Index) ->
    Index;
get_record_field_pos(Name, [_ | Tail], Index) ->
    get_record_field_pos(Name, Tail, Index + 1).


%% @doc P and a list containing the conditions prior to Cond Of the
%% same production
make_struct(EngineState0 = #seresye{join=Join}, _Rule, [], _P, Cur_node, ng) ->
    %% create production node
    Key = {np_node, nil},
    {Node, {Join2, EngineState1}} =
        case seresye_tree_list:child(Key, Cur_node, Join) of
            false ->
                Value = [],
                {Node0, Join1} = seresye_tree_list:insert(Key, Value,
                                                         Cur_node, Join),
                {Node0, update_new_node(EngineState0, Node0, Cur_node,
                                        Join1)};
            Node0 -> {Node0, {Join, EngineState0}}
        end,
    {EngineState1#seresye{join=Join2}, Node};
make_struct(EngineState0 = #seresye{join=Join}, Rule, [], _P, Cur_node, nil) ->
    %% create production node
    Key = {p_node, Rule},
    {Join2, EngineState1} = case seresye_tree_list:child(Key, Cur_node, Join) of
                                false ->
                                    Value = [],
                                    {Node, Join1} = seresye_tree_list:insert(Key, Value,
                                                                            Cur_node, Join),
                                    update_new_node(EngineState0, Node, Cur_node,
                                                    Join1);
                                Node ->
                                    {Fun, _Salience} = Rule,
                                    Key1 = element(1, Node),
                                    Sal = element(2, element(2, Key1)),
                                    io:format(">> Rule (~w) already present ~n", [Fun]),
                                    io:format(">> with salience = ~w~n", [Sal]),
                                    io:format(">> To change salience use 'set_salience()'.~n"),
                                    {Join, EngineState0}
                            end,
    EngineState1#seresye{join=Join2};
make_struct(EngineState0 = #seresye{join=Join}, Rule, [], P, Cur_node, {Nod, NConds}) ->
    Id = seresye_tree_list:get_id(Nod),
    {Cur_node1, Join1, EngineState1} = make_join_node(EngineState0, Join,
                                                      {old, {n_node, Id}}, NConds, P,
                                                      Cur_node),
    Nod1 = seresye_tree_list:refresh(Nod, Join1),
    Join2 = seresye_tree_list:set_child(Cur_node1, Nod1,
                                       Join1),
    Key = {p_node, Rule},
    {Join4, EngineState2} =
        case seresye_tree_list:child(Key, Cur_node1, Join2) of
            false ->
                Value = [],
                {Node, Join3} = seresye_tree_list:insert(Key, Value,
                                                        Cur_node1, Join2),
                Cur_node2 = seresye_tree_list:refresh(Cur_node1, Join3),
                update_new_node(EngineState1, Node, Cur_node2,
                                Join3);
            Node ->
                {Fun, _Salience} = Rule,
                Key1 = element(1, Node),
                Sal = element(2, element(2, Key1)),
                io:format(">> Rule (~w) already present ~n", [Fun]),
                io:format(">> with salience = ~w~n", [Sal]),
                io:format(">> To change salience use 'set_salience()'.~n"),
                {Join2, EngineState1}
        end,
    EngineState2#seresye{join=Join4};
make_struct(EngineState0 = #seresye{join=Join}, Rule, [Cond | T], P, Cur_node, Nod) ->
    {Alfa1, Tab} = add_alfa(EngineState0, Cond),
    {Cur_node1, Join1, EngineState1} = make_join_node(EngineState0, Join, Tab,
                                                      Cond, P, Cur_node),
    P1 = P ++ [Cond],
    make_struct(EngineState1#seresye{alfa=Alfa1, join=Join1}, Rule, T,
                P1, Cur_node1, Nod).

add_alfa(#seresye{kb=Kb, alfa=Alfa}, Cond) ->
    case is_present(Cond, Alfa) of
        false ->
            Tab = ets:new(alfa, [bag]),
            Fun = [{'fun',1,
                    {clauses,
                     [{clause,1,
                       [Cond],[],[{atom,1,true}]}]}}],
            Alfa_fun = eval(Fun),
            Alfa1 = [{Cond, Tab, Alfa_fun} | Alfa],
            initialize_alfa(Cond, Tab, Kb),
            {Alfa1, {new, Tab}};
        {true, Tab} -> {Alfa, {old, Tab}}
    end.

remove_prod(EngineState0 = #seresye{join=Join}, Fun) ->
    case seresye_tree_list:keysearch({p_node, Fun}, Join) of
        false -> EngineState0;
        Node ->
            Parent_node = seresye_tree_list:get_parent(Node, Join),
            Join1 = seresye_tree_list:remove_node(Node, Join),
            Parent_node1 = seresye_tree_list:refresh(Parent_node,
                                                    Join1),
            EngineState1 = remove_nodes(Parent_node1,
                                        EngineState0#seresye{join=Join1}),
            remove_prod(EngineState1, Fun)
    end.

remove_nodes(Node, EngineState0 = #seresye{join=Join, alfa=Alfa}) ->
    case seresye_tree_list:have_child(Node) of
        false ->
            case seresye_tree_list:is_root(Node) of
                false ->
                    Parent_node = seresye_tree_list:get_parent(Node, Join),
                    Join1 = seresye_tree_list:remove_node(Node, Join),
                    Parent_node1 = seresye_tree_list:refresh(Parent_node,
                                                            Join1),
                    {First, _} = seresye_tree_list:get_key(Node),
                    case First of
                        {n_node, IdNp_node} ->
                            ParentKey = seresye_tree_list:get_key(Parent_node1),
                            %% delete all nodes of the conditions negated
                            Np_node = seresye_tree_list:get_node(IdNp_node, Join1),
                            Join2 = seresye_tree_list:remove_child(Node, Np_node,
                                                                  Join1),
                            Np_node1 = seresye_tree_list:refresh(Np_node, Join2),
                            EngineState1 = remove_nodes(Np_node1, EngineState0#seresye{join=Join2}),
                            %% Recovery of the parent node of the node passed as an argument n_node
                            %% The parent can now have a different id, but has the same key
                            Join3 = EngineState1#seresye.join,
                            Parent_node2 = seresye_tree_list:keysearch(ParentKey,
                                                                      Join3),
                            remove_nodes(Parent_node2, EngineState1);
                        np_node ->
                            remove_nodes(Parent_node1, EngineState0#seresye{join=Join1});
                        Tab ->
                            Alfa1 = case seresye_tree_list:is_present(Tab, Join1) of
                                        false ->
                                            ets:delete(Tab),
                                            lists:keydelete(Tab, 2, Alfa);
                                        true ->
                                            Alfa
                                    end,
                            remove_nodes(Parent_node1,
                                         EngineState0#seresye{alfa=Alfa1,
                                                             join=Join1})
                    end;
                true -> EngineState0
            end;
        true -> EngineState0
    end.

%% @doc occurs and if the condition Cond is present
is_present(_Cond, []) -> false;
is_present(Cond, [{C1, Tab, _Alfa_fun} | Other_cond]) ->
    case same_cond(Cond, C1) of
        true -> {true, Tab};
        false -> is_present(Cond, Other_cond)
    end.

same_cond(Cond, Cond) -> true;
same_cond(_Cond1, _Cond2) -> false.

eval(Expr) ->
    ?LOG("FUN = ~p~n", [String]),
    case catch erl_eval:exprs(Expr, erl_eval:new_bindings()) of
        {'EXIT', _} -> false;
        {value, Value, _Bindings} -> Value;
        _ -> false
    end.

prepare_fun(_Cond, []) -> [{atom, 1, nil}];
prepare_fun(Cond0, Cond1)
  when not is_list(Cond0), is_list(Cond1) ->
       [{'fun',1,
         {clauses,
          [{clause,1,
            [Cond0,
             prepare_rest(Cond1)],
            [],
            [{atom,1,true}]}]}}];
prepare_fun(Cond0, Cond1)
  when is_list(Cond0), is_list(Cond1) ->
       [{'fun',1,
         {clauses,
          [{clause,1,
            [prepare_rest(Cond0),
             prepare_rest(Cond1)],
            [],
            [{atom,1,true}]}]}}].

prepare_rest([Element | Rest]) ->
    {cons, 1, Element, prepare_rest(Rest)};
prepare_rest([]) ->
    {nil, 1}.

%% @doc join_node entering any new updates in the beta-token memory
update_new_node(EngineState0, Node, Parent_node, Join) ->
    case seresye_tree_list:is_root(Parent_node) of
        false ->
            Children = seresye_tree_list:children(Parent_node, Join),
            case Children -- [Node] of
                [] ->
                    case seresye_tree_list:get_key(Parent_node) of
                        {{n_node, _IdNp_node}, _Join_fun} ->
                            Beta = seresye_tree_list:get_beta(Parent_node),
                            update_from_n_node(EngineState0, Parent_node, Beta, Join);
                        {Tab, _} ->
                            Fact_list = ets:tab2list(Tab),
                            update_new_node(EngineState0, Node, Parent_node, Join, Fact_list)
                    end;
                [Child | _Other_child] ->
                    Beta = seresye_tree_list:get_beta(Child),
                    Join1 = seresye_tree_list:update_beta(Beta, Node, Join),
                    EngineState1 =
 
Download .txt
gitextract_cfewqrrs/

├── .gitignore
├── LICENSE.md
├── README.md
├── do-gh-pages
├── doc/
│   ├── CNAME
│   ├── _layouts/
│   │   └── default.html
│   ├── assets/
│   │   ├── css/
│   │   │   ├── code.css
│   │   │   ├── prettify.css
│   │   │   ├── skeleton/
│   │   │   │   ├── 404.html
│   │   │   │   ├── index.html
│   │   │   │   ├── javascripts/
│   │   │   │   │   └── tabs.js
│   │   │   │   ├── robots.txt
│   │   │   │   └── stylesheets/
│   │   │   │       ├── base.css
│   │   │   │       ├── layout.css
│   │   │   │       └── skeleton.css
│   │   │   └── style.css
│   │   └── javascript/
│   │       ├── html5.js
│   │       ├── lang-apollo.js
│   │       ├── lang-clj.js
│   │       ├── lang-css.js
│   │       ├── lang-go.js
│   │       ├── lang-hs.js
│   │       ├── lang-lisp.js
│   │       ├── lang-lua.js
│   │       ├── lang-ml.js
│   │       ├── lang-n.js
│   │       ├── lang-proto.js
│   │       ├── lang-scala.js
│   │       ├── lang-sql.js
│   │       ├── lang-tex.js
│   │       ├── lang-vb.js
│   │       ├── lang-vhdl.js
│   │       ├── lang-wiki.js
│   │       ├── lang-xq.js
│   │       ├── lang-yaml.js
│   │       └── prettify.js
│   └── index.md
├── examples/
│   ├── seresye_phil.erl
│   ├── seresye_prodcons.erl
│   └── seresyee_auto.erl
├── features/
│   ├── seresyet_12.feature
│   └── seresyet_13.feature
├── include/
│   └── seresye.hrl
├── rebar.config
├── sinan.config
├── src/
│   ├── internal.hrl
│   ├── seresye.app.src
│   ├── seresye.erl
│   ├── seresye_agenda.erl
│   ├── seresye_app.erl
│   ├── seresye_autoneg.erl
│   ├── seresye_engine.erl
│   ├── seresye_speedtest.erl
│   ├── seresye_sup.erl
│   ├── seresye_transform.erl
│   └── seresye_tree_list.erl
└── test/
    ├── seresyet_12.erl
    ├── seresyet_13.erl
    ├── seresyet_cannibals.erl
    ├── seresyet_relatives.erl
    ├── seresyet_sample.erl
    ├── seresyet_sieve.erl
    └── seresyet_simple_relatives.erl
Download .txt
SYMBOL INDEX (10 symbols across 1 files)

FILE: doc/assets/javascript/prettify.js
  function L (line 2) | function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var...
  function M (line 6) | function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.classN...
  function B (line 7) | function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}
  function x (line 7) | function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(...
  function u (line 9) | function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''...
  function D (line 12) | function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.clas...
  function k (line 15) | function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(...
  function C (line 15) | function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-m...
  function E (line 15) | function E(a){var m=
  function m (line 25) | function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Inf...
Condensed preview — 63 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (257K chars).
[
  {
    "path": ".gitignore",
    "chars": 42,
    "preview": "_build\nerl_crash.dump\ndoc/_site\ndeps\nebin\n"
  },
  {
    "path": "LICENSE.md",
    "chars": 1504,
    "preview": "BSD License\n===========\n\nCopyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro\nAll rights reserved.\n\nRedistributio"
  },
  {
    "path": "README.md",
    "chars": 14166,
    "preview": "SERESYE - Swarm oriented ERlang Expert SYstem Engine\n====================================================\n\nIntroduction\n"
  },
  {
    "path": "do-gh-pages",
    "chars": 243,
    "preview": "#!/bin/sh\n\nPARENT_SHA=$(git show-ref -s refs/heads/gh-pages)\nDOC_SHA=$(git ls-tree -d HEAD doc | awk '{print $3}')\nNEW_C"
  },
  {
    "path": "doc/CNAME",
    "chars": 11,
    "preview": "seresye.org"
  },
  {
    "path": "doc/_layouts/default.html",
    "chars": 3466,
    "preview": "<!DOCTYPE html>\n<html lang='en'>\n  <head>\n    <title>{{ page.title }}</title>\n    <meta http-equiv='Content-Type' conten"
  },
  {
    "path": "doc/assets/css/code.css",
    "chars": 3684,
    "preview": ".highlight .hll { background-color: #ffffcc }\n.highlight  { background: #ffffff; }\n.highlight .c { color: #999988; font-"
  },
  {
    "path": "doc/assets/css/prettify.css",
    "chars": 675,
    "preview": ".pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,"
  },
  {
    "path": "doc/assets/css/skeleton/404.html",
    "chars": 1680,
    "preview": "<!DOCTYPE html>\n<!--[if lt IE 7 ]><html class=\"ie ie6\" lang=\"en\"> <![endif]-->\n<!--[if IE 7 ]><html class=\"ie ie7\" lang="
  },
  {
    "path": "doc/assets/css/skeleton/index.html",
    "chars": 3561,
    "preview": "<!DOCTYPE html>\n<!--[if lt IE 7 ]><html class=\"ie ie6\" lang=\"en\"> <![endif]-->\n<!--[if IE 7 ]><html class=\"ie ie7\" lang="
  },
  {
    "path": "doc/assets/css/skeleton/javascripts/tabs.js",
    "chars": 842,
    "preview": "/*\n* Skeleton V1.1\n* Copyright 2011, Dave Gamache\n* www.getskeleton.com\n* Free to use under the MIT license.\n* http://ww"
  },
  {
    "path": "doc/assets/css/skeleton/robots.txt",
    "chars": 107,
    "preview": "# www.robotstxt.org/\n# www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449\n\nUser-agent: *\n\n"
  },
  {
    "path": "doc/assets/css/skeleton/stylesheets/base.css",
    "chars": 10512,
    "preview": "/*\n* Skeleton V1.1\n* Copyright 2011, Dave Gamache\n* www.getskeleton.com\n* Free to use under the MIT license.\n* http://ww"
  },
  {
    "path": "doc/assets/css/skeleton/stylesheets/layout.css",
    "chars": 1744,
    "preview": "/*\n* Skeleton V1.1\n* Copyright 2011, Dave Gamache\n* www.getskeleton.com\n* Free to use under the MIT license.\n* http://ww"
  },
  {
    "path": "doc/assets/css/skeleton/stylesheets/skeleton.css",
    "chars": 9546,
    "preview": "/*\n* Skeleton V1.1\n* Copyright 2011, Dave Gamache\n* www.getskeleton.com\n* Free to use under the MIT license.\n* http://ww"
  },
  {
    "path": "doc/assets/css/style.css",
    "chars": 4051,
    "preview": "/**\n * A clean concise theme for your GitHub projects\n *\n * Licenced under GPL v3\n * http://www.gnu.org/licenses/gpl.htm"
  },
  {
    "path": "doc/assets/javascript/html5.js",
    "chars": 2051,
    "preview": "// html5shiv @rem remysharp.com/html5-enabling-script\n// iepp v1.6.2 @jon_neal iecss.com/print-protector\n// Dual license"
  },
  {
    "path": "doc/assets/javascript/lang-apollo.js",
    "chars": 986,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"com\",/^#[^\\n\\r]*/,null,\"#\"],[\"pln\",/^[\\t\\n\\r \\xa0]+/,null,\"\\t\\n\\r \\xa0\"],"
  },
  {
    "path": "doc/assets/javascript/lang-clj.js",
    "chars": 1444,
    "preview": "/*\n Copyright (C) 2011 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use th"
  },
  {
    "path": "doc/assets/javascript/lang-css.js",
    "chars": 861,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"pln\",/^[\\t\\n\\f\\r ]+/,null,\" \\t\\r\\n\f\"]],[[\"str\",/^\"(?:[^\\n\\f\\r\"\\\\]|\\\\(?:\\r"
  },
  {
    "path": "doc/assets/javascript/lang-go.js",
    "chars": 281,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"pln\",/^[\\t\\n\\r \\xa0]+/,null,\"\\t\\n\\r \\xa0\"],[\"pln\",/^(?:\"(?:[^\"\\\\]|\\\\[\\S\\s"
  },
  {
    "path": "doc/assets/javascript/lang-hs.js",
    "chars": 569,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"pln\",/^[\\t-\\r ]+/,null,\"\\t\\n\u000b\f\\r \"],[\"str\",/^\"(?:[^\\n\\f\\r\"\\\\]|\\\\[\\S\\s])*("
  },
  {
    "path": "doc/assets/javascript/lang-lisp.js",
    "chars": 755,
    "preview": "var a=null;\nPR.registerLangHandler(PR.createSimpleLexer([[\"opn\",/^\\(+/,a,\"(\"],[\"clo\",/^\\)+/,a,\")\"],[\"com\",/^;[^\\n\\r]*/,a"
  },
  {
    "path": "doc/assets/javascript/lang-lua.js",
    "chars": 551,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"pln\",/^[\\t\\n\\r \\xa0]+/,null,\"\\t\\n\\r \\xa0\"],[\"str\",/^(?:\"(?:[^\"\\\\]|\\\\[\\S\\s"
  },
  {
    "path": "doc/assets/javascript/lang-ml.js",
    "chars": 1104,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"pln\",/^[\\t\\n\\r \\xa0]+/,null,\"\\t\\n\\r \\xa0\"],[\"com\",/^#(?:if[\\t\\n\\r \\xa0]+("
  },
  {
    "path": "doc/assets/javascript/lang-n.js",
    "chars": 1400,
    "preview": "var a=null;\nPR.registerLangHandler(PR.createSimpleLexer([[\"str\",/^(?:'(?:[^\\n\\r'\\\\]|\\\\.)*'|\"(?:[^\\n\\r\"\\\\]|\\\\.)*(?:\"|$))/"
  },
  {
    "path": "doc/assets/javascript/lang-proto.js",
    "chars": 302,
    "preview": "PR.registerLangHandler(PR.sourceDecorator({keywords:\"bytes,default,double,enum,extend,extensions,false,group,import,max,"
  },
  {
    "path": "doc/assets/javascript/lang-scala.js",
    "chars": 914,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"pln\",/^[\\t\\n\\r \\xa0]+/,null,\"\\t\\n\\r \\xa0\"],[\"str\",/^\"(?:\"\"(?:\"\"?(?!\")|[^\""
  },
  {
    "path": "doc/assets/javascript/lang-sql.js",
    "chars": 1685,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"pln\",/^[\\t\\n\\r \\xa0]+/,null,\"\\t\\n\\r \\xa0\"],[\"str\",/^(?:\"(?:[^\"\\\\]|\\\\.)*\"|"
  },
  {
    "path": "doc/assets/javascript/lang-tex.js",
    "chars": 284,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"pln\",/^[\\t\\n\\r \\xa0]+/,null,\"\\t\\n\\r \\xa0\"],[\"com\",/^%[^\\n\\r]*/,null,\"%\"]]"
  },
  {
    "path": "doc/assets/javascript/lang-vb.js",
    "chars": 1700,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"pln\",/^[\\t\\n\\r \\xa0\\u2028\\u2029]+/,null,\"\\t\\n\\r \\xa0

\"],[\"str\",/^(?:[\"\\u"
  },
  {
    "path": "doc/assets/javascript/lang-vhdl.js",
    "chars": 1448,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"pln\",/^[\\t\\n\\r \\xa0]+/,null,\"\\t\\n\\r \\xa0\"]],[[\"str\",/^(?:[box]?\"(?:[^\"]|\""
  },
  {
    "path": "doc/assets/javascript/lang-wiki.js",
    "chars": 542,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"pln\",/^[\\d\\t a-gi-z\\xa0]+/,null,\"\\t \\xa0abcdefgijklmnopqrstuvwxyz01234567"
  },
  {
    "path": "doc/assets/javascript/lang-xq.js",
    "chars": 23242,
    "preview": "PR.registerLangHandler(PR.createSimpleLexer([[\"var pln\",/^\\$[\\w-]+/,null,\"$\"]],[[\"pln\",/^[\\s=][<>][\\s=]/],[\"lit\",/^@[\\w-"
  },
  {
    "path": "doc/assets/javascript/lang-yaml.js",
    "chars": 412,
    "preview": "var a=null;\nPR.registerLangHandler(PR.createSimpleLexer([[\"pun\",/^[:>?|]+/,a,\":|>?\"],[\"dec\",/^%(?:YAML|TAG)[^\\n\\r#]+/,a,"
  },
  {
    "path": "doc/assets/javascript/prettify.js",
    "chars": 13632,
    "preview": "var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;\n(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92"
  },
  {
    "path": "doc/index.md",
    "chars": 14319,
    "preview": "---\nlayout: default\ntitle: Swarm oriented ERlang Expert SYstem Engine\n---\n\nIntroduction\n------------\n\nSERESYE is a Rete "
  },
  {
    "path": "examples/seresye_phil.erl",
    "chars": 1711,
    "preview": "%%%  SERESYE, an ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro\n%%% All"
  },
  {
    "path": "examples/seresye_prodcons.erl",
    "chars": 1032,
    "preview": "%%%  ERESYE, an ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro\n%%% All "
  },
  {
    "path": "examples/seresyee_auto.erl",
    "chars": 9162,
    "preview": "%%%  SERESYE, an ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado Santoro\n%%% All"
  },
  {
    "path": "features/seresyet_12.feature",
    "chars": 569,
    "preview": "Feature: Support explicit state passing in an seresye system\n  In order to make callbacks more easily accessible and les"
  },
  {
    "path": "features/seresyet_13.feature",
    "chars": 498,
    "preview": "Feature: Support defining rules via module attributes\n  In order to seresye more usable\n  As an Erlang Developer\n  I wan"
  },
  {
    "path": "include/seresye.hrl",
    "chars": 312,
    "preview": "%% Parse transforms for automatic creating negative specs for rules in\n%% a rules file. though the user can write them i"
  },
  {
    "path": "rebar.config",
    "chars": 297,
    "preview": "{deps, \n  [\n   {edown, \".*\", {git, \"https://github.com/uwiger/edown.git\", {branch, \"master\"}}},\n   {erlware_commons, \".*"
  },
  {
    "path": "sinan.config",
    "chars": 330,
    "preview": "{project_name, seresye}.\n{project_vsn, \"0.0.4\"}.\n\n{compile_args, [debug_info, warnings_as_errors,\n               {warn_f"
  },
  {
    "path": "src/internal.hrl",
    "chars": 99,
    "preview": "-record(seresye, {kb, alfa, join, agenda, pending_actions, client_state, fired_rule, hooks = []}).\n"
  },
  {
    "path": "src/seresye.app.src",
    "chars": 420,
    "preview": "%% -*- mode: Erlang; fill-column: 75; comment-column: 50; -*-\n\n{application, seresye,\n [{description, \"SERESYE means Swa"
  },
  {
    "path": "src/seresye.erl",
    "chars": 7097,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado S"
  },
  {
    "path": "src/seresye_agenda.erl",
    "chars": 13616,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado S"
  },
  {
    "path": "src/seresye_app.erl",
    "chars": 831,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado S"
  },
  {
    "path": "src/seresye_autoneg.erl",
    "chars": 2706,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2011, Afiniate, Inc.\n%%% All rights res"
  },
  {
    "path": "src/seresye_engine.erl",
    "chars": 41400,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado S"
  },
  {
    "path": "src/seresye_speedtest.erl",
    "chars": 1510,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado S"
  },
  {
    "path": "src/seresye_sup.erl",
    "chars": 1582,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado S"
  },
  {
    "path": "src/seresye_transform.erl",
    "chars": 2105,
    "preview": "-module(seresye_transform).\n-export([parse_transform/2]).\n\n-record(state,{ \n          rules = [],\n          rule_functio"
  },
  {
    "path": "src/seresye_tree_list.erl",
    "chars": 6583,
    "preview": "%%%  SERESYE, an Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado "
  },
  {
    "path": "test/seresyet_12.erl",
    "chars": 2218,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2011, Afiniate, Inc.\n%%% All rights res"
  },
  {
    "path": "test/seresyet_13.erl",
    "chars": 1967,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2011 Afiniate, Inc.\n%%% All rights rese"
  },
  {
    "path": "test/seresyet_cannibals.erl",
    "chars": 7749,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado S"
  },
  {
    "path": "test/seresyet_relatives.erl",
    "chars": 7853,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado S"
  },
  {
    "path": "test/seresyet_sample.erl",
    "chars": 2784,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado S"
  },
  {
    "path": "test/seresyet_sieve.erl",
    "chars": 2262,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado S"
  },
  {
    "path": "test/seresyet_simple_relatives.erl",
    "chars": 3495,
    "preview": "%%%  SERESYE, a Swarm oriented ERlang Expert SYstem Engine\n%%%\n%%% Copyright (c) 2005-2010, Francesca Gangemi, Corrado S"
  }
]

About this extraction

This page contains the full source code of the afiniate/seresye GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 63 files (238.8 KB), approximately 70.4k tokens, and a symbol index with 10 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!