---
project
  session
version
  1.0.0
links
  []
unit
  struct
info

  # TODO

  * Add a function, say `Session.toQuiz : Type.list (SESSION) --> Html.Code.DOCUMENT` that returns an interactive questionnaire.

  <div style="color:red;">........................CONTINUEHERE............................................</div>


  # Overview

                    Data.Moral.type(SESSION)
                     ↗          \
                    /            \
      fromFlatCode /              \  Data.Moral.goodValue
                  /                \
                 /                  ↘          runnerCode
         FLAT_CODE  ←⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯  SESSION ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯→  code : EcmaScript.CODE
                      toFlatCode        |                 /
                                        |               /
                                        |             /
                                    run |           /  code(session)
                                        |         /
                                        |       /
                                        ↓     ↙
                                     SESSION
                                        |
                                        |
                             bugChecker |
                                        |
                                        ↓             bugSummary
                                     SESSION  ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯→  Type.nullify(Type.MARKDOWN)
                                        |
                                        |
                                        | allMarkdownToHtml
                                        | toHtml
                                        |
                                        ↓
                                      Data.HTML


  # Syntax

  ## Syntax rules

  ### `SESSION` syntax

  ----------   ---   -----------------------------------------------
  `SESSION`    ::=   `Type.list (Type.or (SESSION_STEP) (DOC_STEP))`
  ----------   ---   -----------------------------------------------


  ### `SESSION_STEP` syntax

  Each `SESSION_STEP` is a record with the following properties:

  ---------------------------  -----------------------------------
  `id`                         `EcmaScript.ID`
  **`input`**                  **`EcmaScript.CODE`**
  `output`                     `ANYTHING`
  `__output__`                 `ANYTHING`
  `error`                      `STRING`
  `__error__`                  `STRING`
  `__bug__`                    `Type.nullify(Data.Moral.type(STRING))`
  ---------------------------  ------------------------------------

  Note, that

  * Only `input` is a mandatory property, the others are all optional.
  * There is at most one of the two properties `output` or `error`; and also at most one of the two properties `__output__` or `__error__`.


  ### `DOC_STEP` syntax

  ---------------------------  --------------------------
  `doc`                        `Type.MARKDOWN`
  `__doc__`                    `Data.HTML`
  ---------------------------  --------------------------

  ## Legend

  * `id`, `input`, `output`, `error` and `doc` are __user-defined__ properties.
  * `__output__`, `__error__`, `__bug__` and `__doc__` are __machine-generated__ properties.
  * `__output__` is the __real output__, `__error__` is the __real error__, `output` is the __predicted output__ and `error` is the __predicted error__.


  # Notes

  * Consider the advise to only use identifiers with a single initial `_` as variables in sessions.

  * Note, that our symbol `◀` for input, `▶` for output and `❌` for error are similar to the ones of Firebug.
      The prompt `>` of Node.js is a kind of input symbol, took, but goes into the opposite direction.

  * Note, that our (named) input statement `["in", x, expr]` does not translate in node to

          > x = expr
          > var x = expr          // alteratively

       but to

          > (x = expr, x)
          > (var x = expr, x)     // alternatively

       The former is a statement and evaluates to `undefined`, the latter is an expression and evaluates to the value of `x`.

  ## FlatCode

  Each session is list of session steps and doc steps, and each of these steps is a string record.
  So, generally speaking, each session is a **String Record List**, i.e. each `SESSION` value is a `Type.list(Type.record(STRING))` value.

  In the `flatcode.tofu` we already defined **Flat Code**, which is a more convenient form to edit String Record Lists.
  A String Record List

      [ { a_1 : "AAA111",
          a_2 : "AAA222",
          a_3 : "AAA333" },
        { b_1 : "BBB111",
          b_2 : "BBB222" },
        { c_1 : "C1",
          c_2 : "CC22",
          c_3 : "CCC333" } ]

  can equivalently be represented by the FlatCode string

      '---\na_1\n  AAA111\na_2\n  AAA222\na_3\n  AAA333\n---\nb_1\n  BBB111\nb_2\n  BBB222\n---\nc_1\n  C1\nc_2\n  CC22\nc_3\n  CCC333\n---\n'

  which is displayed as

      ╭─────────╮
      │---↵     │
      │a_1↵     │
      │  AAA111↵│
      │a_2↵     │
      │  AAA222↵│
      │a_3↵     │
      │  AAA333↵│
      │---↵     │
      │b_1↵     │
      │  BBB111↵│
      │b_2↵     │
      │  BBB222↵│
      │---↵     │
      │c_1↵     │
      │  C1↵    │
      │c_2↵     │
      │  CC22↵  │
      │c_3↵     │
      │  CCC333↵│
      │---↵     │
      │         │
      ╰─────────╯

  If `strRecL` is the given String Record List, the according Flat Code can be generated by

      FlatCode.fromStringRecordList (strRecL)

  The rules for this conversion are:

  * each key-value pair `key: str` is written on a line with `key` and `str`, indented by two spaces on the next line

          ╭───────╮
          │key↵   │
          │  str1↵│
          ╰───────╯
  * the String Record List `[r_1,...,r_n]` itself is then displayed as a horizontal sequence of blocks, separated by horizontal Markdown lines, i.e. lines starting with three or more dashes `---`.

          ╭──────╮
          │---↵  │
          │r_1↵  │
          │---↵  │
          │r_2↵  │
          │---↵  │
          │r_3↵  │
          │---↵  │
          ╰──────╯

  The conversions are done by

                    fromFlatCode                      Data.Moral.goodValue
        FLAT_CODE ----------------> Data.Moral.type(Session) -------------------> SESSION


                                       toFlatCode
        SESSION  -----------------------------------------------------> FLAT_CODE


  # Appendix: Symbols

  Symbol    Unicode/JS    HTML
  --------  -----------  ---------------
  `|`       `"\u007c"`   `&#124;`
  `⎯`       `"\u23af"`   `&#9135;`
  `←`       `"\u2190"`   `&#8592;`
  `↑`       `"\u2191"`   `&#8593;`
  `→`       `"\u2192"`   `&#8594;`
  `↓`       `"\u2193"`   `&#8595;`
  `↖`       `"\u2196"`   `&#8598;`
  `↗`       `"\u2197"`   `&#8599;`
  `↘`       `"\u2198"`   `&#8600;`
  `↙`       `"\u2199"`   `&#8601;`
---


---
// Session ////////////////////////////////////////////////////////////////////////////////////////
---
unit
  struct
name
  Session
info
  The `Session` structure provides data types and functions that allow to conveniently display, run, test and document entire JavaScript sessions.

  This provides a testing system for JavaScript programs and a more expressive and comprehensible alternative to
  [assertion testing](http://en.wikipedia.org/wiki/Assertion_(software_development)) in say
  [Node.js](http://nodejs.org/api/assert.html) or
  [Dart](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#assert).

  # Introduction

  Some [JavaScript engines](http://en.wikipedia.org/wiki/JavaScript_engine) provide an interactive __Read-Eval-Print-Loop__ feature,
  where the user can input expressions and statements and the machine immediately evaluates and prints the results.
  Examples of these interactive dialog systems are the
  [REPL of Node.js](http://nodejs.org/api/repl.html) or the console of
  [Firebug](http://getfirebug.com/logging) or in
  [Chrome](https://developer.chrome.com/devtools/docs/console).
  An actual example of such a dialog is what we call a __session__.

  A typical example of a session is this

      ........

---
unit
  type
name
  Session.SESSION_STEP
value
  Type.synonym ([
    'Session.SESSION_STEP',
    Type.modelPlus (Rec.create ({ input       : EcmaScript.CODE            }))
                   (Rec.create ({ id          : EcmaScript.ID,
                                  output      : ANYTHING,
                                  error       : STRING,               // only either `output` or `error` must occur
                                  __output__  : ANYTHING,
                                  __error__   : STRING,               // only either `__output__` or `__error__` must occur
                                  __bug__     : Type.nullify(Data.Moral.type(STRING)) }))
  ])
info
  ....
---
unit
  type
name
  Session.DOC_STEP
value
  Type.synonym ([
    'Session.DOC_STEP',
    Type.modelPlus (Rec.create ({ doc     : Type.MARKDOWN }))
                   (Rec.create ({ __doc__ : Data.HTML     }))
  ])
---
unit
  type
name
  Session.SESSION
value
  Type.synonym ([
    'Session.SESSION',
    Type.list (Type.or (SESSION_STEP) (DOC_STEP))
  ])
---
unit
  value
name
  Session.defaultId
type
  EcmaScript.ID
value
  '_'
---
unit
  function
name
  Session.fromFlatCode
type
  Type.function ([FLAT_CODE, Data.Moral.type(SESSION)])
value
  function (flatCode) {
    var result = FlatCode.parseStringRecordList (flatCode);  // `result` is of type `Data.Moral.type(Type.list(Type.record(STRING)))`
    if (Data.Moral.isBad (result)) {
      return Data.Moral.bad (
        "`Session.fromFlatCode(flatCode)` error, when trying to convert `flatCode` into a string record list:\n" +
        Data.Moral.badValue (result)
      );
    } else {
      var recL = Data.Moral.goodValue (result);    // `recL` is here of type `Type.list (Type.record (STRING))`
      // change all `output` and `__output__` properties from type `STRING` to type `ANYTHING`
      for (var i = 0; i < recL.length; i++) {
        if ('output' in recL[i]) {
          try {
            var x = Val.read (recL[i]['output']);
            recL[i]['output'] = x;
          } catch (e) {
            return Data.Moral.bad ( "`Session.fromFlatCode(flatCode)` error, the `output` value `"
                             + recL[i]['output'] + "` in the step `" + i + "` does not parse to a value." )
          }
        }
        if ('__output__' in recL[i]) {
          try {
            var x = Val.read (recL[i]['__output__']);
            recL[i]['__output__'] = x;
          } catch (e) {
            return Data.Moral.bad ( "`Session.fromFlatCode(flatCode)` error, the `__output__` value `"
                             + recL[i]['__output__'] + "` in the step `" + i + "` does not parse to a value." )
          }
        }
      }
      // verify that `recL` is a session
      var c = SESSION.complain (recL);
      if (c) {
        return Data.Moral.bad ( "`Session.fromFlatCode(flatCode)` error.\n"
                         + "`flatCode` does convert into a string record list, which is not a proper `SESSION`, however:\n"
                         + c );
      } else {
        return Data.Moral.good (recL);
      }
    }
  }
info
  `Session.fromFlatCode (flatCode)` returns either of the following two forms:

  * `{good: session}`, if `flatCode` does convert into a proper `SESSION` value (namely `session`), or

  * `{bad: message}`, if it does not, where `message` is a string giving an explanation.
---
unit
  function
name
  Session.toFlatCode
type
  Type.lambda ([SESSION, FLAT_CODE])
value
  function (session) {
    var recL = [];
    for (var i = 0; i < session.length; i++) {
      var rec = Val.clone (session [i]);
      if ('output' in rec) {
        rec.output = Literal.block (output);
      }
      recL.push (rec);
    }
    return FlatCode.fromStringRecordList (recL);
  }
info
  ....
---
unit
  value
name
  Session.run
type
  $prod1 ([SESSION, SESSION])
value
  function (session) {
    session = Val.clone (session);
    for (var i = 0; i < session.length; i++) {
      if ('input' in session[i]) {
        var step = session[i];
        var id = ('id' in step ? step.id : defaultId);
        try {
          eval ("var " + id + " = " + step.input + ";");
          var __output__ = eval (id);
          step.__output__ = __output__;
        } catch (e) {
          step.__error__ = e.toString();
        }
      }
    }
    return session;
  }
info
  `Session.run(session)` evaluates the given `session` in the current environment and returns (a clone of) the same `session` again, but with boosted session steps.

  For example,

      > Session.run ([{input: '12 * 23'}])
      { input: '12 * 23', __output__: '276' }

---
unit
  function
name
  Session.runnerCode
type
  Type.lambda ([SESSION, $literal ($prod0 (SESSION))])
value
  function (session) {
    var code = "var __session__ =" + "\n"
             + Str.indent(2)(Literal.block (session)) + ";\n";
    for (var i = 0; i < session.length; i++) {
      if ('input' in session[i]) {
        var step = session[i];
        var id = ('id' in step ? step.id : defaultId);
        code += "try {"                                              + "\n"
             +  "  var " + id + " ="                                 + "\n"
             +       Str.indent(4)(step.input) + ";"                 + "\n"
             +  "  __session__[" + i  + "].__output__ = " + id + ";" + "\n"
             +  "} catch (e) {"                                      + "\n"
             +  "  __session__[" + i + "].__error__ = e.toString();" + "\n"
             +  "}"                                                  + "\n";
      }
    }
    return ( "(function () {\n"
           +    Str.indent(2)(code)
           + "  return __session__;\n"
           + "}())" );
  }
info
  `Session.runner(session)` takes a `session` and returns the code of a self-calling closure function.
  When this code is evaluated, it returns the given `session`, but boosted by additional `__output__` or `__error__` properties for each session step.

  For example, let `session1` be the `SESSION` value given by

      [ { doc: 'A simple session example' },
        { input: '12 + 34' },
        { id: '_x',
          input: '123' },
        { id: '_y',
          input: '234' },
        { input: '_x + _y' } ]


  then `Session.runnerCode(session1)` returns

      ╭────────────────────────────────────────────╮
      │(function () {↵                             │
      │  var __session__ =↵                        │
      │    [ { doc : "A simple session example" },↵│
      │      { input : "12 + 34" },↵               │
      │      { id    : "_x",↵                      │
      │        input : "123" },↵                   │
      │      { id    : "_y",↵                      │
      │        input : "234" },↵                   │
      │      { input : "_x + _y" } ];↵             │
      │  try {↵                                    │
      │    var _ =↵                                │
      │      12 + 34;↵                             │
      │    __session__[1].__output__ = _;↵         │
      │  } catch (e) {↵                            │
      │    __session__[1].__error__ = e;↵          │
      │  }↵                                        │
      │  try {↵                                    │
      │    var _x =↵                               │
      │      123;↵                                 │
      │    __session__[2].__output__ = _x;↵        │
      │  } catch (e) {↵                            │
      │    __session__[2].__error__ = e;↵          │
      │  }↵                                        │
      │  try {↵                                    │
      │    var _y =↵                               │
      │      234;↵                                 │
      │    __session__[3].__output__ = _y;↵        │
      │  } catch (e) {↵                            │
      │    __session__[3].__error__ = e;↵          │
      │  }↵                                        │
      │  try {↵                                    │
      │    var _ =↵                                │
      │      _x + _y;↵                             │
      │    __session__[4].__output__ = _;↵         │
      │  } catch (e) {↵                            │
      │    __session__[4].__error__ = e;↵          │
      │  }↵                                        │
      │    return __session__;↵                    │
      │}())                                        │
      ╰────────────────────────────────────────────╯

  and when we run this code, e.g. by calling `eval(Session.runnerCode(session1))`, the returned `SESSION` value is this:

      [ { doc: 'A simple session example' },
        { input: '12 + 34',
          __output__: 46 },
        { id: '_x',
          input: '123',
          __output__: 123 },
        { id: '_y',
          input: '234',
          __output__: 234 },
        { input: '_x + _y',
          __output__: 357 } ]

comment
  Update the `type` of this unit!!!!
---
unit
  function
name
  Session.bugChecker
type
  Type.lambda ([SESSION, SESSION])
value
  function (session) {
    var checkedSession = [];
    for (var i = 0; i < session.length; i++) {
      var step = Val.clone (session [i]);
      if ('input' in step) {
        if (('output' in step || '__output__' in step) && ('error' in step || '__error__' in step))
          { step.__bug__ = Data.Moral.bad ("Output and error clash!"); }
        else if ('output' in step && '__output__' in step)   // and no 'error' and no '__error__'
          { if (Val.eq (step.output) (step.__output__)) {
              step.__bug__ = null;
              delete step.__output__;
            } else {
              step.__bug__ = Data.Moral.bad ("Predicted and real output are different!");
            }
          }
        else if ('error' in step && '__error__' in step)    // and no 'output' and no '__output__'
          { if (step.error === step.__error__) {
              step.__bug__ = null;
              delete step.__error__;
            } else {
              step.__bug__ = Data.Moral.good ("Not sure if the predicted and real error are really equal.");
            }
          }
        else if ('output' in step)                          // and no '__output__', no 'error' and no '__error__'
          { step.__bug__ = Data.Moral.good ("The real output is still undetermined."); }
        else if ('__output__' in step)                      // and no 'output', no 'error' and no '__error__'
          { if (Val.literal (step.__output__) === step.input) {
              step.__bug__ = null;
              delete step.__output__;
            } else {
              step.__bug__ = Data.Moral.good ("Not sure if the real output is correct.");
            }
          }
        else if ('error' in step)                           // and no 'output', no '__output__' and no '__error__'
          { step.__bug__ = Data.Moral.good ("Not sure if the predicted error is really thrown."); }
        else if ('__error__' in step)                       // and no 'output', no '__output__' and no 'error'
          { step.__bug__ = Data.Moral.good ("Not sure if the thrown error should be expected."); }
        else                                                // so no 'output', no '__output__', no 'error' and no '__error__'
          { step.__bug__ = Data.Moral.good ("No predicted or real behavior mentioned here."); }

      }
      checkedSession.push (step);
    }
    return checkedSession;
  }
info
  `Session.bugChecker(session)` checks for every session step and adds a `__bug__` property, accordingly.

  Note, that `__bug__` is of type `Type.nullify(Data.Moral.type(STRING))`, which means that we have three distinct kind of values

  * `{bad: message}`, is a malicious bug, saying that there is something fundamentally wrong. This happens when

        * A (predicted or real) output clashes with a (predicted or real) error.
        * The predicted `__output__` and the real `__output__` are different values.

  * `null`, indicating that there is no bug in the given session step. This is the case in one of the following situations

        * Predicted `output` and real `__output__` are equal.
        * There is a predicted `error` and real `__error__`, and they have the same string message.
        * There is not predicted `output` but a real `__output__` which as a literal string is equal to the `input`.

  * `{good: message}`, is a benign bug or warning, saying that the session step is insufficiently verified, either because the real value/error is not determined, yet, or because the predicted value/error is still missing. This value occurs when

        * _Not sure if the predicted and real error are really equal._ I.e. the thrown `__error__` and the predicted `error` have different message strings.
        * _The real output is still undetermined._ There is a predicted `output`, but no real `__output__` value, yet.
        * _Not sure if the real output is correct._ We know the real `__output__` which is different from the `input`, but there is no predicted `__output__` value.
        * _Not sure if the predicted error is really thrown._ There is a predicted `error`, but no real `__error__` thrown, yet.
        * _Not sure if the thrown error should be expected._ A real `__error__` is thrown here, but no `error` is predicted.
        * _No predicted or real behavior mentioned here._ No predicted `output` or `error`, and no real `__output__` or `__error__`, at all.


  Each of these three `__bug__` values is represented by a symbol (generated by `Session.toHtml(session)`):

  Symbol                                                                        `__bug__` value        standing for
  ----------------------------------------------------------------------------  ---------------------  ------------------------------------
  <span style="color:green">&#10004;</span>                                     `null`                 *O.k.*, step is verified
  <span style="color:yellow;font-weight:bold" title="message">???</span>        `{good: message}`      *Warning*, insufficient information
  <span style="color:red;font-weight:bold" title="message">!!!</span>           `{bad: message}`       *Bug!*, wrong prediction
  ----------------------------------------------------------------------------  ---------------------  ------------------------------------


---
unit
  function
name
  Session.bugSummary
type
  Type.lambda ([SESSION, Type.nullify(Type.MARKDOWN)])
value
  function (session) {
    var n = 0; // for the total number of errors
    var bugs = "";
    for (var i = 0; i < session.length; i++) {
      if ('__bug__' in session[i]) {
        var bug = session[i]['__bug__'];
        if (bug !== null && Data.Moral.isBad(bug)) {
          n++;
          bugs += "* Step " + i + " **" + Data.Moral.badValue (session[i]['__bug__']) + "**"
               +  "\n\n" + Str.indent (8) (Literal.block (session[i])) + "\n\n" ;
        }
      }
    }
    if (n === 0) {
      return null;
    } else {
      return ( "" + n + " bugs are found!" + "\n\n" + bugs );
    }
  }
info
  `Session.conflictSummary(sessionL)` takes a `session` and returns a (rather short) string summarizing all the session steps containing `__bug__` properties.
---
unit
  function
name
  Session.allMarkdownToHtml
type
  Type.lambda ([SESSION, SESSION])
value
  function (session) {
    var session = Val.clone (session);
    for (var i = 0; i < session.length; i++) {
      if (DOC_STEP.chi (session [i])) {
        session[i]['__doc__'] = Markdown.toHtml (session [i]['doc']);
        delete session[i]['doc'];
      }
    }
    return session;
  }
info
  `Session.allMarkdownToHtml(session)` returns (a clone of) `session`, where each `doc` property with a `Type.MARKDOWN` value is replaced by a `__doc__` property with a `Data.HTML` value.
comment
  `Session.allMarkdownToHtml` requires the `Markdown.toHtml` function from the `utils` tofu.
---
unit
  struct
name
  Session.Css
---
unit
  value
name
  Session.Css.defaultStyle
type
  $Css
value
  'color:#444444;background-color:#DDDDDD'
info
  The default light gray background and light black color as the basic style for sessions in HTML.
---
unit
  value
name
  Session.Css.userStyle
type
  $Css
value
  'color:#666666;background-color:#FFFFFF;font-family:monospace;padding:1px'
info
  The default colors for user input in sessions: white background and gray font color.
  The font is `monospace`.
---
unit
  struct
name
  Session.Symbols
---
unit
  value
name
  Session.Symbols.inputSymbol
type
  Data.HTML
value
  "&#9664;"
info
  The black triangle pointing to the left &#9664; is the input symbol for sessions in HTML.
---
unit
  value
name
  Session.Symbols.outputSymbol
type
  Data.HTML
value
  "&#9654;"
info
  The black triangle pointing to the right &#9654; is the output symbol for sessions in HTML.
---
unit
  value
name
  Session.Symbols.errorSymbol
type
  Data.HTML
value
  "&#10060;"
info
  The cross &#10060; is the error symbol for sessions in HTML.
---
unit
  value
name
  Session.Css.machineStyle
type
  $Css
value
  'color:#666666;background-color:#FFFFFF;font-family:monospace;'
info
  The default colors for machine output in sessions: little more gray than the white background of user input.
  The font is `monospace`.
---
unit
  function
name
  Session.toHtml
type
  Type.lambda ([SESSION, Data.HTML])
value
  function (session) {

    var id = defaultId;  // updated in each call of `oneStepToHtml(step)`

    function userCode (code) {
      return '<span style="padding:1px;' + Css.userStyle + '">' + Html.entityify (code) + '</span>';
    }
    function machineCode (code) {
      return '<span style="padding:1px;' + Css.machineStyle + '">' + Html.entityify (code) + '</span>';
    }

    function bugSymbol (bug) { // `bug` is of type `Type.nullify(Data.Moral.type(STRING))`
      if (bug === null)
        { return '<span style="color:green">&#10004;</span>'; }
      else if (Data.Moral.isGood (bug))
        { return '<span style="color:yellow;font-weight:bold" title="' + Data.Moral.goodValue(bug) + '">???</span>'; }
      else if (Data.Moral.isBad (bug))
        { return '<span style="color:red;font-weight:bold" title="' + Data.Moral.badValue(bug) + '">!!!</span>'; }
    }

    function threeCellRow (leftCell, middleCell, rightCell) {
      return ( '<tr>'
             + '<td style="vertical-align:top;text-align:right">' + leftCell + '</td>'
             + '<td style="vertical-align:top;text-align:center;width:2em;">' + middleCell + '</td>'
             + '<td style="text-align:left;white-space:pre">' + rightCell + '</td>'
             + '</tr>' );
    }
    function singleCellRow (cell) {
      return ( '<tr><td colspan="3" style="padding:5px">' + cell + '</td></tr>' );
    }
    function rightAlignRow (cell) {
      return ( '<tr><td colspan="3" style="text-align:right;padding:0">' + cell + '</td></tr>' );
    }

    // `oneStepToHtml(step)` takes a session or doc step and returns a couple of HTML table rows
    function oneStepToHtml (step) {
      id = step.id || defaultId;
      var html = "";
      for (var k in step) {
        switch (k) {
          case 'doc':
            html += singleCellRow (Html.entityify (step.doc));
            break;
          case '__doc__':
            html += singleCellRow (step.__doc__);
            break;
          case 'id':
            break;
          case 'input':
            html += threeCellRow ( (step.id ? userCode(id) : machineCode(id)), Symbols.inputSymbol, userCode (step.input));
            break;
          case 'output':
            html += threeCellRow ("", Symbols.outputSymbol, machineCode (Val.literal (step.output)));
            break;
          case '__output__':
            html += threeCellRow ("", Symbols.outputSymbol, machineCode (Val.literal (step.__output__)));
            break;
          case 'error':
            html += threeCellRow ("", Symbols.errorSymbol, machineCode (step.error));
            break;
          case '__error__':
            html += threeCellRow ("", Symbols.errorSymbol, machineCode (step.__error__));
            break;
          case '__bug__':
            html += rightAlignRow (bugSymbol (step.__bug__));
            break;
          default:
            throw Error ( "`Session.toHtml(session)` error due to unknown property `" + k + "` in session step:"
                        + Literal.block (step) );
        }
      }
      return html;
    }

    // the main program
    var html = '<table style="' + Css.defaultStyle + '">' + "\n";
    for (var i = 0; i < session.length; i++) {
      html += oneStepToHtml (session [i]) + "\n";
    }
    html += "</table>";
    return html;

  }
info
  `Session.toHtml(session)` returns a colored HTML version of the given `session`.

  Note, that HTML is not generated from Markdown by this function.
  If the given Markdown properties (`comment` and `doc`) have no HTML counterparts (`__comment__` and `__doc__`, respectively), the Markdown versions are displayed in the returned HTML.
  If you need to make sure that all Markdown is converted to HTML, run a prior `Session.allMarkdownToHtml(session)`.

  The symbols

      ----------------------------------------------------------------------------  ---------------------  ------------------------------
      <span style="color:green">&#10004;</span>                                     checked and no bug     `__bug__ === null`
      <span style="color:yellow;font-weight:bold" title="message">???</span>        unchecked              `__bug__ === {good: message}`
      <span style="color:red;font-weight:bold" title="message">!!!</span>           checked and bug        `__bug__ === {bad: message}`
      ----------------------------------------------------------------------------  ---------------------  ------------------------------
comment
  Correct the table (Markdown/Pandoc/HTML) in the `info`!!!
---




---
// session function on files //////////////////////////////////////////////////////////////////////////////////////
---
unit
  value
name
  Session.$__FUNCTIONS_ON_FILES__$
value
  undefined
info
  <div style="color:red">.................................CONTINUEHERE....................................</div>
---
// ...............................CONTINUEHERE..........................................................
---











---
// docs ///////////////////////////////////////////////////////////////////////////////////////////////////////////
---
unit
  value
name
  Session.$__DOCUMENTATION__$
value
  undefined
info
  # Introduction

  ## Assertion Testing vs Session Testing

  In the JavaScript community, **assertion testing** has become an established paradigm in verifying the correctness of code.
  There is a [Commonjs specification](http://wiki.commonjs.org/wiki/Unit_Testing/1.0#Assert), which is implemented e.g. by the [Assert](https://nodejs.org/api/assert.html) module of [Nodejs](https://nodejs.org).
  [Dart](https://www.dartlang.org) has an [`assert`](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#assert) statement built into its language.

  The basic idea is that you insert an *assertion* about some value or state in the program and that the JavaScript machine evaluates it. In case the assertion turns out to be true, nothing happens and the machine continues executing. But if the assertion is incorrect, the execution is interrupted and an error message is issued.

  For example, in [Dart](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#assert), we can insert a line

      assert (x != null);

  and an [`AssertionError`](http://api.dartlang.org/dart_core/AssertionError.html) is throws if the variable `x` is `null` at this point. Otherwise, the statement is silently ignored.

  In a Nodjs REPL session, we can load the [`Assert`](https://nodejs.org/api/assert.html) module

      > var Assert = require('assert')

  and have this dialog:

      > Assert (123 === 123)
      undefined
      > Assert (123 === 234)
      AssertionError: false == true .....

  i.e. the first input `Assert (123 === 123)` has no effect (`undefined`) because it is correct.
  But the second input `Assert (123 === 234)` throws an error.

  ## Session Testing

  We introduce **session testing** as a more expressive and powerful testing method, especially for functional programming.
  It does not only evaluate a single statement, but whole "sessions", i.e. dialogs with interactive JavaScript machines like the [Nodejs REPL](https://nodejs.org/api/repl.html) or the JavaScript console of a browser, say [Firefox](https://developer.mozilla.org/en/docs/Tools/Web_Console#command-line).

  Suppose you want to test the output of a user-defined function called `square` in a Nodejs REPL session.
  `square(x)` is supposed to return the square value `x * x` of its input.
  At each *loop* or *step* in such a session, Node offers you the prompt `>` that awaits your input and then prints the result.
  So, if `square` is implemented properly, this would be an example session:

      > square(2)
      4
      > square(9)
      81
      > square(-3)
      9
      > square(0)
      0

  You could also make ..............................................

  <div style="color:red">................CONTINUEHERE......................................................</div>


  # Example

  <div style="color:red">................CONTINUEHERE......................................................</div>

---
---
// End of Session ///
---
---


/***
***/
