(function(root, factory) {
    if (typeof exports === 'object') { // Node.js
        module.exports = factory(
            require('../functional.js'),
            require('../stream.js')
        );
    } else if (typeof define === 'function' && define.amd) { // Require.JS
        define(['jef/stream', 'jef/reactive'], factory);
    } else {  // Browser globals
        root.jefdemo = root.jefdemo || {};
        root.jefdemo.stream_excel = factory(
            root.jef.functional,
            root.jef.stream
        );
    }
})(this, function(f, stream){
    'use strict';

    function node_set_text(node, value) {
        node.innerText = value();
    }
    function extract_function_name(value) {
        return value.match(/[a-z]+/i)[0].toUpperCase();
    }
    function extract_function_arguments(value) {
        return value.match(/[a-z]{1,2}[0-9]{1,2}/ig) || [];
    }
    function build_excel_function(name, args) {
        return new Function(
            'functions',
            'streams',
            'value',
            'cellName',
            'console.log("executed: ", cellName);'
            + 'return jef.stream.when(streams["'+ args.join('"], streams["') +'"])'
                + '.last(function() {'
                    + 'console.log("on value: " + cellName);'
                    + 'value.value('
                        + 'functions["' + name + '"].apply(null, arguments)'
                    + ');'
                +'});'
        );
    }

    stream.when()

    var baseOptions = {
        functions: {},
        columns: '#ABCDEFGHIJ',
        rows: 5
    };

    return {
        main: function(element, document, options) {
            options = f.merge(baseOptions, options);

            var tr, td, label, result, input, cellName,
                streams = {},
                sharedResults = {},
                sharedFunctions = {},
                cols = options.columns.length,
                rows = options.rows;

            // Build columns
            tr = document.createElement('tr');
            for (var j = 0; j < cols; j++) {
                td = document.createElement('td');
                td.innerText = options.columns.charAt(j);
                tr.appendChild(td);
            }
            element.appendChild(tr);

            // Build rows
            for (var i = 1; i < rows; i++) {
                tr = document.createElement('tr');

                td = document.createElement('td');
                td.innerText = i;
                tr.appendChild(td);

                // Build cells
                for (var j = 1; j < cols; j++) {
                    td = document.createElement('td');
                    input = document.createElement('input');
                    result = document.createElement('pre');

                    td.appendChild(input);
                    td.appendChild(result);
                    tr.appendChild(td);

                    cellName = options.columns.charAt(j) + i;
                    streams[cellName] = new stream();
                    streams[cellName].on('value', function(value) {
                         this.innerText = value;
                    }.bind(result));

                    input.onchange = (function(cellName) {
                        return function() {
                            if (cellName in sharedResults) {
                                sharedResults[cellName].destroy();
                            }

                            if (this.value > 0) {
                                console.log('a: integer')
                                streams[cellName].value(this.value);
                            } else if(!this.value) {
                                console.log('b: null')
                                streams[cellName].value(null);
                            } else {
                                console.log('c: function');
                                sharedFunctions[cellName] = build_excel_function(
                                    extract_function_name(this.value),
                                    extract_function_arguments(this.value)
                                );

                                sharedResults[cellName] = sharedFunctions[cellName](options.functions, streams, streams[cellName], cellName);
                            }
                        }
                    })(cellName);
                }
                element.appendChild(tr);
            }
        }
    };
});

@@ -576,90 +576,8 @@
 ';%0A%0A
-    function node_set_text(node, value) %7B%0A        node.innerText = value();%0A    %7D%0A
     
@@ -922,29 +922,8 @@
 s',%0A
-            'value',%0A
     
@@ -958,46 +958,39 @@
     
-'console.log(%22executed: %22, cellName);'
+// Merge steams into one stream
 %0A   
@@ -997,18 +997,16 @@
         
- +
  'return
@@ -1088,80 +1088,161 @@
     
-+ '.last(function() %7B'%0A                    + 'console.log(%22on value: %22 +
+   // for last merged values in stream (if any)%0A                + '.last(function() %7B'%0A                    // apply function and set this value for given
  cel
@@ -1246,19 +1246,16 @@
 cellName
-);'
 %0A       
@@ -1270,21 +1270,33 @@
      + '
-value
+streams%5BcellName%5D
 .value('
@@ -1445,27 +1445,8 @@
  %7D%0A%0A
-    stream.when()%0A%0A
     
@@ -3444,66 +3444,8 @@
 ) %7B%0A
-                                console.log('a: integer')%0A
     
@@ -3566,63 +3566,8 @@
 ) %7B%0A
-                                console.log('b: null')%0A
     
@@ -3666,68 +3666,8 @@
 e %7B%0A
-                                console.log('c: function');%0A
     
@@ -4014,63 +4014,186 @@
 me%5D(
-options.functions, streams, streams%5BcellName%5D, cellName
+%0A                                    options.functions,%0A                                    streams,%0A                                    cellName%0A                                
 );%0A 

add description for example