<commit_before>Elm.Native.Runner = {};
Elm.Native.Runner.make = function(elm) {

    elm.Native = elm.Native || {};
    elm.Native.Runner = elm.Native.Runner || {};
    if (elm.Native.Runner.values) return elm.Native.Runner.values;

    var Signal    = Elm.Signal.make(elm);
    var Utils     = Elm.Native.Utils.make(elm);
    var ListUtils = Elm.Native.List.make(elm);
    var Element   = Elm.Graphics.Element.make(elm);
    var Renderer  = ElmRuntime.Render.Element();
    var now       = (function() {
        // Returns the number of milliseconds elapsed since either the browser navigationStart event or
        // the UNIX epoch, depending on availability.
        // Where the browser supports 'performance' we use that as it is more accurate (microsoeconds
        // will be returned in the fractional part) and more reliable as it does not rely on the system time.
        // Where 'performance' is not available, we will fall back to Date().getTime().
        // http://dvolvr.davidwaterston.com/2012/06/24/javascript-accurate-timing-is-almost-here/
        var performance = window.performance || {};
        performance.now = (function() {
            return performance.now    ||
            performance.webkitNow     ||
            performance.msNow         ||
            performance.oNow          ||
            performance.mozNow        ||
            function() { return new Date().getTime(); };
        })();
        return performance.now();
    });

    /* runMany : [Benchmark] -> Signal Either Element Time
     |
     | For rendering tests we have to be clever. We need an element to get to
     | screen. We instrument the element such that it notifies our signal and
     | consequently updates the foldp upon being rendered or updated.
     | Thanks to evancz for the advice on this!
     |
     | For pure tests we still have to return an element, so it's blank. We
     | also do not need this rendering trick as the functions are pure thunks.
     | We asynchronously run the pure function while timing it. When it
     | completes, it notifies the signal.
     |
     | When the signal is notified it recieves either a delta time or a
     | timestamp, distinguished by the type of deltaObject. After it is
     | appropriately placed in the results, the function grabs the next function
     | in the current benchmark (either a logic or a view benchmark). If there
     | are no more thunks left in the current benchmark, then the foldp goes on
     | to the next set of functions. This continues until we run out of
     | benchmarks at which point we display the results of all benchmarks.
     |
     | This is intentionally a monolithic function. The hope is to clean this
     | up when we need more functionality and when more features have been
     | added to Elm. It is possible that Commands will help.
     */
    function runMany(benchmarks){
        var bms = ListUtils.toArray(benchmarks);
        var totalBenchmarks = bms.length;
        var bmIndex   = 0;
        var index     = 0;
        var deltas = Signal.constant(-1);
        var w = 1000, h = 1000;
        var emptyElem = Element.empty;

        var results = [];
        var currentFunctions = ListUtils.toArray(bms[bmIndex]._1);
        if (currentFunctions.length < 1) {
            console.log("One of your benchmarks didn't have any functions to\
run. This is a fatal error.");
            return;
        }
        var currentFunctionType = bms[bmIndex].ctor;
        results[bmIndex] = {_:{}};
        results[bmIndex].name = bms[bmIndex]._0;
        results[bmIndex].times = [];

        var startTime = now();

        // time -> Element -> Element
        function bmStep (deltaObject, _) {
            var doWork = true;
            if(deltaObject.ctor === 'Pure') {
                results[bmIndex].times.push(deltaObject.time);
            } else if(deltaObject.ctor === 'Rendering') {
                results[bmIndex].times.push(now() - deltaObject.time);
            }
            if(index >= currentFunctions.length) {
                results[bmIndex].times = ListUtils.fromArray(results[bmIndex].times);
                index = 0;
                bmIndex++;
                if(bmIndex >= totalBenchmarks) {
                    console.log(now() - startTime);
                    return { ctor : 'Right'
                           , _0   : ListUtils.fromArray(results)
                           }
                }
                // Consider refreshing the screen at this point
                doWork = false;
                results.push({_:{}});
                results[bmIndex].name = bms[bmIndex]._0;
                results[bmIndex].times = [];
                currentFunctions = ListUtils.toArray(bms[bmIndex]._1);
                currentFunctionType = bms[bmIndex].ctor;
            }
            // insert a blank sheet between sets of thunks
            if(!doWork) {
                setTimeout(function(){
                    elm.notify(deltas.id,{});
                },0);
                return { ctor : 'Left'
                       , _0   : emptyElem
                       }
            }
            if(currentFunctionType === 'Logic') {
                timeFunction(currentFunctions[index++]);
                return { ctor : 'Left'
                       , _0   : emptyElem
                       }
            } else if (currentFunctionType === 'Render'){
                var elem = instrumentedElement(currentFunctions[index++]);
                return { ctor : 'Left'
                       , _0   : elem
                       }
            }
        }

        var bmBaseState;
        if(currentFunctionType === 'Logic') {
            bmBaseState = { ctor : 'Left'
                          , _0   : emptyElem
                          }
            setTimeout(function() {
                elm.notify(deltas.id, -1);
            },100); // Need time for the fold to get hooked up
        } else {
            var elem = instrumentedElement(currentFunctions[index++]);
            bmBaseState = { ctor : 'Left'
                          , _0   : elem
                          }
        }
        var accumulation = A3( Signal.foldp, F2(bmStep), bmBaseState, deltas);

        // type Model = { thunk : () -> Element, cachedElement : Element }
        // model : Model
        // render : Model -> DOM
        // update : DOM -> Model -> Model -> ()

        function instrumentedElement(thunk) {
           return A3(Element.newElement, w, h,
                    { ctor: 'Custom'
                    , type: 'customBenchmark'
                    , render: benchRender
                    , update: benchUpdate
                    , model: thunk
                    });
        }

        function benchRender(thunk) {
            var t1           = now();
            var newRendering = Renderer.render(thunk(Utils.Tuple0));
            var deltaObject  = { ctor: 'Rendering'
                               , time: t1
                               };
            setTimeout(function() { elm.notify(deltas.id, deltaObject); }, 0);
            return newRendering
        }

        function benchUpdate(node, oldThunk, newThunk) {
            var t1           = now();
            var oldModel     = oldThunk(Utils.Tuple0);
            var newModel     = newThunk(Utils.Tuple0);
            var newRendering = Renderer.update(node, oldModel, newModel);
            var deltaObject  = { ctor: 'Rendering'
                               , time: t1
                               };
            setTimeout(function() { elm.notify(deltas.id, deltaObject); }, 0);
        }

        function timeFunction(f) {
            var t1 = now();
            f(Utils.Tuple0);
            var t2 = now();
            var deltaObject = { ctor: 'Pure'
                              , time: t2 - t1}
            setTimeout(function() {
                elm.notify(deltas.id, deltaObject);
            },0);
        };

        return accumulation;
    }

    return elm.Native.Runner.values =
        { runMany   : runMany
        };
};<commit_msg>changed a comment<commit_after>Elm.Native.Runner = {};
Elm.Native.Runner.make = function(elm) {

    elm.Native = elm.Native || {};
    elm.Native.Runner = elm.Native.Runner || {};
    if (elm.Native.Runner.values) return elm.Native.Runner.values;

    var Signal    = Elm.Signal.make(elm);
    var Utils     = Elm.Native.Utils.make(elm);
    var ListUtils = Elm.Native.List.make(elm);
    var Element   = Elm.Graphics.Element.make(elm);
    var Renderer  = ElmRuntime.Render.Element();
    var now       = (function() {
        // Returns the number of milliseconds elapsed since either the browser navigationStart event or
        // the UNIX epoch, depending on availability.
        // Where the browser supports 'performance' we use that as it is more accurate (microsoeconds
        // will be returned in the fractional part) and more reliable as it does not rely on the system time.
        // Where 'performance' is not available, we will fall back to Date().getTime().
        // http://dvolvr.davidwaterston.com/2012/06/24/javascript-accurate-timing-is-almost-here/
        var performance = window.performance || {};
        performance.now = (function() {
            return performance.now    ||
            performance.webkitNow     ||
            performance.msNow         ||
            performance.oNow          ||
            performance.mozNow        ||
            function() { return new Date().getTime(); };
        })();
        return performance.now();
    });

    /* runMany : [Benchmark] -> Signal Either Element Time
     |
     | For rendering tests we have to be clever. We need an element to get to
     | screen. We instrument the element such that it notifies our signal and
     | consequently updates the foldp upon being rendered or updated.
     | Thanks to evancz for the advice on this!
     |
     | For pure tests we still have to return an element, so it's blank. We
     | also do not need this rendering trick as the functions are pure thunks.
     | We asynchronously run the pure function while timing it. When it
     | completes, it notifies the signal.
     |
     | When the signal is notified it recieves either a delta time or a
     | timestamp, distinguished by the type of deltaObject. After it is
     | appropriately placed in the results, the function grabs the next function
     | in the current benchmark (either a logic or a view benchmark). If there
     | are no more thunks left in the current benchmark, then the foldp goes on
     | to the next set of functions. This continues until we run out of
     | benchmarks at which point we display the results of all benchmarks.
     |
     | This is intentionally a monolithic function. The hope is to clean this
     | up when we need more functionality and when more features have been
     | added to Elm. It is possible that Commands will help.
     */
    function runMany(benchmarks){
        var bms = ListUtils.toArray(benchmarks);
        var totalBenchmarks = bms.length;
        var bmIndex   = 0;
        var index     = 0;
        var deltas = Signal.constant(-1);
        var w = 1000, h = 1000;
        var emptyElem = Element.empty;

        var results = [];
        var currentFunctions = ListUtils.toArray(bms[bmIndex]._1);
        if (currentFunctions.length < 1) {
            console.log("One of your benchmarks didn't have any functions to\
run. This is a fatal error.");
            return;
        }
        var currentFunctionType = bms[bmIndex].ctor;
        results[bmIndex] = {_:{}};
        results[bmIndex].name = bms[bmIndex]._0;
        results[bmIndex].times = [];

        var startTime = now();

        // time -> Element -> Element
        function bmStep (deltaObject, _) {
            var doWork = true;
            if(deltaObject.ctor === 'Pure') {
                results[bmIndex].times.push(deltaObject.time);
            } else if(deltaObject.ctor === 'Rendering') {
                results[bmIndex].times.push(now() - deltaObject.time);
            }
            if(index >= currentFunctions.length) {
                results[bmIndex].times = ListUtils.fromArray(results[bmIndex].times);
                index = 0;
                bmIndex++;
                if(bmIndex >= totalBenchmarks) {
                    console.log(now() - startTime);
                    return { ctor : 'Right'
                           , _0   : ListUtils.fromArray(results)
                           }
                }
                // On to the next round of thunks, do a blank element
                doWork = false;
                results.push({_:{}});
                results[bmIndex].name = bms[bmIndex]._0;
                results[bmIndex].times = [];
                currentFunctions = ListUtils.toArray(bms[bmIndex]._1);
                currentFunctionType = bms[bmIndex].ctor;
            }
            // insert a blank sheet between sets of thunks
            if(!doWork) {
                setTimeout(function(){
                    elm.notify(deltas.id,{});
                },0);
                return { ctor : 'Left'
                       , _0   : emptyElem
                       }
            }
            if(currentFunctionType === 'Logic') {
                timeFunction(currentFunctions[index++]);
                return { ctor : 'Left'
                       , _0   : emptyElem
                       }
            } else if (currentFunctionType === 'Render'){
                var elem = instrumentedElement(currentFunctions[index++]);
                return { ctor : 'Left'
                       , _0   : elem
                       }
            }
        }

        var bmBaseState;
        if(currentFunctionType === 'Logic') {
            bmBaseState = { ctor : 'Left'
                          , _0   : emptyElem
                          }
            setTimeout(function() {
                elm.notify(deltas.id, -1);
            },100); // Need time for the fold to get hooked up
        } else {
            var elem = instrumentedElement(currentFunctions[index++]);
            bmBaseState = { ctor : 'Left'
                          , _0   : elem
                          }
        }
        var accumulation = A3( Signal.foldp, F2(bmStep), bmBaseState, deltas);

        // type Model = { thunk : () -> Element, cachedElement : Element }
        // model : Model
        // render : Model -> DOM
        // update : DOM -> Model -> Model -> ()

        function instrumentedElement(thunk) {
           return A3(Element.newElement, w, h,
                    { ctor: 'Custom'
                    , type: 'customBenchmark'
                    , render: benchRender
                    , update: benchUpdate
                    , model: thunk
                    });
        }

        function benchRender(thunk) {
            var t1           = now();
            var newRendering = Renderer.render(thunk(Utils.Tuple0));
            var deltaObject  = { ctor: 'Rendering'
                               , time: t1
                               };
            setTimeout(function() { elm.notify(deltas.id, deltaObject); }, 0);
            return newRendering
        }

        function benchUpdate(node, oldThunk, newThunk) {
            var t1           = now();
            var oldModel     = oldThunk(Utils.Tuple0);
            var newModel     = newThunk(Utils.Tuple0);
            var newRendering = Renderer.update(node, oldModel, newModel);
            var deltaObject  = { ctor: 'Rendering'
                               , time: t1
                               };
            setTimeout(function() { elm.notify(deltas.id, deltaObject); }, 0);
        }

        function timeFunction(f) {
            var t1 = now();
            f(Utils.Tuple0);
            var t2 = now();
            var deltaObject = { ctor: 'Pure'
                              , time: t2 - t1}
            setTimeout(function() {
                elm.notify(deltas.id, deltaObject);
            },0);
        };

        return accumulation;
    }

    return elm.Native.Runner.values =
        { runMany   : runMany
        };
};<|endoftext|>


<commit_before>module('lively.ide.tests.SCBTests').requires('lively.TestFramework', 'lively.ide').toRun(function() {
// Browser related tests
TestCase.subclass('lively.ide.tests.SCBTests.SystemBrowserTests', {

	  setUp: function() {
		    var browser = this.createBrowser();
		    var root = this.createMockNode(browser);
		    browser.rootNode = function() { return root };
		    this.browser = browser;
	  },

	  createBrowser: function() {
		    return new lively.ide.BasicBrowser();
	  },

	  mockNodeClass: lively.ide.BrowserNode.subclass('lively.ide.tests.SCBTests.MockNode', {
			  initialize: function($super, target, browser, c) { $super(target, browser); this.children = c || [] },
			  childNodes: function() { return this.children; }
		}),

	  createMockNode: function(browser, children, target, name) {
		    var node = new this.mockNodeClass(target, browser, children);
		    if (name)
			  node.asString = function() { return name}
		    return node;
	  },

	  testSelectNodeInFirstPane: function() {
		    lively.ide.startSourceControl();
		    var browser = this.browser;
		    var node1 = this.createMockNode(browser);
		    var node2 = this.createMockNode(browser);
		    browser.rootNode().children = [node1, node2];
		    browser.buildView();
		    this.assertEquals(browser.nodesInPane('Pane1').length, 2);
		    browser.selectNode(node1);
		    this.assertIdentity(node1, browser.selectedNode());
	  },

	  testFilterChildNodes: function() {
		    var browser = this.browser;
		    var node1 = this.createMockNode(browser);
		    var node2 = this.createMockNode(browser);
		    node1.shouldAppear = true; node2.shouldAppear = false;
		    browser.rootNode().children = [node1, node2];
		    var testFilterClass = lively.ide.NodeFilter.subclass('lively.tests.ToolsTest.TestFilter', {
			      apply: function(nodes) { return nodes.select(function(ea) {return ea.shouldAppear}) }
		    });
		    var result = browser.filterChildNodesOf(browser.rootNode(), [new testFilterClass()]);
		    this.assertEquals(result.length, 1);
		        this.assertIdentity(result[0], node1);
	  },

	  testUninstallFilter: function() {
		    var browser = this.browser;
		    browser.installFilter(new lively.ide.NodeFilter(), 'Pane1');
		    this.assert(browser.getPane1Filters().length > 0);
		    browser.uninstallFilters(function(filter) { return filter instanceof lively.ide.NodeFilter }, 'Pane1')
		    this.assertEquals(browser.getPane1Filters().length, 0);
	  },

	  testSortFilter: function() {
		    var filter = new lively.ide.SortFilter();
		    var n1 = this.createMockNode(null, null, null, 'c');
		    var n2 = this.createMockNode(null, null, null, 'a');
		    var n3 = this.createMockNode(null, null, null, 'b');
		    var result = filter.apply([n1, n2, n3]);
		    this.assertEquals(result.length, 3);
		        this.assertIdentity(result[0], n2);
		    this.assertIdentity(result[1], n3);
		    this.assertIdentity(result[2], n1);
	  },

    testBrowserFourthPane: function() {
	      var browser = this.browser;

	      var n4 = this.createMockNode(browser, [], null, 'd');
	      var n3 = this.createMockNode(browser, [n4], null, 'c');
	      var n2 = this.createMockNode(browser, [n3], null, 'b');
	      var n1 = this.createMockNode(browser, [n2], null, 'a');

	      browser.rootNode().children = [n1];

	      var m = browser.buildView();

	      browser.selectNode(n1);
	      browser.selectNode(n2);
	      browser.selectNode(n3);

	      // m.openInWorld()

	      this.assertEquals(browser.nodesInPane('Pane4').length, 1);
	      this.assertIdentity(n4, browser.nodesInPane('Pane4')[0]);
    },

});

lively.ide.tests.SCBTests.SystemBrowserTests.subclass('lively.ide.tests.SCBTests.BrowserNodeTest',
'running', {
	  createBrowser: function() {
		    // FIXME
		    return new lively.ide.SystemBrowser();
	  },

	  buildTestSource: function() {
		    // create and parse the source into filefragments
		    var src = "\n\Object.subclass('Foo',\n\
'catA', {\n\
m1: function() { return 23 },\n\
m2: function() {},\n\
},\n\
'catB', {\n\
m3: function() { return 42},\n\
});\n\
\n\
Foo.addMethods('catC',{\n\
m4: function() {},\n\
});";

		    this.db = new AnotherSourceDatabase();
		    var rootFragment = this.db.prepareForMockModule('dummySource.js', src);

		    this.klassDef = rootFragment.subElements()[1]
		    this.m1 = this.klassDef.subElements()[0];
		    this.m2 = this.klassDef.subElements()[1];
		    this.m3 = this.klassDef.subElements()[2];
		    this.klassExtensionDef = rootFragment.subElements()[3]
		    this.m4 = this.klassExtensionDef.subElements()[0];

		    this.fileFragment = rootFragment;

		    // setup browser
		    var completeFFNode = new lively.ide.CompleteFileFragmentNode(
			      this.fileFragment, this.browser, null, this.fileFragment.name)
		    var root = this.createMockNode(this.browser, [completeFFNode]);
		    this.browser.rootNode =  function() { return root };
	  },

	  buildCopTestSource: function() {
		    // create and parse the source into filefragments
		    var src = "cop.create(\"testLayer\")"

		    this.db = new AnotherSourceDatabase();
		    var rootFragment = this.db.prepareForMockModule('dummyCopSource.js', src);

		    this.fileFragment = rootFragment;

		    // setup browser
		    var completeFFNode = new lively.ide.CompleteFileFragmentNode(
			      this.fileFragment, this.browser, null, this.fileFragment.name)
		    var root = this.createMockNode(this.browser, [completeFFNode]);

		    this.copNode = completeFFNode.childNodes()[0];

		    this.browser.rootNode =  function() { return root };
	  },
},
'testing', {

	  testCopFragmentWholeLayerEvaluate: function() {
		    this.browser.buildView();
		    this.buildCopTestSource();
		    var node = this.copNode;
		    var klass = Object.subclass('CopBrowserNodeDummy');
		    var src = 'cop.create("testLayer").refineClass(CopBrowserNodeDummy, { m: function() { return 23 } });'
		    node.newSource(src);
		    withLayers([testLayer], function() {
			      this.assertEquals(23, new klass().m());
		    }.bind(this))
	  },
	  testCopFragmentPartialClassEvaluate: function() {
		    this.browser.buildView();
		    this.buildCopTestSource();
		    var node = this.copNode;
		    var klass = Object.subclass('CopBrowserNodeDummy');
		    var src = 'cop.create("testLayer").refineClass(CopBrowserNodeDummy, { m: function() { return 23 } });'
		    node.newSource(src);
		    this.assertEquals(1, node.childNodes().length);
		    var klassNode = node.childNodes()[0];
		    klassNode.newSource('.refineClass(CopBrowserNodeDummy, { m: function() { return 42 } })')
		    withLayers([testLayer], function() {
			      this.assertEquals(42, new klass().m(), 'klass not did not evaluate');
		    }.bind(this))
	  },
	  testCopFragmentMethodEvaluate: function() {
		    this.browser.buildView();
		    this.buildCopTestSource();
		    var node = this.copNode;
		    var klass = Object.subclass('CopBrowserNodeDummy');
		    var src = 'cop.create("testLayer").refineClass(CopBrowserNodeDummy, {\nm: function() { return 23 }\n});'
		    node.newSource(src);
		    var methodNode = node.childNodes()[0].childNodes()[0];
		    methodNode.newSource('m: function() { return 42 }')
		    withLayers([testLayer], function() {
			      this.assertEquals(42, new klass().m(), 'method not did not evaluate');
		    }.bind(this))
	  },

    	  testCreateCategoriesFromClassDef: function() {
		    this.buildTestSource();
		    var browser = this.browser;

		    var completeFFNode = browser.rootNode().childNodes().first();
		    this.assertEquals(2, completeFFNode.childNodes().length);
		    var classNode = completeFFNode.childNodes().first();

		    this.assertEquals(3, classNode.childNodes().length);
		    this.assertEquals('-- all --', classNode.childNodes()[0].getName());
		    this.assertEquals('catA', classNode.childNodes()[1].getName());
		    this.assertEquals('catB', classNode.childNodes()[2].getName());

		    this.assertEquals(3, classNode.childNodes()[0].childNodes().length);
		    this.assertEquals(2, classNode.childNodes()[1].childNodes().length);
		    this.assertEquals(1, classNode.childNodes()[2].childNodes().length);

		    var methodNodes = classNode.childNodes()[1].childNodes()
		        this.assertEquals('m1', methodNodes[0].getName());
		        this.assertEquals('m2', methodNodes[1].getName());

	  },
	  testCreateCategoriesFromAddMethodDef: function() {
		        this.buildTestSource();
		    var browser = this.browser;
		    // browser.buildView()

		    var completeFFNode = browser.rootNode().childNodes().first();
		    this.assertEquals(2, completeFFNode.childNodes().length);
		    var addMethodNode = completeFFNode.childNodes()[1];

		    this.assertEquals(2, addMethodNode.childNodes().length);
		    this.assertEquals('-- all --', addMethodNode.childNodes()[0].getName());
		        this.assertEquals('catC', addMethodNode.childNodes()[1].getName());

		    // category childs
		    this.assertEquals(1, addMethodNode.childNodes()[0].childNodes().length);
		        this.assertEquals(1, addMethodNode.childNodes()[1].childNodes().length);

		    var methodNodes = addMethodNode.childNodes()[1].childNodes()
		    this.assertEquals('m4', methodNodes[0].getName());

	  },

	  testAddClassCommand: function() {
		    this.buildTestSource();
		    var browser = this.browser;
		    browser.buildView()

		    browser.inPaneSelectNodeNamed('Pane1', 'dummySource.js');
		    var commands = browser.commandMenuSpec('Pane2'),
			  commandSpec = commands.detect(function(spec) { return spec[0] == 'add class' });
		    this.assert(commandSpec && Object.isFunction(commandSpec[1]), 'Cannot find add class command');

		    var className = 'MyClass';
		    this.answerPromptsDuring(commandSpec[1]);

		    var newClassFragment = this.fileFragment.subElements().detect(function(ff) {
			      return ff.getName() == className;
		    });

		    this.assert(newClassFragment, 'new class not created');
        var code = newClassFragment.getSourceCode();
		    this.assert(code.startsWith('Object.subclass(\'' + className + '\','),
			              'source code of new class is strange: ' + code);

		    // var newNode = browser.selectedNode();
		    // this.assertEquals(newClassFragment, newNode.target,
        //                   'browser hasn\'t selected the new class');
	  },

	  testAddMethodCommand: function() {
		    this.buildTestSource();
		    var browser = this.browser;
		    browser.buildView()

		    browser.inPaneSelectNodeNamed('Pane1', 'dummySource.js');
		    browser.inPaneSelectNodeNamed('Pane2', 'Foo');
		    var commands = browser.commandMenuSpec('Pane4');
		    var commandSpec = commands.detect(function(spec) { return spec[0] == 'add method' });
		        this.assert(commandSpec && Object.isFunction(commandSpec[1]), 'Cannot find add method command');

		    var methodName = 'newMethod';
		    this.answerPromptsDuring(commandSpec[1]);

		    var newMethodFragment = this.fileFragment.flattened().detect(function(ff) {
			      return ff.getName() == methodName;
		    });

		    this.assert(newMethodFragment, 'new class not created');
        var code = newMethodFragment.getSourceCode();
		    this.assert(code.match(new RegExp('\s*' + methodName + ': function')),
			              'source code of new method is strange: ' + code);

		    // var newNode = browser.selectedNode();
        // this.assertEquals(newMethodFragment, newNode.target,
        //                   'browser hasn\'t selected the new method');
	  },

	  testBrowseIt: function() {
		    this.buildTestSource();
		    var browser = this.browser;
		    browser.buildView()

		    this.m1.basicBrowseIt(browser)

		    this.assertEquals(browser.nodesInPane('Pane4').length, 3);
		    this.assertIdentity(this.m1, browser.nodesInPane('Pane4')[0].target);
	  },
	  testBrowserKnowsCurrentModule: function() {
		    if (Global.Foo) Foo.remove();
		    this.buildTestSource();
		    this.browser.buildView()
		    this.browser.selectNodeNamed('dummySource.js');
		        this.browser.selectNodeNamed('Foo');
		    var n  = this.browser.selectedNode();
		    n.evalSource(n.sourceString());
		    this.assert(Global.Foo, 'Class Foo could not be evaled');
		    this.assertIdentity(Foo.sourceModule, module('dummySource'));
	  },

});

TestCase.subclass('lively.tests.ToolsTests.LivelyIdeBrowse',
'testing', {

    testLivelyIdeBrowse: function() {
        var sut = lively.ide.browse("lively.morphic.Morph", "onMouseDown", "lively.morphic.Events");

        this.assert(sut, "could not open browser")
        try {
            this.assertEquals(sut.targetURL, URL.codeBase + "lively/morphic/")

            this.assert(sut.pane1Selection, "no selection in Pane1")
            this.assertEquals(sut.pane1Selection.asString(), "Events.js")

            this.assert(sut.pane2Selection, "no selection in Pane2")
            this.assertEquals(sut.pane2Selection.asString(), "lively.morphic.Morph (extension)")

            // this.assertEquals(sut.pane3Selection.asString(), "event handling")
            this.assertEquals(sut.pane4Selection.asString(), "onMouseDown (proto)")
        } finally {
            if(sut) sut.view.remove() // close window
        }
    }

});

});<commit_msg>continued test refactoring, part 3<commit_after>module('lively.ide.tests.SCBTests').requires('lively.TestFramework', 'lively.ide').toRun(function() {
// Browser related tests
TestCase.subclass('lively.ide.tests.SCBTests.SystemBrowserTests', {

	  setUp: function() {
		    var browser = this.createBrowser();
		    var root = this.createMockNode(browser);
		    browser.rootNode = function() { return root };
		    this.browser = browser;
	  },

	  createBrowser: function() {
		    return new lively.ide.BasicBrowser();
	  },

	  mockNodeClass: lively.ide.BrowserNode.subclass('lively.ide.tests.SCBTests.MockNode', {
			  initialize: function($super, target, browser, c) { $super(target, browser); this.children = c || [] },
			  childNodes: function() { return this.children; }
		}),

	  createMockNode: function(browser, children, target, name) {
		    var node = new this.mockNodeClass(target, browser, children);
		    if (name)
			  node.asString = function() { return name}
		    return node;
	  },

	  testSelectNodeInFirstPane: function() {
		    lively.ide.startSourceControl();
		    var browser = this.browser;
		    var node1 = this.createMockNode(browser);
		    var node2 = this.createMockNode(browser);
		    browser.rootNode().children = [node1, node2];
		    browser.buildView();
		    this.assertEquals(browser.nodesInPane('Pane1').length, 2);
		    browser.selectNode(node1);
		    this.assertIdentity(node1, browser.selectedNode());
	  },

	  testFilterChildNodes: function() {
		    var browser = this.browser;
		    var node1 = this.createMockNode(browser);
		    var node2 = this.createMockNode(browser);
		    node1.shouldAppear = true; node2.shouldAppear = false;
		    browser.rootNode().children = [node1, node2];
		    var testFilterClass = lively.ide.NodeFilter.subclass('lively.tests.ToolsTest.TestFilter', {
			      apply: function(nodes) { return nodes.select(function(ea) {return ea.shouldAppear}) }
		    });
		    var result = browser.filterChildNodesOf(browser.rootNode(), [new testFilterClass()]);
		    this.assertEquals(result.length, 1);
		        this.assertIdentity(result[0], node1);
	  },

	  testUninstallFilter: function() {
		    var browser = this.browser;
		    browser.installFilter(new lively.ide.NodeFilter(), 'Pane1');
		    this.assert(browser.getPane1Filters().length > 0);
		    browser.uninstallFilters(function(filter) { return filter instanceof lively.ide.NodeFilter }, 'Pane1')
		    this.assertEquals(browser.getPane1Filters().length, 0);
	  },

	  testSortFilter: function() {
		    var filter = new lively.ide.SortFilter();
		    var n1 = this.createMockNode(null, null, null, 'c');
		    var n2 = this.createMockNode(null, null, null, 'a');
		    var n3 = this.createMockNode(null, null, null, 'b');
		    var result = filter.apply([n1, n2, n3]);
		    this.assertEquals(result.length, 3);
		        this.assertIdentity(result[0], n2);
		    this.assertIdentity(result[1], n3);
		    this.assertIdentity(result[2], n1);
	  },

    testBrowserFourthPane: function() {
	      var browser = this.browser;

	      var n4 = this.createMockNode(browser, [], null, 'd');
	      var n3 = this.createMockNode(browser, [n4], null, 'c');
	      var n2 = this.createMockNode(browser, [n3], null, 'b');
	      var n1 = this.createMockNode(browser, [n2], null, 'a');

	      browser.rootNode().children = [n1];

	      var m = browser.buildView();

	      browser.selectNode(n1);
	      browser.selectNode(n2);
	      browser.selectNode(n3);

	      // m.openInWorld()

	      this.assertEquals(browser.nodesInPane('Pane4').length, 1);
	      this.assertIdentity(n4, browser.nodesInPane('Pane4')[0]);
    },

});

lively.ide.tests.SCBTests.SystemBrowserTests.subclass('lively.ide.tests.SCBTests.BrowserNodeTest',
'running', {
	  createBrowser: function() {
		    // FIXME
		    return new lively.ide.SystemBrowser();
	  },

	  buildTestSource: function() {
		    // create and parse the source into filefragments
		    var src = "\n\Object.subclass('Foo',\n\
'catA', {\n\
m1: function() { return 23 },\n\
m2: function() {},\n\
},\n\
'catB', {\n\
m3: function() { return 42},\n\
});\n\
\n\
Foo.addMethods('catC',{\n\
m4: function() {},\n\
});";

		    this.db = new AnotherSourceDatabase();
		    var rootFragment = this.db.prepareForMockModule('dummySource.js', src);

		    this.klassDef = rootFragment.subElements()[1]
		    this.m1 = this.klassDef.subElements()[0];
		    this.m2 = this.klassDef.subElements()[1];
		    this.m3 = this.klassDef.subElements()[2];
		    this.klassExtensionDef = rootFragment.subElements()[3]
		    this.m4 = this.klassExtensionDef.subElements()[0];

		    this.fileFragment = rootFragment;

		    // setup browser
		    var completeFFNode = new lively.ide.CompleteFileFragmentNode(
			      this.fileFragment, this.browser, null, this.fileFragment.name)
		    var root = this.createMockNode(this.browser, [completeFFNode]);
		    this.browser.rootNode =  function() { return root };
	  },

	  buildCopTestSource: function() {
		    // create and parse the source into filefragments
		    var src = "cop.create(\"testLayer\")"

		    this.db = new AnotherSourceDatabase();
		    var rootFragment = this.db.prepareForMockModule('dummyCopSource.js', src);

		    this.fileFragment = rootFragment;

		    // setup browser
		    var completeFFNode = new lively.ide.CompleteFileFragmentNode(
			      this.fileFragment, this.browser, null, this.fileFragment.name)
		    var root = this.createMockNode(this.browser, [completeFFNode]);

		    this.copNode = completeFFNode.childNodes()[0];

		    this.browser.rootNode =  function() { return root };
	  },
},
'testing', {

	  testCopFragmentWholeLayerEvaluate: function() {
		    this.browser.buildView();
		    this.buildCopTestSource();
		    var node = this.copNode;
		    var klass = Object.subclass('CopBrowserNodeDummy');
		    var src = 'cop.create("testLayer").refineClass(CopBrowserNodeDummy, { m: function() { return 23 } });'
		    node.newSource(src);
		    withLayers([testLayer], function() {
			      this.assertEquals(23, new klass().m());
		    }.bind(this))
	  },
	  testCopFragmentPartialClassEvaluate: function() {
		    this.browser.buildView();
		    this.buildCopTestSource();
		    var node = this.copNode;
		    var klass = Object.subclass('CopBrowserNodeDummy');
		    var src = 'cop.create("testLayer").refineClass(CopBrowserNodeDummy, { m: function() { return 23 } });'
		    node.newSource(src);
		    this.assertEquals(1, node.childNodes().length);
		    var klassNode = node.childNodes()[0];
		    klassNode.newSource('.refineClass(CopBrowserNodeDummy, { m: function() { return 42 } })')
		    withLayers([testLayer], function() {
			      this.assertEquals(42, new klass().m(), 'klass not did not evaluate');
		    }.bind(this))
	  },
	  testCopFragmentMethodEvaluate: function() {
		    this.browser.buildView();
		    this.buildCopTestSource();
		    var node = this.copNode;
		    var klass = Object.subclass('CopBrowserNodeDummy');
		    var src = 'cop.create("testLayer").refineClass(CopBrowserNodeDummy, {\nm: function() { return 23 }\n});'
		    node.newSource(src);
		    var methodNode = node.childNodes()[0].childNodes()[0];
		    methodNode.newSource('m: function() { return 42 }')
		    withLayers([testLayer], function() {
			      this.assertEquals(42, new klass().m(), 'method not did not evaluate');
		    }.bind(this))
	  },

    	  testCreateCategoriesFromClassDef: function() {
		    this.buildTestSource();
		    var browser = this.browser;

		    var completeFFNode = browser.rootNode().childNodes().first();
		    this.assertEquals(2, completeFFNode.childNodes().length);
		    var classNode = completeFFNode.childNodes().first();

		    this.assertEquals(3, classNode.childNodes().length);
		    this.assertEquals('-- all --', classNode.childNodes()[0].getName());
		    this.assertEquals('catA', classNode.childNodes()[1].getName());
		    this.assertEquals('catB', classNode.childNodes()[2].getName());

		    this.assertEquals(3, classNode.childNodes()[0].childNodes().length);
		    this.assertEquals(2, classNode.childNodes()[1].childNodes().length);
		    this.assertEquals(1, classNode.childNodes()[2].childNodes().length);

		    var methodNodes = classNode.childNodes()[1].childNodes()
		        this.assertEquals('m1', methodNodes[0].getName());
		        this.assertEquals('m2', methodNodes[1].getName());

	  },
	  testCreateCategoriesFromAddMethodDef: function() {
		        this.buildTestSource();
		    var browser = this.browser;
		    // browser.buildView()

		    var completeFFNode = browser.rootNode().childNodes().first();
		    this.assertEquals(2, completeFFNode.childNodes().length);
		    var addMethodNode = completeFFNode.childNodes()[1];

		    this.assertEquals(2, addMethodNode.childNodes().length);
		    this.assertEquals('-- all --', addMethodNode.childNodes()[0].getName());
		        this.assertEquals('catC', addMethodNode.childNodes()[1].getName());

		    // category childs
		    this.assertEquals(1, addMethodNode.childNodes()[0].childNodes().length);
		        this.assertEquals(1, addMethodNode.childNodes()[1].childNodes().length);

		    var methodNodes = addMethodNode.childNodes()[1].childNodes()
		    this.assertEquals('m4', methodNodes[0].getName());

	  },

	  testAddClassCommand: function() {
		    this.buildTestSource();
		    var browser = this.browser;
		    browser.buildView()

		    browser.inPaneSelectNodeNamed('Pane1', 'dummySource.js');
		    var commands = browser.commandMenuSpec('Pane2'),
			  commandSpec = commands.detect(function(spec) { return spec[0] == 'add class' });
		    this.assert(commandSpec && Object.isFunction(commandSpec[1]), 'Cannot find add class command');

		    var className = 'MyClass';
		    this.answerPromptsDuring(commandSpec[1]);

		    var newClassFragment = this.fileFragment.subElements().detect(function(ff) {
			      return ff.getName() == className;
		    });

		    this.assert(newClassFragment, 'new class not created');
        var code = newClassFragment.getSourceCode();
		    this.assert(code.startsWith('Object.subclass(\'' + className + '\','),
			              'source code of new class is strange: ' + code);

		    // var newNode = browser.selectedNode();
		    // this.assertEquals(newClassFragment, newNode.target,
        //                   'browser hasn\'t selected the new class');
	  },

	  testAddMethodCommand: function() {
		    this.buildTestSource();
		    var browser = this.browser;
		    browser.buildView()

		    browser.inPaneSelectNodeNamed('Pane1', 'dummySource.js');
		    browser.inPaneSelectNodeNamed('Pane2', 'Foo');
		    var commands = browser.commandMenuSpec('Pane4');
		    var commandSpec = commands.detect(function(spec) { return spec[0] == 'add method' });
		        this.assert(commandSpec && Object.isFunction(commandSpec[1]), 'Cannot find add method command');

		    var methodName = 'newMethod';
		    this.answerPromptsDuring(commandSpec[1]);

		    var newMethodFragment = this.fileFragment.flattened().detect(function(ff) {
			      return ff.getName() == methodName;
		    });

		    this.assert(newMethodFragment, 'new class not created');
        var code = newMethodFragment.getSourceCode();
		    this.assert(code.match(new RegExp('\s*' + methodName + ': function')),
			              'source code of new method is strange: ' + code);

		    // var newNode = browser.selectedNode();
        // this.assertEquals(newMethodFragment, newNode.target,
        //                   'browser hasn\'t selected the new method');
	  },

	  testBrowseIt: function() {
		    this.buildTestSource();
		    var browser = this.browser;
		    browser.buildView()

		    this.m1.basicBrowseIt(browser)

		    this.assertEquals(browser.nodesInPane('Pane4').length, 3);
		    this.assertIdentity(this.m1, browser.nodesInPane('Pane4')[0].target);
	  },
	  testBrowserKnowsCurrentModule: function() {
		    if (Global.Foo) Foo.remove();
		    this.buildTestSource();
		    this.browser.buildView()
		    this.browser.selectNodeNamed('dummySource.js');
		        this.browser.selectNodeNamed('Foo');
		    var n  = this.browser.selectedNode();
		    n.evalSource(n.sourceString());
		    this.assert(Global.Foo, 'Class Foo could not be evaled');
		    this.assertIdentity(Foo.sourceModule, module('dummySource'));
	  },

});

TestCase.subclass('lively.tests.ToolsTests.LivelyIdeBrowse',
'testing', {

    shouldRun: false,

    testLivelyIdeBrowse: function() {
        var sut = lively.ide.browse("lively.morphic.Morph", "onMouseDown", "lively.morphic.Events");

        this.assert(sut, "could not open browser")
        try {
            this.assertEquals(sut.targetURL, URL.codeBase + "lively/morphic/")

            this.assert(sut.pane1Selection, "no selection in Pane1")
            this.assertEquals(sut.pane1Selection.asString(), "Events.js")

            this.assert(sut.pane2Selection, "no selection in Pane2")
            this.assertEquals(sut.pane2Selection.asString(), "lively.morphic.Morph (extension)")

            // this.assertEquals(sut.pane3Selection.asString(), "event handling")
            this.assertEquals(sut.pane4Selection.asString(), "onMouseDown (proto)")
        } finally {
            if (sut) sut.view.remove() // close window
        }
    }

});

});<|endoftext|>


<commit_before>;
/*!
 * Tarsier JavaScript Library v1.0.1
 * http://github.com/moky/Tarsier/
 *
 * Copyright 2013 moKy at slanissue.com
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2013-12-11 T10:43Z
 */

/**
 *
 *  Object utilities
 *
 *  Author: moKy @ Jan. 17, 2014
 *
 */

(function(tarsier) {

	// flat the element into a json string
	function flat(element, indent) {
		indent = indent || "";
		var _INDENT_ = indent + "\t";
		var _CRLF_ = "\r\n";

		var type = typeof(element);
		if (type === "object" && element instanceof Array) {
			type = "array";
		}

		if (type === "array") {
			var string = "";
			for (var i = 0; i < element.length; ++i) {
				string += _INDENT_ + "/* " + i + " */ " + flat(element[i], _INDENT_) + "," + _CRLF_;
			}
			return "[" + _CRLF_ + string + indent + "]";
		} else if (type === "object") {
			var string = "";
			for (var key in element) {
				string += _INDENT_ + "\"" + key + "\" : " + flat(element[key], _INDENT_) + "," + _CRLF_;
			}
			return "{" + _CRLF_ + string + indent + "}";
		} else if (type === "string") {
			return "\"" + element + "\"";
		} else {
			return element;
		}
	}

	//--------------------------------------------------------------------------

	// class: Object
	tarsier.Object = function(object) {
		this.data = object;
		return this;
	};

	tarsier.Object.prototype.json = function() {
		return flat(this.data);
	};

	tarsier.Object.prototype.description = function() {
		return flat(this.data);
	};

})(tarsier);
<commit_msg>v1.0.2<commit_after>;
/*!
 * Tarsier JavaScript Library v1.0.1
 * http://github.com/moky/Tarsier/
 *
 * Copyright 2013 moKy at slanissue.com
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2013-12-11 T10:43Z
 */

/**
 *
 *  Object utilities
 *
 *  Author: moKy @ Jan. 17, 2014
 *
 */

(function(tarsier) {

	// flat the element into a json string
	function json(element) {
		var type = typeof(element);
		if (type === "object" && element instanceof Array) {
			type = "array";
		}

		if (type === "array") {
			var string = "";
			for (var i = 0; i < element.length; ++i) {
				string += json(element[i]) + ",";
			}
			if (string.length > 0) {
				string = string.substr(0, string.length - 1); // erase last ','
			}
			return "[" + string + "]";
		} else if (type === "object") {
			var string = "";
			for (var key in element) {
				string += "\"" + key + "\":" + json(element[key]) + ",";
			}
			if (string.length > 0) {
				string = string.substr(0, string.length - 1); // erase last ','
			}
			return "{" + string + "}";
		} else if (type === "string") {
			var string = element;
			string = string.replace(/"/g, "\\\"");
			return "\"" + string + "\"";
		} else {
			return element;
		}
	}

	// flat the element into a string
	function desc(element, indent) {
		indent = indent || "";
		var _INDENT_ = indent + "\t";
		var _CRLF_ = "\r\n";

		var type = typeof(element);
		if (type === "object" && element instanceof Array) {
			type = "array";
		}

		if (type === "array") {
			var string = "";
			for (var i = 0; i < element.length; ++i) {
				string += _CRLF_ + _INDENT_ + "/* " + i + " */ " + desc(element[i], _INDENT_) + ",";
			}
			if (string.length > 0) {
				string = string.substr(0, string.length - 1); // erase last ','
			}
			return "[" + string + _CRLF_ + indent + "]";
		} else if (type === "object") {
			var string = "";
			for (var key in element) {
				string += _CRLF_ + _INDENT_ + "\"" + key + "\" : " + desc(element[key], _INDENT_) + ",";
			}
			if (string.length > 0) {
				string = string.substr(0, string.length - 1); // erase last ','
			}
			return "{" + string + _CRLF_ + indent + "}";
		} else if (type === "string") {
			var string = element;
			string = string.replace(/"/g, "\\\"");
			return "\"" + string + "\"";
		} else {
			return element;
		}
	}

	//--------------------------------------------------------------------------

	// class: Object
	tarsier.Object = function(object) {
		this.data = object;
		return this;
	};

	tarsier.Object.prototype.json = function() {
		return json(this.data);
	};

	tarsier.Object.prototype.description = function() {
		return desc(this.data);
	};

})(tarsier);
<|endoftext|>


<commit_before>Template.search.onCreated(function() {
    this.search = new ReactiveDict()
})
Template.search.onRendered(function() {
    const search = Template.instance().search
    search.set('icon', Template.currentData().icon)
    this.autorun(() => {
        search.set('url', Template.currentData().url)
        $('.ui.search')
            .search({
                apiSettings: {
                    cache: false,
                    onResponse: function(searchResponse) {
                        return WSL.search.searchResponse(searchResponse)
                    },
                    url: search.get('url')
                },
                minCharacters : 3
            })
    })
})

Template.search.helpers({
    icon: () => {
        const search = Template.instance().search
        return search.get('icon') ? search.get('icon'): "search"
    }
})<commit_msg>search result<commit_after>Meteor.startup(() => {
    if(!Package['heaven7:wsl-core']) WSL = window && window['WSL'] ? window['WSL'] : {}
    else WSL = window['WSL']

    WSL.search.result = {}
})
Template.search.onCreated(function() {
    this.search = new ReactiveDict()
    this.result = new ReactiveVar()
})
Template.search.onRendered(function() {
    const search = Template.instance().search
    search.set('icon', Template.currentData().icon)
    this.autorun(() => {
        search.set('url', Template.currentData().url)
        $('.ui.search')
            .search({
                apiSettings: {
                    cache: false,
                    onResponse: function(searchResponse) {
                        return WSL.search.searchResponse(searchResponse)
                    },
                    url: search.get('url')
                },
                minCharacters : 3
            })
    })
})

Template.search.helpers({
    icon: () => {
        const search = Template.instance().search
        return search.get('icon') ? search.get('icon'): "search"
    }
})

Template.search.events({
    'click .result': (e,t) => {
        let val = $(e.currentTarget).find('.title').text()
        WSL.search.result = val
        Template.instance().result.set(val)
    }
})<|endoftext|>


<commit_before>import { UPDATE_MATCH, RESOLVE_MATCH, getRoutesByPath, getRoutePath } from '../../router'
import { getComponentsMeta, mergeMeta, updateMeta } from '../../meta/meta'
import { getLocationUrl } from '../../location'

import {
	PRELOAD_STARTED,
	PRELOAD_FINISHED,
	PRELOAD_FAILED
} from '../preload/actions'

import {
	isInstantTransition,
	setInstantNavigationFlag,
	addInstantBack,
	resetInstantBack
} from '../client/instantBack'

export default function routerMiddleware(routes, codeSplit, onNavigate, reportStats)
{
	let startedAt
	let previousLocation
	let previousRouteIndices

	function updateMetaTags(routeIndices, state) {
		const routeChain = getRoutesByPath(routeIndices, routes)
		const meta = codeSplit ? getCodeSplitMeta(routeChain, state) : getComponentsMeta(routeChain.map(_ => _.Component), state)
		updateMeta(mergeMeta(meta))
	}

	return ({ dispatch, getState }) =>
	{
		return next => event =>
		{
			const location = event.payload && event.payload.location
			const routeIndices = event.payload && event.payload.routeIndices

			switch (event.type) {
				case UPDATE_MATCH:
					startedAt = Date.now()

					// If it's an instant "Back"/"Forward" navigation
					// then navigate to the page without preloading it.
					// (has been previously preloaded and is in Redux state)
					const _isInstantTransition =
						location.action === 'POP' &&
						previousLocation &&
						isInstantTransition(previousLocation, location)

					// Set the flag for `wasInstantNavigation()`.
					setInstantNavigationFlag(_isInstantTransition)

					if (onNavigate) {
						onNavigate(getLocationUrl(location), location)
					}

					// Indicates whether an `instantBack` `<Link/>` was clicked.
					const instantBack = window._react_website_instant_back

					// Update instant back navigation chain.
					if (instantBack) {
						// Stores "current" (soon to be "previous") location
						// in "instant back chain", so that if "Back" is clicked
						// then such transition could be detected as "should be instant".
						addInstantBack(
							location,
							previousLocation,
							routeIndices,
							previousRouteIndices
						)
					} else if (!_isInstantTransition) {
						// If current transition is not "instant back" and not "instant"
						// then reset the whole "instant back" chain.
						// Only a consequitive "instant back" navigation chain
						// preserves the ability to instantly navigate "Back".
						// Once a regular navigation takes place
						// all previous "instant back" possibilities are discarded.
						resetInstantBack()
					}

					// `RESOLVE_MATCH` is not being emitted
					// for the first render for some reason.
					const isFirstRender = !previousLocation
					if (isFirstRender) {
						updateMetaTags(routeIndices, getState())
					} else {
						// Show page loading indicator.
						dispatch({ type: PRELOAD_STARTED })
					}

					previousLocation = location
					previousRouteIndices = routeIndices
					break

				case RESOLVE_MATCH:
					updateMetaTags(routeIndices, getState())

					// Report preloading time.
					// This preloading time will be longer then
					// the server-side one, say, by 10 milliseconds,
					// probably because the web browser making
					// an asynchronous HTTP request is slower
					// than the Node.js server making a regular HTTP request.
					// Also this includes network latency
					// for a particular website user, etc.
					// So this `preload` time doesn't actually describe
					// the server-side performance.
					if (reportStats) {
						reportStats({
							url: getLocationUrl(location),
							// Concatenated `react-router` route string.
							// E.g. "/user/:user_id/post/:post_id"
							route: getRoutePath(getRoutesByPath(routeIndices, routes)),
							time: {
								preload: Date.now() - startedAt
							}
						})
					}

					// Hide page loading indicator.
					dispatch({ type: PRELOAD_FINISHED })

					if (Date.now() - startedAt > 30) {
						console.log(`[react-website] "${location.pathname}" loaded in ${Date.now() - startedAt} ms`)
					}

					break
			}

			return next(event)
		}
	}
}

function getCodeSplitMeta(routes, state) {
	return routes.map(_ => _.getMeta).filter(_ => _).map(_ => _(state))
}<commit_msg>console.log<commit_after>import { UPDATE_MATCH, RESOLVE_MATCH, getRoutesByPath, getRoutePath } from '../../router'
import { getComponentsMeta, mergeMeta, updateMeta } from '../../meta/meta'
import { getLocationUrl } from '../../location'

import {
	PRELOAD_STARTED,
	PRELOAD_FINISHED,
	PRELOAD_FAILED
} from '../preload/actions'

import {
	isInstantTransition,
	setInstantNavigationFlag,
	addInstantBack,
	resetInstantBack
} from '../client/instantBack'

export default function routerMiddleware(routes, codeSplit, onNavigate, reportStats)
{
	let startedAt
	let previousLocation
	let previousRouteIndices

	function updateMetaTags(routeIndices, state) {
		const routeChain = getRoutesByPath(routeIndices, routes)
		const meta = codeSplit ? getCodeSplitMeta(routeChain, state) : getComponentsMeta(routeChain.map(_ => _.Component), state)
		updateMeta(mergeMeta(meta))
	}

	return ({ dispatch, getState }) =>
	{
		return next => event =>
		{
			const location = event.payload && event.payload.location
			const routeIndices = event.payload && event.payload.routeIndices

			switch (event.type) {
				case UPDATE_MATCH:
					startedAt = Date.now()

					// If it's an instant "Back"/"Forward" navigation
					// then navigate to the page without preloading it.
					// (has been previously preloaded and is in Redux state)
					const _isInstantTransition =
						location.action === 'POP' &&
						previousLocation &&
						isInstantTransition(previousLocation, location)

					// Set the flag for `wasInstantNavigation()`.
					setInstantNavigationFlag(_isInstantTransition)

					if (onNavigate) {
						onNavigate(getLocationUrl(location), location)
					}

					// Indicates whether an `instantBack` `<Link/>` was clicked.
					const instantBack = window._react_website_instant_back

					// Update instant back navigation chain.
					if (instantBack) {
						// Stores "current" (soon to be "previous") location
						// in "instant back chain", so that if "Back" is clicked
						// then such transition could be detected as "should be instant".
						addInstantBack(
							location,
							previousLocation,
							routeIndices,
							previousRouteIndices
						)
					} else if (!_isInstantTransition) {
						// If current transition is not "instant back" and not "instant"
						// then reset the whole "instant back" chain.
						// Only a consequitive "instant back" navigation chain
						// preserves the ability to instantly navigate "Back".
						// Once a regular navigation takes place
						// all previous "instant back" possibilities are discarded.
						resetInstantBack()
					}

					// `RESOLVE_MATCH` is not being emitted
					// for the first render for some reason.
					const isFirstRender = !previousLocation
					if (isFirstRender) {
						updateMetaTags(routeIndices, getState())
					} else {
						// Show page loading indicator.
						dispatch({ type: PRELOAD_STARTED })
					}

					previousLocation = location
					previousRouteIndices = routeIndices
					break

				case RESOLVE_MATCH:
					updateMetaTags(routeIndices, getState())

					// Report preloading time.
					// This preloading time will be longer then
					// the server-side one, say, by 10 milliseconds,
					// probably because the web browser making
					// an asynchronous HTTP request is slower
					// than the Node.js server making a regular HTTP request.
					// Also this includes network latency
					// for a particular website user, etc.
					// So this `preload` time doesn't actually describe
					// the server-side performance.
					if (reportStats) {
						reportStats({
							url: getLocationUrl(location),
							// Concatenated `react-router` route string.
							// E.g. "/user/:user_id/post/:post_id"
							route: getRoutePath(getRoutesByPath(routeIndices, routes)),
							time: {
								preload: Date.now() - startedAt
							}
						})
					}

					// Hide page loading indicator.
					dispatch({ type: PRELOAD_FINISHED })

					// Report preload time in console for debugging.
					if (Date.now() - startedAt > 30) {
						console.log(`[react-website] "${location.pathname}" loaded in ${Date.now() - startedAt} ms`)
					}

					break
			}

			return next(event)
		}
	}
}

function getCodeSplitMeta(routes, state) {
	return routes.map(_ => _.getMeta).filter(_ => _).map(_ => _(state))
}<|endoftext|>


<commit_before>// OutputBoard.js (c) 2013-2014 Loren West
// May be freely distributed under the MIT license.
// For further details and documentation:
// http://lorenwest.github.com/beaglebone-monitor
var Monitor = require('monitor'),
    Probe = Monitor.Probe,
    Config = Monitor.Config,
    Bonescript = require('bonescript'),
    BBUtils = require('../js/BBUtils'),
    IC595 = require('../js/IC74HC595'),
    logger = Monitor.getLogger('OutputBoard');

/**
* The output board is a series of 74HC595 chips, attached to the main board
* with an ethernet cable.
*
* It can host any number of digital outputs, 8 per 595 chip.
*
* It uses 4 GPIO ports (3 if the initial output isn't important)
*
* IO Board      Wire Color        BeagleBone
* ------------|-----------------|-------------------------------------------
* Ground      | Orange Stripe   | Ground
* +3.3v       | Orange          | +3.3v (Vcc or 3v3)
* +5v         | Green Stripe    | +5v   (Vin)
* data        | Blue            | (specified in initParams.pins)
* clock       | Blue Stripe     | (specified in initParams.pins)
* latch       | Green           | (specified in initParams.pins)
* enable      | Brown Stripe    | (specified in initParams.pins)
* not used    | Brown           | not used
*
* For more information about the board design, see: [TODO]
*
* @class OutputBoard
* @constructor
* @param initParams {Object} Probe initialization parameters
* @param [initParams.bbProbeName] {String} probeName of the BB probe
* @param initParams.pins {Object} BeagleBone I/O pin IDs (ex: P9_22)
* @param initParams.pins.data {String} Pin number for ic595 data
* @param initParams.pins.clock {String} Pin number for ic595 clock
* @param initParams.pins.latch {String} Pin number for ic595 latch
* @param [initParams.pins.enable] {String} Pin number for ic595 enable
* @param initParams.outputs {Object Array} Array defining all output positions.
* @param initParams.outputs.n.name {String} Name of the probe variable to use
* @param [initParams.outputs.n.description] {String} Human description of the input
* @param [initParams.outputs.n.inverse=false] {Boolean} Inverse 0/1? Useful for relay module
* @param [initParams.outputs.n.initialValue=0] {Integer} Initial output value (0 or 1)
*/
var OutputBoard = Probe.extend({

  probeClass: 'OutputBoard',

  // Called by Backbone.Model on object construction
  initialize: function(attributes, options){
    var t = this;

    // Assume callback responsibility
    options.asyncInit = true;
    var callback = options.callback;

    // Assign instance data
    t.pins = attributes.pins;
    t.outputs = attributes.outputs;
    t.numOutputs = t.outputs.length;
    t.num595chips = Math.ceil(t.numOutputs / 8);
    t.ic595 = null;
    t.bbMonitor = null;
    t.validOutputNames = [];
    t.ic595Array = []; // One element per 595 chip
    t.isDisabled = true;
    t.isSendingNow = false;

    // Initialize the 959 array with zeros
    for (var i = 0; i < t.num595chips; i++) {
      t.ic595Array.push(0x00);
    }

    // Connect a monitor to the beaglebone probe
    var initBBMonitor = function() {
      Bonescript.getPlatform(function(platform) {
        if (!platform.serialNumber) {
          logger.info('initialize', 'No beaglebone detected.  Running in emulation mode.');
        }
        t.emulationMode = platform.serialNumber ? false : true;
        t.set('emulationMode', t.emulationMode);
        t.bbMonitor = null;
        if (attributes.bbProbeName) {
          t.bbMonitor = new Monitor({probeName: attributes.bbProbeName});
          t.bbMonitor.connect(function(error) {
            if (error) {
              logger.error('595init.bbMonitor', error);
              return callback(error);
            }
            initIC();
            t.bbMonitor.on('change', t.onBBChange, t);
          });
        }
        else {
          initIC();
        }
      });
    };

    // Called to initialize the IC
    var initIC = function() {
      if (t.emulationMode) {
        return callback();
      }

      // Initialize the 595 library, but keep the chips disabled until
      // the values are set.
      t.isSendingNow = true;
      t.ic595 = new IC595({pins: t.pins, values:t.ic595Array, enabled:false}, function(error) {
        t.isSendingNow = false;
        if (error) {
          logger.error('595init', error);
          return callback(error);
        }

        // Build the named data model elements
        var outputs = {}; // key=name, value=value
        t.outputs.forEach(function(output){
          t.validOutputNames.push(output.name);
          outputs[output.name] = output.initalValue ? 1 : 0;
        });

        // Now set output values
        t.set_control(outputs, callback);
      });
    };

    initBBMonitor();
  },

  // Send the current output states to the 595 array
  sendOutputs: function(callback) {
    var t = this;

    // If sending now, wait a second and try again
    if (t.isSendingNow) {
      setTimeout(function(){t.sendOutputs(callback)},1000);
      return;
    }
    t.isSendingNow = true;

    // Set each output value
    for (var i = 0; i < t.outputs.length; i++) {
      var value = t.get(t.outputs[i].name);
      if (typeof value === 'undefined') {
        value = 0;
      }
      if (t.outputs[i].inverse) {
        value = value ? 0 : 1;
      }
      t.ic595.set(i, value);
    }

    // Now shift them out
    t.ic595.shiftOut(function(error){
      t.isSendingNow = false;
      if (error) {
        return callback(error);
      }

      // If the 595 is disabled, enable it now
      if (t.isDisabled) {
        t.isDisabled = false;
        return t.ic595.enableOutput(callback);
      }
      callback();
    });
  },

  /**
  * Enable or disable the output board pins
  *
  * @method enable_control
  * @param enabled {boolean} Enabled or disabled (t/f)
  * @param callback {function(err)} Called when done or error
  */
  enable_control: function(params, callback) {
    var t = this;
    callback = callback || function(){};
    if (typeof(params.enabled) === 'undefined' || params.enabled) {
      t.ic595.enableOutput(callback);
    }
    else {
      t.ic595.disableOutput(callback);
    }
  },

  /**
  * Called when the monitored BB changes
  *
  * This allows control of this probe by setting the attribute in the BB probe
  */
  onBBChange: function() {
    var t = this,
        changes = {};
    t.validOutputNames.forEach(function(attrName) {
      var attrValue = t.bbMonitor.get(attrName);
      if (attrValue !== t.get(attrName)) {
        changes[attrName] = attrValue;
      }
    });
    if (Monitor._.size(changes)) {
      t.set_control(changes);
    }
  },

  /**
  * Remotely set an output via set
  *
  * This overrides Probe.set_control for settable monitor attributes.  It allows
  * setting pin values by using the remote model.set() method.
  *
  * @method set_control
  * @param outputs {Object} Name/value outputs to set into the probe.  Only names
  *                         defined as outputs can be set by this control, and
  *                         only 0 or 1 are valid values.
  * @param callback {Function(error)} Called when the attributes are set or error
  */
  set_control: function(outputs, callback) {
    var t = this;
    callback = callback || function(){};

    // Validate the param names and values
    var value = null;
    for (var paramName in outputs) {
      if (t.validOutputNames.indexOf(paramName) < 0) {
        var err = {msg: 'Invalid output param: "' + paramName + '"'};
        logger.error('setOutputs', err);
        return callback(err);
      }
      value = outputs[paramName];
      if (value !== 0 && value !== 1) {
        var err = {msg: 'Invalid output value (must be 0 or 1)', value: value};
        logger.error('setOutputs', err);
        return callback(err);
      }
    }

    // Set the output in this model for sendOutputs
    t.set(outputs, {quiet:true});

    // Send outputs to the ICs
    t.sendOutputs(function(){

      // Publish the output values now
      t.set(outputs);

      // Set the values in the central BB probe
      if (t.bbMonitor) {
        t.bbMonitor.set(outputs);
      }

      // We're done
      callback();
    });
  }

});
<commit_msg>Fixed a typo<commit_after>// OutputBoard.js (c) 2013-2014 Loren West
// May be freely distributed under the MIT license.
// For further details and documentation:
// http://lorenwest.github.com/beaglebone-monitor
var Monitor = require('monitor'),
    Probe = Monitor.Probe,
    Config = Monitor.Config,
    Bonescript = require('bonescript'),
    BBUtils = require('../js/BBUtils'),
    IC595 = require('../js/IC74HC595'),
    logger = Monitor.getLogger('OutputBoard');

/**
* The output board is a series of 74HC595 chips, attached to the main board
* with an ethernet cable.
*
* It can host any number of digital outputs, 8 per 595 chip.
*
* It uses 4 GPIO ports (3 if the initial output isn't important)
*
* IO Board      Wire Color        BeagleBone
* ------------|-----------------|-------------------------------------------
* Ground      | Orange Stripe   | Ground
* +3.3v       | Orange          | +3.3v (Vcc or 3v3)
* +5v         | Green Stripe    | +5v   (Vin)
* data        | Blue            | (specified in initParams.pins)
* clock       | Blue Stripe     | (specified in initParams.pins)
* latch       | Green           | (specified in initParams.pins)
* enable      | Brown Stripe    | (specified in initParams.pins)
* not used    | Brown           | not used
*
* For more information about the board design, see: [TODO]
*
* @class OutputBoard
* @constructor
* @param initParams {Object} Probe initialization parameters
* @param [initParams.bbProbeName] {String} probeName of the BB probe
* @param initParams.pins {Object} BeagleBone I/O pin IDs (ex: P9_22)
* @param initParams.pins.data {String} Pin number for ic595 data
* @param initParams.pins.clock {String} Pin number for ic595 clock
* @param initParams.pins.latch {String} Pin number for ic595 latch
* @param [initParams.pins.enable] {String} Pin number for ic595 enable
* @param initParams.outputs {Object Array} Array defining all output positions.
* @param initParams.outputs.n.name {String} Name of the probe variable to use
* @param [initParams.outputs.n.description] {String} Human description of the input
* @param [initParams.outputs.n.inverse=false] {Boolean} Inverse 0/1? Useful for relay module
* @param [initParams.outputs.n.initialValue=0] {Integer} Initial output value (0 or 1)
*/
var OutputBoard = Probe.extend({

  probeClass: 'OutputBoard',

  // Called by Backbone.Model on object construction
  initialize: function(attributes, options){
    var t = this;

    // Assume callback responsibility
    options.asyncInit = true;
    var callback = options.callback;

    // Assign instance data
    t.pins = attributes.pins;
    t.outputs = attributes.outputs;
    t.numOutputs = t.outputs.length;
    t.num595chips = Math.ceil(t.numOutputs / 8);
    t.ic595 = null;
    t.bbMonitor = null;
    t.validOutputNames = [];
    t.ic595Array = []; // One element per 595 chip
    t.isDisabled = true;
    t.isSendingNow = false;

    // Initialize the 959 array with zeros
    for (var i = 0; i < t.num595chips; i++) {
      t.ic595Array.push(0x00);
    }

    // Connect a monitor to the beaglebone probe
    var initBBMonitor = function() {
      Bonescript.getPlatform(function(platform) {
        if (!platform.serialNumber) {
          logger.info('initialize', 'No beaglebone detected.  Running in emulation mode.');
        }
        t.emulationMode = platform.serialNumber ? false : true;
        t.set('emulationMode', t.emulationMode);
        t.bbMonitor = null;
        if (attributes.bbProbeName) {
          t.bbMonitor = new Monitor({probeName: attributes.bbProbeName});
          t.bbMonitor.connect(function(error) {
            if (error) {
              logger.error('595init.bbMonitor', error);
              return callback(error);
            }
            initIC();
            t.bbMonitor.on('change', t.onBBChange, t);
          });
        }
        else {
          initIC();
        }
      });
    };

    // Called to initialize the IC
    var initIC = function() {
      if (t.emulationMode) {
        return callback();
      }

      // Initialize the 595 library, but keep the chips disabled until
      // the values are set.
      t.isSendingNow = true;
      t.ic595 = new IC595({pins: t.pins, values:t.ic595Array, enabled:false}, function(error) {
        t.isSendingNow = false;
        if (error) {
          logger.error('595init', error);
          return callback(error);
        }

        // Build the named data model elements
        var outputs = {}; // key=name, value=value
        t.outputs.forEach(function(output){
          t.validOutputNames.push(output.name);
          outputs[output.name] = output.initialValue ? 1 : 0;
        });

        // Now set output values
        t.set_control(outputs, callback);
      });
    };

    initBBMonitor();
  },

  // Send the current output states to the 595 array
  sendOutputs: function(callback) {
    var t = this;

    // If sending now, wait a second and try again
    if (t.isSendingNow) {
      setTimeout(function(){t.sendOutputs(callback)},1000);
      return;
    }
    t.isSendingNow = true;

    // Set each output value
    for (var i = 0; i < t.outputs.length; i++) {
      var value = t.get(t.outputs[i].name);
      if (typeof value === 'undefined') {
        value = 0;
      }
      if (t.outputs[i].inverse) {
        value = value ? 0 : 1;
      }
      t.ic595.set(i, value);
    }

    // Now shift them out
    t.ic595.shiftOut(function(error){
      t.isSendingNow = false;
      if (error) {
        return callback(error);
      }

      // If the 595 is disabled, enable it now
      if (t.isDisabled) {
        t.isDisabled = false;
        return t.ic595.enableOutput(callback);
      }
      callback();
    });
  },

  /**
  * Enable or disable the output board pins
  *
  * @method enable_control
  * @param enabled {boolean} Enabled or disabled (t/f)
  * @param callback {function(err)} Called when done or error
  */
  enable_control: function(params, callback) {
    var t = this;
    callback = callback || function(){};
    if (typeof(params.enabled) === 'undefined' || params.enabled) {
      t.ic595.enableOutput(callback);
    }
    else {
      t.ic595.disableOutput(callback);
    }
  },

  /**
  * Called when the monitored BB changes
  *
  * This allows control of this probe by setting the attribute in the BB probe
  */
  onBBChange: function() {
    var t = this,
        changes = {};
    t.validOutputNames.forEach(function(attrName) {
      var attrValue = t.bbMonitor.get(attrName);
      if (attrValue !== t.get(attrName)) {
        changes[attrName] = attrValue;
      }
    });
    if (Monitor._.size(changes)) {
      t.set_control(changes);
    }
  },

  /**
  * Remotely set an output via set
  *
  * This overrides Probe.set_control for settable monitor attributes.  It allows
  * setting pin values by using the remote model.set() method.
  *
  * @method set_control
  * @param outputs {Object} Name/value outputs to set into the probe.  Only names
  *                         defined as outputs can be set by this control, and
  *                         only 0 or 1 are valid values.
  * @param callback {Function(error)} Called when the attributes are set or error
  */
  set_control: function(outputs, callback) {
    var t = this;
    callback = callback || function(){};

    // Validate the param names and values
    var value = null;
    for (var paramName in outputs) {
      if (t.validOutputNames.indexOf(paramName) < 0) {
        var err = {msg: 'Invalid output param: "' + paramName + '"'};
        logger.error('setOutputs', err);
        return callback(err);
      }
      value = outputs[paramName];
      if (value !== 0 && value !== 1) {
        var err = {msg: 'Invalid output value (must be 0 or 1)', value: value};
        logger.error('setOutputs', err);
        return callback(err);
      }
    }

    // Set the output in this model for sendOutputs
    t.set(outputs, {quiet:true});

    // Send outputs to the ICs
    t.sendOutputs(function(){

      // Publish the output values now
      t.set(outputs);

      // Set the values in the central BB probe
      if (t.bbMonitor) {
        t.bbMonitor.set(outputs);
      }

      // We're done
      callback();
    });
  }

});
<|endoftext|>