<commit_before>var assert = require("assert");
var http = require('http');
var m2 = require('../m2server-module.js');

describe('Array', function(){
  describe('#indexOf()', function(){
    it('should return -1 when the value is not present', function(){
      assert.equal(-1, [1,2,3].indexOf(5));
      assert.equal(-1, [1,2,3].indexOf(0));
    });
    it('should be true', function() {
        assert(true);
    });
  })
})

describe('assert.notEqual', function() {
    it('should make 1 not equal to null', function() {
        assert.notEqual(1, null);
    })
})

describe('m2server', function(){
    describe('basic behavior', function() {

        it('should be available as a variable', function(done){
            var server = m2.M2Server();
            assert.notEqual(server, null);
            //server.close();
            done();
        });
        it('should not listen without being started', function(done) {
            var http = require('http');
            http.get("http://localhost:8002/", function(res) {
                //console.log("status: " + res.statusCode);
                assert.notEqual(res.statusCode, 200);
            }).on('error', function(e) {
                //console.log("Got error: " + e.message);
                assert.equal(e.message, "connect ECONNREFUSED");
                done();
            });
        });
        it('should be able to create server and get title from html body', function(done){
            //var server = http.createServer(m2server.app);
            var server = m2.M2Server();
            server.listen(8002);
            http.get("http://localhost:8002/", function(res) {
                //console.log(res.statusCode);
                res.on('data', function(body) {
                     //console.log(body.toString('utf-8'));
                     var str = body.toString('utf-8');
                     var n = str.match(/<title>\s*([^\s]*)\s*<\/title>/);
                     assert.equal(n[1], 'Macaulay2');
                     //console.log("The title is: " + n[1]);
                     server.close();
                     done();
                 });
            });
        });
        it('should close the server', function(done) {
            var server = m2.M2Server();
            server.listen(8002);
            server.close();
            var http = require('http');
            http.get("http://localhost:8002/", function(res) {
                assert.notEqual(res.statusCode, 200);
            }).on('error', function(e) {
                //console.log("Got error: " + e.message);
                assert.equal(e.message, "connect ECONNREFUSED");
                done();
            });
        });
    });
    describe('JS on M2 website', function() {
         it('should load content into lesson with JS', function(done) {
                var server = m2.M2Server();
                server.listen(8002);
                http.get("http://localhost:8002/", function(res) {
                    //console.log("!!!!!!!!!");
                    assert.equal(res.statusCode, 200);
                    res.on('data', function(body) {
                         //console.log(body.toString('utf-8'));
                         var str = body.toString('utf-8');
                         var n = str.match(/<title>\s*([^\s]*)\s*<\/title>/);
                         assert.equal(n[1], 'Macaulay2');
                         //console.log("The title is: " + n[1]);
                         server.close();
                         done();
                 });
            });
        });
    });
    describe('advanced behavior', function() {
        it('should be running M2', function(){
            //assert(false);
        });
        it('should calculate 2+2', function() {
            //assert(false);
        });
    });
})

describe('jsdom', function(){
    it('should work with code from jsdom documentation', function(done){
        var jsdom = require('jsdom');

        jsdom.env({
          html: "",
          scripts: [
            'http://code.jquery.com/jquery-1.5.min.js'
          ]
        }, function (err, window) {
          var $ = window.jQuery;

          $('body').append("
Hello World
");
          //console.log($(".testing").text()); // outputs Hello World
          assert.equal($(".testing").text(), 'Hello World');
          done();
        });
    });
    it('should work with fs', function(done) {
        var fs = require('fs');
        var jsdom = require('jsdom');
        var doc   = jsdom.jsdom(fs.readFileSync("tests/test2.html"), null, {
                  features: {
                    FetchExternalResources   : ['script'],
                    ProcessExternalResources : ['script'],
                    MutationEvents           : '2.0',
                }
            });

        var window = doc.createWindow();
        jsdom.jQueryify(window, "http://code.jquery.com/jquery-1.5.min.js", function() {
            var $ = window.jQuery;
            var s = $("h1").text();
            //console.log(s);
            assert.equal(s, 'Before');
            done();
        });
    });
    it('should work with fs and javascript', function(done) {
          var fs = require('fs');
          var jsdom = require('jsdom');
          var doc   = jsdom.jsdom(fs.readFileSync("tests/test.html"), null, {
                    features: {
                      FetchExternalResources   : ['script'],
                      ProcessExternalResources : ['script'],
                      MutationEvents           : '2.0',
                  }
              });

          var window = doc.createWindow();
          jsdom.jQueryify(window, "http://code.jquery.com/jquery-1.5.min.js", function() {
              console.log(window.$().jquery); //jquery version
              var $ = window.jQuery;
              assert.equal($("h1").text(), 'BeforeExternalAfter');
              done();
          });
    });
    it('should work on Lars code', function(done){
        var fs = require('fs');
        var jsdom = require('jsdom');
        var doc   = jsdom.jsdom(fs.readFileSync("./tests/test.html"), null, {
                  features: {
                    FetchExternalResources   : ['script'],
                    ProcessExternalResources : ['script'],
                    MutationEvents           : '2.0',
                }
            });
        var window = doc.createWindow();
        jsdom.jQueryify(window, function() {
            //console.log(window.document.innerHTML);
            var $ = window.jQuery;
            assert.equal($("h1").text(), 'BeforeExternalAfter');
            done();
        });
    });
})

describe('regexsearch', function(){
    it('should find text between title tags', function() {
        var s = 'bla <title> blubb </title> blobber';
        var n = s.match(/<title>\s*([^\s]*)\s*<\/title>/);
        //console.log(n);
        assert.equal(n[1], 'blubb');
        s = 'bla <title> blubb\n </title> blobber';
        var n = s.match(/<title>\s*([^\s]*)\s*<\/title>/);
        assert.equal(n[1], 'blubb');
    })
})

describe('testserver', function() {
    var server;
    before(function(done) {
        var http = require('http');
        server = http.createServer(function (req, res) {
          res.writeHead(200, {'Content-Type': 'text/plain'});
          res.end('Hello World\n');
        }).listen(1337, '127.0.0.1');
        console.log('Server running at http://127.0.0.1:1337/');

        server.on("listening", function() {
            console.log("started");
            done();
        });
    });
    it("Should fetch /", function(done) {
        http.get("http://localhost:1337/", function(res) {
            assert.equal(res.statusCode, 200);
            done();
        });
    });
    it("Should fetch Hello World", function(done) {
        http.get("http://localhost:1337/", function(res) {
            res.on('data', function(body) {
                console.log(body);
                assert.equal(body, "Hello World\n");
                done();
            });
        });
    });

    after(function(done){
      server.close();
      console.log("stopped");
      done();
    });
});

<commit_msg>Test for loading content of lesson<commit_after>var assert = require("assert");
var http = require('http');
var m2 = require('../m2server-module.js');

describe('Array', function(){
  describe('#indexOf()', function(){
    it('should return -1 when the value is not present', function(){
      assert.equal(-1, [1,2,3].indexOf(5));
      assert.equal(-1, [1,2,3].indexOf(0));
    });
    it('should be true', function() {
        assert(true);
    });
  })
})

describe('assert.notEqual', function() {
    it('should make 1 not equal to null', function() {
        assert.notEqual(1, null);
    })
})

describe('m2server', function(){
    describe('basic behavior', function() {

        it('should be available as a variable', function(done){
            var server = m2.M2Server();
            assert.notEqual(server, null);
            //server.close();
            done();
        });
        it('should not listen without being started', function(done) {
            var http = require('http');
            http.get("http://localhost:8002/", function(res) {
                //console.log("status: " + res.statusCode);
                assert.notEqual(res.statusCode, 200);
            }).on('error', function(e) {
                //console.log("Got error: " + e.message);
                assert.equal(e.message, "connect ECONNREFUSED");
                done();
            });
        });
        it('should be able to create server and get title from html body', function(done){
            //var server = http.createServer(m2server.app);
            var server = m2.M2Server();
            server.listen(8002);
            http.get("http://localhost:8002/", function(res) {
                //console.log(res.statusCode);
                res.on('data', function(body) {
                     //console.log(body.toString('utf-8'));
                     var str = body.toString('utf-8');
                     var n = str.match(/<title>\s*([^\s]*)\s*<\/title>/);
                     assert.equal(n[1], 'Macaulay2');
                     //console.log("The title is: " + n[1]);
                     server.close();
                     done();
                 });
            });
        });
        it('should close the server', function(done) {
            var server = m2.M2Server();
            server.listen(8002);
            server.close();
            var http = require('http');
            http.get("http://localhost:8002/", function(res) {
                assert.notEqual(res.statusCode, 200);
            }).on('error', function(e) {
                //console.log("Got error: " + e.message);
                assert.equal(e.message, "connect ECONNREFUSED");
                done();
            });
        });
    });
    describe('JS on M2 website', function() {
         it('should load content into lesson', function(done) {
             var fs = require('fs');
             var jsdom = require('jsdom');
             var doc   = jsdom.jsdom(fs.readFileSync("./public/index.html"), null, {
                       features: {
                         FetchExternalResources   : ['script'],
                         ProcessExternalResources : ['script'],
                         MutationEvents           : '2.0',
                     }
                 });
             var window = doc.createWindow();
             jsdom.jQueryify(window, function() {
                 //console.log(window.document.innerHTML);
                 var $ = window.jQuery;
                 var s = $("#lesson").text();
                 console.log("Lesson:" + s + ":");
                 assert.notEqual(s, "");
                 assert(s.match(/^  Get started by selecting a tutorial or by using the Input Terminal. Have fun!  needsPacka/));
                 done();
             });
        });
    });
    describe('advanced behavior', function() {
        it('should be running M2', function(){
            //assert(false);
        });
        it('should calculate 2+2', function() {
            //assert(false);
        });
    });
})

describe('jsdom', function(){
    it('should work with code from jsdom documentation', function(done){
        var jsdom = require('jsdom');

        jsdom.env({
          html: "",
          scripts: [
            'http://code.jquery.com/jquery-1.5.min.js'
          ]
        }, function (err, window) {
          var $ = window.jQuery;

          $('body').append("
Hello World
");
          //console.log($(".testing").text()); // outputs Hello World
          assert.equal($(".testing").text(), 'Hello World');
          done();
        });
    });
    it('should work with fs', function(done) {
        var fs = require('fs');
        var jsdom = require('jsdom');
        var doc   = jsdom.jsdom(fs.readFileSync("tests/test2.html"), null, {
                  features: {
                    FetchExternalResources   : ['script'],
                    ProcessExternalResources : ['script'],
                    MutationEvents           : '2.0',
                }
            });

        var window = doc.createWindow();
        jsdom.jQueryify(window, "http://code.jquery.com/jquery-1.5.min.js", function() {
            var $ = window.jQuery;
            var s = $("h1").text();
            //console.log(s);
            assert.equal(s, 'Before');
            done();
        });
    });
    it('should work with fs and javascript', function(done) {
          var fs = require('fs');
          var jsdom = require('jsdom');
          var doc   = jsdom.jsdom(fs.readFileSync("tests/test.html"), null, {
                    features: {
                      FetchExternalResources   : ['script'],
                      ProcessExternalResources : ['script'],
                      MutationEvents           : '2.0',
                  }
              });

          var window = doc.createWindow();
          jsdom.jQueryify(window, "http://code.jquery.com/jquery-1.5.min.js", function() {
              console.log(window.$().jquery); //jquery version
              var $ = window.jQuery;
              assert.equal($("h1").text(), 'BeforeExternalAfter');
              done();
          });
    });
    it('should work on Lars code', function(done){
        var fs = require('fs');
        var jsdom = require('jsdom');
        var doc   = jsdom.jsdom(fs.readFileSync("./tests/test.html"), null, {
                  features: {
                    FetchExternalResources   : ['script'],
                    ProcessExternalResources : ['script'],
                    MutationEvents           : '2.0',
                }
            });
        var window = doc.createWindow();
        jsdom.jQueryify(window, function() {
            //console.log(window.document.innerHTML);
            var $ = window.jQuery;
            assert.equal($("h1").text(), 'BeforeExternalAfter');
            done();
        });
    });
})

describe('regexsearch', function(){
    it('should find text between title tags', function() {
        var s = 'bla <title> blubb </title> blobber';
        var n = s.match(/<title>\s*([^\s]*)\s*<\/title>/);
        //console.log(n);
        assert.equal(n[1], 'blubb');
        s = 'bla <title> blubb\n </title> blobber';
        var n = s.match(/<title>\s*([^\s]*)\s*<\/title>/);
        assert.equal(n[1], 'blubb');
    });
    it('should find beginning of string', function() {
       var s = "hello world";
       assert(s.match(/^hello/));
       assert(!false);
       assert(!s.match(/^Hello/));
    });
})

describe('testserver', function() {
    var server;
    before(function(done) {
        var http = require('http');
        server = http.createServer(function (req, res) {
          res.writeHead(200, {'Content-Type': 'text/plain'});
          res.end('Hello World\n');
        }).listen(1337, '127.0.0.1');
        console.log('Server running at http://127.0.0.1:1337/');

        server.on("listening", function() {
            console.log("started");
            done();
        });
    });
    it("Should fetch /", function(done) {
        http.get("http://localhost:1337/", function(res) {
            assert.equal(res.statusCode, 200);
            done();
        });
    });
    it("Should fetch Hello World", function(done) {
        http.get("http://localhost:1337/", function(res) {
            res.on('data', function(body) {
                console.log(body);
                assert.equal(body, "Hello World\n");
                done();
            });
        });
    });

    after(function(done){
      server.close();
      console.log("stopped");
      done();
    });
});

<|endoftext|>


<commit_before>'use strict'
var DropdownPanel = require('./DropdownPanel')
var localDecoder = require('../solidity/localDecoder')
var solidityTypeFormatter = require('./SolidityTypeFormatter')
var yo = require('yo-yo')

class SolidityLocals {

  constructor (_parent, _traceManager, internalTreeCall) {
    this.parent = _parent
    this.internalTreeCall = internalTreeCall
    this.traceManager = _traceManager
    this.basicPanel = new DropdownPanel('Solidity Locals', {
      json: true,
      formatSelf: solidityTypeFormatter.formatSelf,
      extractData: solidityTypeFormatter.extractData
    })
    this.init()
    this.view
  }

  render () {
    this.view = yo`

    ${this.basicPanel.render()}

`
    return this.view
  }

  init () {
    this.parent.event.register('sourceLocationChanged', this, (sourceLocation) => {
      var warningDiv = this.view.querySelector('#warning')
      warningDiv.innerHTML = ''
      this.traceManager.waterfall([
        this.traceManager.getStackAt,
        this.traceManager.getMemoryAt],
        this.parent.currentStepIndex,
        (error, result) => {
          if (!error) {
            var stack = result[0].value
            var memory = result[1].value
            try {
              var locals = localDecoder.solidityLocals(this.parent.currentStepIndex, this.internalTreeCall, stack, memory, sourceLocation)
              this.basicPanel.update(locals)
            } catch (e) {
              warningDiv.innerHTML = e.message
            }
          }
        })
    })
  }
}

module.exports = SolidityLocals
<commit_msg>readd getStorage<commit_after>'use strict'
var DropdownPanel = require('./DropdownPanel')
var localDecoder = require('../solidity/localDecoder')
var solidityTypeFormatter = require('./SolidityTypeFormatter')
var yo = require('yo-yo')

class SolidityLocals {

  constructor (_parent, _traceManager, internalTreeCall) {
    this.parent = _parent
    this.internalTreeCall = internalTreeCall
    this.traceManager = _traceManager
    this.basicPanel = new DropdownPanel('Solidity Locals', {
      json: true,
      formatSelf: solidityTypeFormatter.formatSelf,
      extractData: solidityTypeFormatter.extractData
    })
    this.init()
    this.view
  }

  render () {
    this.view = yo`

    ${this.basicPanel.render()}

`
    return this.view
  }

  init () {
    this.parent.event.register('sourceLocationChanged', this, (sourceLocation) => {
      var warningDiv = this.view.querySelector('#warning')
      warningDiv.innerHTML = ''
      this.traceManager.waterfall([
        this.traceManager.getStackAt,
        this.traceManager.getMemoryAt],
        this.parent.currentStepIndex,
        (error, result) => {
          if (!error) {
            var stack = result[0].value
            var memory = result[1].value
            try {
              this.traceManager.getStorageAt(this.parent.currentStepIndex, this.parent.tx, (error, storage) => {
                if (!error) {
                  var locals = localDecoder.solidityLocals(this.parent.currentStepIndex, this.internalTreeCall, stack, memory, storage, sourceLocation)
                  this.basicPanel.update(locals)
                }
              })
            } catch (e) {
              warningDiv.innerHTML = e.message
            }
          }
        })
    })
  }
}

module.exports = SolidityLocals
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

base.require('base.bbox2');
base.require('base.quad');
base.require('ui.quad_stack');
base.require('ui.quad_view_viewport');
base.require('ui.rect_view');

base.unittest.testSuite('ui.rect_view', function() {

  test('rect_size', function() {
    var quads = [
      base.Quad.FromXYWH(0, 0, 640, 480),
      base.Quad.FromXYWH(0, -100, 640, 480),
      base.Quad.FromXYWH(100, 100, 640, 480)
    ];
    quads[0].stackingGroupId = 0;
    quads[1].stackingGroupId = 1;
    quads[2].stackingGroupId = 2;

    var quadsBbox = new base.BBox2();
    quads.forEach(function(quad) { quadsBbox.addQuad(quad); });

    var stack = new ui.QuadStack();

    var deviceViewportSizeForFrame = {width: 640, height: 480};
    stack.initialize(quadsBbox.asRect(), deviceViewportSizeForFrame);
    stack.quads = quads;

    this.addHTMLOutput(stack);

    var expected = stack.viewport.devicePixelsPerWorldPixel *
        deviceViewportSizeForFrame.width + 'px';

    assertEquals(expected, stack.worldViewportRectView.style.width);

    expected = (stack.viewport.devicePixelsPerWorldPixel *
        deviceViewportSizeForFrame.height) +
        stack.worldViewportRectView_.decorationHeight + 'px';

    assertEquals(expected, stack.worldViewportRectView.style.height);
  });
});
<commit_msg>Disable rect_view.rect_size test, failing on HighDPI<commit_after>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

base.require('base.bbox2');
base.require('base.quad');
base.require('ui.quad_stack');
base.require('ui.quad_view_viewport');
base.require('ui.rect_view');

base.unittest.testSuite('ui.rect_view', function() {

  // TODO(johnjbarton): Fails on HighDPI,
  // https://code.google.com/p/trace-viewer/issues/detail?id=339.
  function FAILS_rect_size() {
    var quads = [
      base.Quad.FromXYWH(0, 0, 640, 480),
      base.Quad.FromXYWH(0, -100, 640, 480),
      base.Quad.FromXYWH(100, 100, 640, 480)
    ];
    quads[0].stackingGroupId = 0;
    quads[1].stackingGroupId = 1;
    quads[2].stackingGroupId = 2;

    var quadsBbox = new base.BBox2();
    quads.forEach(function(quad) { quadsBbox.addQuad(quad); });

    var stack = new ui.QuadStack();

    var deviceViewportSizeForFrame = {width: 640, height: 480};
    stack.initialize(quadsBbox.asRect(), deviceViewportSizeForFrame);
    stack.quads = quads;

    this.addHTMLOutput(stack);

    var expected = stack.viewport.devicePixelsPerWorldPixel *
        deviceViewportSizeForFrame.width + 'px';

    assertEquals(expected, stack.worldViewportRectView.style.width);

    expected = (stack.viewport.devicePixelsPerWorldPixel *
        deviceViewportSizeForFrame.height) +
        stack.worldViewportRectView_.decorationHeight + 'px';

    assertEquals(expected, stack.worldViewportRectView.style.height);
  });
});
<|endoftext|>


<commit_before>var QUnit,
	async = require( "async" ),
	glob = require( "glob" ),
	_ = require( "underscore" ),
	childProcess = require( "child_process" ),
	fs = require( "fs" ),
	path = require( "path" ),
	uuid = require( "uuid" ),
	runningProcesses = [],
	getQUnit = function() {
		if ( !QUnit ) {
			QUnit = require( "./setup" );
		}
		return QUnit;
	};

function havePromises() {
	var nodeVersion = _.map(
		process.versions.node.split( "." ),
		function( item ) {
			return +item;
		} );

	return ( nodeVersion.length > 1 &&
		( nodeVersion[ 0 ] > 0 ||
		nodeVersion[ 0 ] === 0 && nodeVersion[ 1 ] > 11 ) );
}

// Spawn a single child and process its stdout.
function spawnOne( assert, options ) {
	var theChild = childProcess.spawn(
		"node",
		[ options.path ].concat( options.uuid ? [ options.uuid ] : [] ),
		{
			stdio: [ process.stdin, "pipe", process.stderr ]
		} );

	theChild.commandLine = "node" + " " + options.path + " " + options.uuid;
	runningProcesses.push( theChild );

	theChild
		.on( "exit", function( code, signal ) {
			var exitCodeOK = ( code === 0 || code === null ),
				signalOK = ( signal !== "SIGSEGV" );

			assert.ok( exitCodeOK, options.name + " exited successfully (" + code + ")" );
			assert.ok( signalOK, options.name + " did not segfault" );
		} )
		.on( "close", function() {
			var childIndex = runningProcesses.indexOf( theChild );
			if ( childIndex >= 0 ) {
				runningProcesses.splice( childIndex, 1 );
			}
			options.maybeQuit( theChild );
		} );

	// The stdout of the child is a sequence of \n-separated stringified JSON objects.
	theChild.stdout.on( "data", function serverStdoutData( data ) {
		_.each( data.toString().split( "\n" ), function( value ) {
			var jsonObject;

			if ( !value ) {
				return;
			}

			// Attempt to retrieve a JSON object from stdout.
			try {
				jsonObject = JSON.parse( value );
			} catch ( e ) {
				options.teardown( "Error parsing " + options.name + " JSON: '" + value + "'" +
					( e.message ? e.message : e ), true );
			}

			// The child is reporting the number of assertions it will be making. We add our own
			// two assertions ( 1.) successful exit and 2.) no segfault) to that count.
			if ( jsonObject.assertionCount ) {
				options.reportAssertions( jsonObject.assertionCount + 2 );

			// The child has requested a teardown.
			} else if ( jsonObject.teardown ) {
				options.teardown(
					options.name + " requested teardown: " + jsonObject.message );

			// The child has requested that its peer be killed.
			} else if ( jsonObject.killPeer ) {
				options.teardown( null, theChild );

			// The child is reporting that it is ready. Only servers do this.
			} else if ( jsonObject.ready ) {
				if ( options.onReady ) {
					options.onReady();
				}

			// The child is making an assertion.
			} else if ( jsonObject.assertion ) {
				assert[ jsonObject.assertion ].apply( assert, jsonObject.arguments );

			// Otherwise, we have received unknown JSON from the child - bail.
			} else {
				options.teardown( "Unkown JSON from " + options.name + ": " + value, true );
			}
		} );
	} );

	return theChild;
}

function runTestSuites( files ) {
	_.each( files, function( item ) {
		var clientPathIndex,
			clientPaths = glob.sync( path.join( item, "client*.js" ) ),
			serverPath = path.join( item, "server.js" );

		if ( fs.lstatSync( item ).isFile() ) {
			getQUnit().test( path.basename( item ).replace( /\.js$/, "" ), function( assert ) {
				var theChild,
					spawnOptions = {
						uuid: uuid.v4(),
						name: "Test",
						path: item,
						teardown: function() {
							if ( theChild ) {
								theChild.kill( "SIGTERM" );
							}
						},
						maybeQuit: assert.async(),
						reportAssertions: _.bind( assert.expect, assert )
					};
				theChild = spawnOne( assert, spawnOptions );
			} );
			return;
		}

		if ( !fs.lstatSync( item ).isDirectory() ) {
			return;
		}

		for ( clientPathIndex in clientPaths ) {
			if ( !( fs.lstatSync( clientPaths[ clientPathIndex ] ).isFile() ) ) {
				throw new Error( "Cannot find client at " + clientPaths[ clientPathIndex ] );
			}
		}

		if ( !( fs.lstatSync( serverPath ).isFile() ) ) {
			throw new Error( "Cannot find server at " + serverPath );
		}

		getQUnit().test( path.basename( item ), function( assert ) {
			var totalChildren = clientPaths.length + 1,

				// Track the child processes involved in this test in this array
				children = [],

				// When killing child processes in a loop we have to copy the array because it may
				// become modified by the incoming notifications that a process has exited.
				copyChildren = function() {
					var index,
						theCopy = [];

					for ( index in children ) {
						theCopy.push( children[ index ] );
					}

					return theCopy;
				},

				// Turn this test async
				done = assert.async(),

				// Count assertions made by the children. Report them to assert.expect() when both
				// children have reported their number of assertions.
				totalAssertions = 0,
				childrenAssertionsReported = 0,

				spawnOptions = {
					uuid: uuid.v4(),
					teardown: function( error, sourceProcess ) {
						var index,
							signal = error ? "SIGTERM" : "SIGINT",
							copyOfChildren = copyChildren();

						for ( index in copyOfChildren ) {
							if ( sourceProcess && sourceProcess === copyOfChildren[ index ] ) {
								continue;
							}
							copyOfChildren[ index ].kill( signal );
						}

						if ( error ) {
							throw new Error( error );
						}
					},
					maybeQuit: function( theChild ) {
						var childIndex = children.indexOf( theChild );
						if ( childIndex >= 0 ) {
							children.splice( childIndex, 1 );
						}
						if ( children.length === 0 ) {
							done();
						}
					},
					reportAssertions: function( assertionCount ) {
						childrenAssertionsReported++;
						totalAssertions += assertionCount;
						if ( childrenAssertionsReported === totalChildren ) {
							assert.expect( totalAssertions );
						}
					}
				};

			// We run the server first, because the server has to be there before the clients
			// can run. OTOH, the clients may initiate the termination of the test via a non-error
			// teardown request.
			children.push( spawnOne( assert, _.extend( {}, spawnOptions, {
				name: "Server",
				path: serverPath,
				onReady: function() {
					var clientIndex = 0;
					async.eachSeries( clientPaths, function startOneChild( item, callback ) {
						children.push( spawnOne( assert, _.extend( {}, spawnOptions, {
							name: "Client" +
								( clientPaths.length > 1 ? " " + ( ++clientIndex ) : "" ),
						path: item } ) ) );

						// Spawn clients at least two seconds apart to avoid message uniqueness
						// issue in iotivity: https://jira.iotivity.org/browse/IOT-724
						setTimeout( callback, 2000 );
					} );
				}
			} ) ) );
		} );
	} );
}

// Run tests. If no tests were specified on the command line, we scan the tests directory and run
// all the tests we find therein.
runTestSuites( ( ( process.argv.length > 2 ) ?
	( _.map( process.argv[ 2 ].split( "," ), function( item ) {
		return path.join( __dirname, "tests", item );
	} ) ) :
	( glob.sync( path.join( __dirname, "tests", ( havePromises() ? "" : "!(API)" ) + "*" ) ) ) ) );

process.on( "exit", function() {
	var childIndex;

	for ( childIndex in runningProcesses ) {
		runningProcesses[ childIndex ].kill( "SIGTERM" );
	}
} );
<commit_msg>Tests: Runner returns after calling teardown on invalid JSON<commit_after>var QUnit,
	async = require( "async" ),
	glob = require( "glob" ),
	_ = require( "underscore" ),
	childProcess = require( "child_process" ),
	fs = require( "fs" ),
	path = require( "path" ),
	uuid = require( "uuid" ),
	runningProcesses = [],
	getQUnit = function() {
		if ( !QUnit ) {
			QUnit = require( "./setup" );
		}
		return QUnit;
	};

function havePromises() {
	var nodeVersion = _.map(
		process.versions.node.split( "." ),
		function( item ) {
			return +item;
		} );

	return ( nodeVersion.length > 1 &&
		( nodeVersion[ 0 ] > 0 ||
		nodeVersion[ 0 ] === 0 && nodeVersion[ 1 ] > 11 ) );
}

// Spawn a single child and process its stdout.
function spawnOne( assert, options ) {
	var theChild = childProcess.spawn(
		"node",
		[ options.path ].concat( options.uuid ? [ options.uuid ] : [] ),
		{
			stdio: [ process.stdin, "pipe", process.stderr ]
		} );

	theChild.commandLine = "node" + " " + options.path + " " + options.uuid;
	runningProcesses.push( theChild );

	theChild
		.on( "exit", function( code, signal ) {
			var exitCodeOK = ( code === 0 || code === null ),
				signalOK = ( signal !== "SIGSEGV" );

			assert.ok( exitCodeOK, options.name + " exited successfully (" + code + ")" );
			assert.ok( signalOK, options.name + " did not segfault" );
		} )
		.on( "close", function() {
			var childIndex = runningProcesses.indexOf( theChild );
			if ( childIndex >= 0 ) {
				runningProcesses.splice( childIndex, 1 );
			}
			options.maybeQuit( theChild );
		} );

	// The stdout of the child is a sequence of \n-separated stringified JSON objects.
	theChild.stdout.on( "data", function serverStdoutData( data ) {
		_.each( data.toString().split( "\n" ), function( value ) {
			var jsonObject;

			if ( !value ) {
				return;
			}

			// Attempt to retrieve a JSON object from stdout.
			try {
				jsonObject = JSON.parse( value );
			} catch ( e ) {
				options.teardown( "Error parsing " + options.name + " JSON: '" + value + "'" +
					( e.message ? e.message : e ), true );
				return;
			}

			// The child is reporting the number of assertions it will be making. We add our own
			// two assertions ( 1.) successful exit and 2.) no segfault) to that count.
			if ( jsonObject.assertionCount ) {
				options.reportAssertions( jsonObject.assertionCount + 2 );

			// The child has requested a teardown.
			} else if ( jsonObject.teardown ) {
				options.teardown(
					options.name + " requested teardown: " + jsonObject.message );

			// The child has requested that its peer be killed.
			} else if ( jsonObject.killPeer ) {
				options.teardown( null, theChild );

			// The child is reporting that it is ready. Only servers do this.
			} else if ( jsonObject.ready ) {
				if ( options.onReady ) {
					options.onReady();
				}

			// The child is making an assertion.
			} else if ( jsonObject.assertion ) {
				assert[ jsonObject.assertion ].apply( assert, jsonObject.arguments );

			// Otherwise, we have received unknown JSON from the child - bail.
			} else {
				options.teardown( "Unkown JSON from " + options.name + ": " + value, true );
			}
		} );
	} );

	return theChild;
}

function runTestSuites( files ) {
	_.each( files, function( item ) {
		var clientPathIndex,
			clientPaths = glob.sync( path.join( item, "client*.js" ) ),
			serverPath = path.join( item, "server.js" );

		if ( fs.lstatSync( item ).isFile() ) {
			getQUnit().test( path.basename( item ).replace( /\.js$/, "" ), function( assert ) {
				var theChild,
					spawnOptions = {
						uuid: uuid.v4(),
						name: "Test",
						path: item,
						teardown: function() {
							if ( theChild ) {
								theChild.kill( "SIGTERM" );
							}
						},
						maybeQuit: assert.async(),
						reportAssertions: _.bind( assert.expect, assert )
					};
				theChild = spawnOne( assert, spawnOptions );
			} );
			return;
		}

		if ( !fs.lstatSync( item ).isDirectory() ) {
			return;
		}

		for ( clientPathIndex in clientPaths ) {
			if ( !( fs.lstatSync( clientPaths[ clientPathIndex ] ).isFile() ) ) {
				throw new Error( "Cannot find client at " + clientPaths[ clientPathIndex ] );
			}
		}

		if ( !( fs.lstatSync( serverPath ).isFile() ) ) {
			throw new Error( "Cannot find server at " + serverPath );
		}

		getQUnit().test( path.basename( item ), function( assert ) {
			var totalChildren = clientPaths.length + 1,

				// Track the child processes involved in this test in this array
				children = [],

				// When killing child processes in a loop we have to copy the array because it may
				// become modified by the incoming notifications that a process has exited.
				copyChildren = function() {
					var index,
						theCopy = [];

					for ( index in children ) {
						theCopy.push( children[ index ] );
					}

					return theCopy;
				},

				// Turn this test async
				done = assert.async(),

				// Count assertions made by the children. Report them to assert.expect() when both
				// children have reported their number of assertions.
				totalAssertions = 0,
				childrenAssertionsReported = 0,

				spawnOptions = {
					uuid: uuid.v4(),
					teardown: function( error, sourceProcess ) {
						var index,
							signal = error ? "SIGTERM" : "SIGINT",
							copyOfChildren = copyChildren();

						for ( index in copyOfChildren ) {
							if ( sourceProcess && sourceProcess === copyOfChildren[ index ] ) {
								continue;
							}
							copyOfChildren[ index ].kill( signal );
						}

						if ( error ) {
							throw new Error( error );
						}
					},
					maybeQuit: function( theChild ) {
						var childIndex = children.indexOf( theChild );
						if ( childIndex >= 0 ) {
							children.splice( childIndex, 1 );
						}
						if ( children.length === 0 ) {
							done();
						}
					},
					reportAssertions: function( assertionCount ) {
						childrenAssertionsReported++;
						totalAssertions += assertionCount;
						if ( childrenAssertionsReported === totalChildren ) {
							assert.expect( totalAssertions );
						}
					}
				};

			// We run the server first, because the server has to be there before the clients
			// can run. OTOH, the clients may initiate the termination of the test via a non-error
			// teardown request.
			children.push( spawnOne( assert, _.extend( {}, spawnOptions, {
				name: "Server",
				path: serverPath,
				onReady: function() {
					var clientIndex = 0;
					async.eachSeries( clientPaths, function startOneChild( item, callback ) {
						children.push( spawnOne( assert, _.extend( {}, spawnOptions, {
							name: "Client" +
								( clientPaths.length > 1 ? " " + ( ++clientIndex ) : "" ),
						path: item } ) ) );

						// Spawn clients at least two seconds apart to avoid message uniqueness
						// issue in iotivity: https://jira.iotivity.org/browse/IOT-724
						setTimeout( callback, 2000 );
					} );
				}
			} ) ) );
		} );
	} );
}

// Run tests. If no tests were specified on the command line, we scan the tests directory and run
// all the tests we find therein.
runTestSuites( ( ( process.argv.length > 2 ) ?
	( _.map( process.argv[ 2 ].split( "," ), function( item ) {
		return path.join( __dirname, "tests", item );
	} ) ) :
	( glob.sync( path.join( __dirname, "tests", ( havePromises() ? "" : "!(API)" ) + "*" ) ) ) ) );

process.on( "exit", function() {
	var childIndex;

	for ( childIndex in runningProcesses ) {
		runningProcesses[ childIndex ].kill( "SIGTERM" );
	}
} );
<|endoftext|>


<commit_before>/*
Copyright 2018 New Vector Ltd

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

const assert = require('assert');

module.exports.scrollToTimelineTop = async function(session) {
    session.log.step(`scrolls to the top of the timeline`);
    await session.page.evaluate(() => {
        return Promise.resolve().then(async () => {
            const timelineScrollView = document.querySelector(".mx_RoomView .gm-scroll-view");
            let timedOut = false;
            let timeoutHandle = null;
            // set scrollTop to 0 in a loop and check every 50ms
            // if content became available (scrollTop not being 0 anymore),
            // assume everything is loaded after 3s
            do {
                if (timelineScrollView.scrollTop !== 0) {
                    if (timeoutHandle) {
                        clearTimeout(timeoutHandle);
                    }
                    timeoutHandle = setTimeout(() => timedOut = true, 3000);
                    timelineScrollView.scrollTop = 0;
                } else {
                    await new Promise((resolve) => setTimeout(resolve, 50));
                }
            } while (!timedOut)
        });
    })
    session.log.done();
}

module.exports.receiveMessage = async function(session, expectedMessage) {
    session.log.step(`receives message "${expectedMessage.body}" from ${expectedMessage.sender}`);
    // wait for a response to come in that contains the message
    // crude, but effective

    async function getLastMessage() {
        const lastTile = await getLastEventTile(session);
        return getMessageFromEventTile(lastTile);
    }

    let lastMessage = null;
    let isExpectedMessage = false;
    let totalTime = 0;
    while (!isExpectedMessage) {
        try {
            lastMessage = await getLastMessage();
            isExpectedMessage = lastMessage &&
                lastMessage.body === expectedMessage.body &&
                lastMessage.sender === expectedMessage.sender
        } catch(err) {}
        if (totalTime > 5000) {
            throw new Error("timed out after 5000ms");
        }
        totalTime += 200;
        await session.delay(200);
    }
    assertMessage(lastMessage, expectedMessage);
    session.log.done();
}

module.exports.checkTimelineContains = async function (session, expectedMessages, sendersDescription) {
    session.log.step(`checks timeline contains ${expectedMessages.length} ` +
        `given messages${sendersDescription ? ` from ${sendersDescription}`:""}`);
    const eventTiles = await getAllEventTiles(session);
    let timelineMessages = await Promise.all(eventTiles.map((eventTile) => {
        return getMessageFromEventTile(eventTile);
    }));
    //filter out tiles that were not messages
    timelineMessages = timelineMessages .filter((m) => !!m);
    expectedMessages.forEach((expectedMessage) => {
        const foundMessage = timelineMessages.find((message) => {
            return message.sender === expectedMessage.sender &&
                   message.body === expectedMessage.body;
        });
        assertMessage(foundMessage, expectedMessage);
    });

    session.log.done();
}

function assertMessage(foundMessage, expectedMessage) {
    assert(foundMessage, `message ${JSON.stringify(expectedMessage)} not found in timeline`);
    assert.equal(foundMessage.body, expectedMessage.body);
    assert.equal(foundMessage.sender, expectedMessage.sender);
    if (expectedMessage.hasOwnProperty("encrypted")) {
        assert.equal(foundMessage.encrypted, expectedMessage.encrypted);
    }
}

function getLastEventTile(session) {
    return session.query(".mx_EventTile_last");
}

function getAllEventTiles(session) {
    return session.queryAll(".mx_RoomView_MessageList .mx_EventTile");
}

async function getMessageFromEventTile(eventTile) {
    const senderElement = await eventTile.$(".mx_SenderProfile_name");
    const className = await (await eventTile.getProperty("className")).jsonValue();
    const classNames = className.split(" ");
    const bodyElement = await eventTile.$(".mx_EventTile_body");
    let sender = null;
    if (senderElement) {
        sender = await(await senderElement.getProperty("innerText")).jsonValue();
    }
    if (!bodyElement) {
        return null;
    }
    const body = await(await bodyElement.getProperty("innerText")).jsonValue();

    return {
        sender,
        body,
        encrypted: classNames.includes("mx_EventTile_verified")
    };
}
<commit_msg>fix scrollpanel selector<commit_after>/*
Copyright 2018 New Vector Ltd

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

const assert = require('assert');

module.exports.scrollToTimelineTop = async function(session) {
    session.log.step(`scrolls to the top of the timeline`);
    await session.page.evaluate(() => {
        return Promise.resolve().then(async () => {
            const timelineScrollView = document.querySelector(".mx_RoomView_timeline .mx_ScrollPanel");
            let timedOut = false;
            let timeoutHandle = null;
            // set scrollTop to 0 in a loop and check every 50ms
            // if content became available (scrollTop not being 0 anymore),
            // assume everything is loaded after 3s
            do {
                if (timelineScrollView.scrollTop !== 0) {
                    if (timeoutHandle) {
                        clearTimeout(timeoutHandle);
                    }
                    timeoutHandle = setTimeout(() => timedOut = true, 3000);
                    timelineScrollView.scrollTop = 0;
                } else {
                    await new Promise((resolve) => setTimeout(resolve, 50));
                }
            } while (!timedOut)
        });
    })
    session.log.done();
}

module.exports.receiveMessage = async function(session, expectedMessage) {
    session.log.step(`receives message "${expectedMessage.body}" from ${expectedMessage.sender}`);
    // wait for a response to come in that contains the message
    // crude, but effective

    async function getLastMessage() {
        const lastTile = await getLastEventTile(session);
        return getMessageFromEventTile(lastTile);
    }

    let lastMessage = null;
    let isExpectedMessage = false;
    let totalTime = 0;
    while (!isExpectedMessage) {
        try {
            lastMessage = await getLastMessage();
            isExpectedMessage = lastMessage &&
                lastMessage.body === expectedMessage.body &&
                lastMessage.sender === expectedMessage.sender
        } catch(err) {}
        if (totalTime > 5000) {
            throw new Error("timed out after 5000ms");
        }
        totalTime += 200;
        await session.delay(200);
    }
    assertMessage(lastMessage, expectedMessage);
    session.log.done();
}

module.exports.checkTimelineContains = async function (session, expectedMessages, sendersDescription) {
    session.log.step(`checks timeline contains ${expectedMessages.length} ` +
        `given messages${sendersDescription ? ` from ${sendersDescription}`:""}`);
    const eventTiles = await getAllEventTiles(session);
    let timelineMessages = await Promise.all(eventTiles.map((eventTile) => {
        return getMessageFromEventTile(eventTile);
    }));
    //filter out tiles that were not messages
    timelineMessages = timelineMessages .filter((m) => !!m);
    expectedMessages.forEach((expectedMessage) => {
        const foundMessage = timelineMessages.find((message) => {
            return message.sender === expectedMessage.sender &&
                   message.body === expectedMessage.body;
        });
        assertMessage(foundMessage, expectedMessage);
    });

    session.log.done();
}

function assertMessage(foundMessage, expectedMessage) {
    assert(foundMessage, `message ${JSON.stringify(expectedMessage)} not found in timeline`);
    assert.equal(foundMessage.body, expectedMessage.body);
    assert.equal(foundMessage.sender, expectedMessage.sender);
    if (expectedMessage.hasOwnProperty("encrypted")) {
        assert.equal(foundMessage.encrypted, expectedMessage.encrypted);
    }
}

function getLastEventTile(session) {
    return session.query(".mx_EventTile_last");
}

function getAllEventTiles(session) {
    return session.queryAll(".mx_RoomView_MessageList .mx_EventTile");
}

async function getMessageFromEventTile(eventTile) {
    const senderElement = await eventTile.$(".mx_SenderProfile_name");
    const className = await (await eventTile.getProperty("className")).jsonValue();
    const classNames = className.split(" ");
    const bodyElement = await eventTile.$(".mx_EventTile_body");
    let sender = null;
    if (senderElement) {
        sender = await(await senderElement.getProperty("innerText")).jsonValue();
    }
    if (!bodyElement) {
        return null;
    }
    const body = await(await bodyElement.getProperty("innerText")).jsonValue();

    return {
        sender,
        body,
        encrypted: classNames.includes("mx_EventTile_verified")
    };
}
<|endoftext|>


<commit_before>define(['../EventEmitter'], function(EventEmitter) {
	// Configure the tests
	describe('getListeners', function() {
		var ee;

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('initialises the event object and a listener array', function() {
			ee.getListeners('foo');
			expect(ee._events).toEqual({
				foo: []
			});
		});

		it('does not overwrite listener arrays', function() {
			var listeners = ee.getListeners('foo');
			listeners.push('bar');

			expect(ee._events).toEqual({
				foo: ['bar']
			});

			ee.getListeners('foo');

			expect(ee._events).toEqual({
				foo: ['bar']
			});
		});

		it('allows you to fetch listeners by regex', function ()
		{
			var count = 0;

			ee.addListener('foo', function() { count++; });
			ee.addListener('bar', function() { count++; return 'bar'; });
			ee.addListener('baz', function() { count++; return 'baz'; });

			var listeners = ee.getListeners(/ba[rz]/);

			expect(listeners.length).toEqual(2);
			expect(listeners[0]()).toEqual('bar');
			expect(listeners[1]()).toEqual('baz');
		});
	});

	describe('addListener', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){};

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('adds a listener to the specified event', function() {
			ee.addListener('foo', fn1);
			expect(ee.getListeners('foo')).toEqual([fn1]);
		});

		it('does not allow duplicate listeners', function() {
			ee.addListener('bar', fn1);
			expect(ee.getListeners('bar')).toEqual([fn1]);

			ee.addListener('bar', fn2);
			expect(ee.getListeners('bar')).toEqual([fn1, fn2]);

			ee.addListener('bar', fn1);
			expect(ee.getListeners('bar')).toEqual([fn1, fn2]);
		});
	});

	describe('removeListener', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){},
			fn3 = function(){},
			fn4 = function(){},
			fnX = function(){};

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('does nothing when the listener is not found', function() {
			var orig = ee.getListeners('foo').length;
			ee.removeListener('foo', fn1);
			expect(ee.getListeners('foo').length).toEqual(orig);
		});

		it('can handle removing events that have not been added', function() {
			expect(ee._events).toBeUndefined();
			ee.removeEvent('foo');
			expect(ee._events).not.toBeUndefined();
		});

		it('actually removes events', function() {
			ee.removeEvent('foo');
			expect(ee._events.foo).toBeUndefined();
		});

		it('removes listeners', function() {
			var listeners = ee.getListeners('bar');

			ee.addListener('bar', fn1);
			ee.addListener('bar', fn2);
			ee.addListener('bar', fn3);
			ee.addListener('bar', fn3); // Make sure doubling up does nothing
			ee.addListener('bar', fn4);
			expect(listeners).toEqual([fn1, fn2, fn3, fn4]);

			ee.removeListener('bar', fn3);
			expect(listeners).toEqual([fn1, fn2, fn4]);

			ee.removeListener('bar', fnX);
			expect(listeners).toEqual([fn1, fn2, fn4]);

			ee.removeListener('bar', fn1);
			expect(listeners).toEqual([fn2, fn4]);

			ee.removeListener('bar', fn4);
			expect(listeners).toEqual([fn2]);

			ee.removeListener('bar', fn2);
			expect(ee._events.bar).toEqual(undefined);
		});
	});

	describe('removeEvent', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){},
			fn3 = function(){},
			fn4 = function(){},
			fn5 = function(){};

		beforeEach(function() {
			ee = new EventEmitter();

			ee.addListener('foo', fn1);
			ee.addListener('foo', fn2);
			ee.addListener('bar', fn3);
			ee.addListener('bar', fn4);
			ee.addListener('baz', fn5);
			expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
			expect(ee.getListeners('bar')).toEqual([fn3, fn4]);
			expect(ee.getListeners('baz')).toEqual([fn5]);
		});

		it('removes all listeners for the specified event', function() {
			ee.removeEvent('bar');
			expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
			expect(ee.getListeners('bar')).toEqual([]);
			expect(ee.getListeners('baz')).toEqual([fn5]);

			ee.removeEvent('baz');
			expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
			expect(ee.getListeners('bar')).toEqual([]);
			expect(ee.getListeners('baz')).toEqual([]);
		});

		it('removes all events when no event is specified', function() {
			ee.removeEvent();
			expect(ee.getListeners('foo')).toEqual([]);
			expect(ee.getListeners('bar')).toEqual([]);
			expect(ee.getListeners('baz')).toEqual([]);
		});

		it('removes listeners when passed a regex', function ()
		{
			var count = 0;
			ee.removeEvent();

			ee.addListener('foo', function() { count++; return 'foo'; });
			ee.addListener('bar', function() { count++; return 'bar'; });
			ee.addListener('baz', function() { count++; return 'baz'; });

			ee.removeEvent(/ba[rz]/);
			var listeners = ee.getListeners('foo');

			expect(listeners.length).toEqual(1);
			expect(listeners[0]()).toEqual('foo');
		});
	});

	describe('emitEvent', function() {
		var ee;

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('executes attached listeners', function() {
			var run = false;

			ee.addListener('foo', function() {
				run = true;
			});
			ee.emitEvent('foo');

			expect(run).toEqual(true);
		});

		it('executes attached with a single argument', function() {
			var key = null;

			ee.addListener('bar', function(a) {
				key = a;
			});
			ee.emitEvent('bar', [50]);

			expect(key).toEqual(50);

			ee.emit('bar', 60);
			expect(key).toEqual(60);
		});

		it('executes attached with arguments', function() {
			var key = null;

			ee.addListener('bar2', function(a, b) {
				key = a + b;
			});
			ee.emitEvent('bar2', [40, 2]);

			expect(key).toEqual(42);
		});

		it('executes multiple listeners', function() {
			var count = 0;

			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });

			ee.emitEvent('baz');

			expect(count).toEqual(5);
		});

		it('executes multiple listeners after one has been removed', function() {
			var count = 0,
				toRemove = function() { count++; };

			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', toRemove);
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });

			ee.removeListener('baz', toRemove);

			ee.emitEvent('baz');

			expect(count).toEqual(4);
		});

		it('executes multiple listeners and removes those that return true', function() {
			var count = 0;

			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; return true; });
			ee.addListener('baz', function() { count++; return false; });
			ee.addListener('baz', function() { count++; return 1; });
			ee.addListener('baz', function() { count++; return true; });

			ee.emitEvent('baz');
			ee.emitEvent('baz');

			expect(count).toEqual(8);
		});

		it('executes all listeners that match a regular expression', function ()
		{
			var count = 0;

			ee.addListener('foo', function() { count++; });
			ee.addListener('bar', function() { count++; });
			ee.addListener('baz', function() { count++; });

			ee.emitEvent(/ba[rz]/);
			expect(count).toEqual(2);
		});
	});

	describe('manipulateListeners', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){},
			fn3 = function(){},
			fn4 = function(){},
			fn5 = function(){};

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('manipulates multiple with an array', function() {
			ee.manipulateListeners(false, 'foo', [fn1, fn2, fn3, fn4, fn5]);
			expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3, fn2, fn1]);

			ee.manipulateListeners(true, 'foo', [fn1, fn2]);
			expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3]);

			ee.manipulateListeners(true, 'foo', [fn3, fn5]);
			ee.manipulateListeners(false, 'foo', [fn4, fn1]);
			expect(ee.getListeners('foo')).toEqual([fn4, fn1]);

			ee.manipulateListeners(true, 'foo', [fn4, fn1]);
			expect(ee.getListeners('foo')).toEqual([]);
		});

		it('manipulates with an object', function() {
			ee.manipulateListeners(false, {
				foo: [fn1, fn2, fn3],
				bar: fn4
			});

			ee.manipulateListeners(false, {
				bar: [fn5, fn1]
			});

			expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1]);
			expect(ee.getListeners('bar')).toEqual([fn4, fn1, fn5]);

			ee.manipulateListeners(true, {
				foo: fn1,
				bar: [fn5, fn4]
			});

			expect(ee.getListeners('foo')).toEqual([fn3, fn2]);
			expect(ee.getListeners('bar')).toEqual([fn1]);

			ee.manipulateListeners(true, {
				foo: [fn3, fn2],
				bar: fn1
			});

			expect(ee.getListeners('foo')).toEqual([]);
			expect(ee.getListeners('bar')).toEqual([]);
		});

		it('does not execute listeners just after they are added in another listeners', function() {
			var count = 0;

			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() {
				count++;

				ee.addListener('baz', function() {
					count++;
				});
			});
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });

			ee.emitEvent('baz');

			expect(count).toEqual(5);
		});
	});

	describe('addListeners', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){},
			fn3 = function(){},
			fn4 = function(){},
			fn5 = function(){};

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('adds with an array', function() {
			ee.addListeners('foo', [fn1, fn2, fn3]);
			expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1]);

			ee.addListeners('foo', [fn4, fn5]);
			expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1, fn5, fn4]);
		});

		it('adds with an object', function() {
			ee.addListeners({
				foo: fn1,
				bar: [fn2, fn3]
			});
			expect(ee.getListeners('foo')).toEqual([fn1]);
			expect(ee.getListeners('bar')).toEqual([fn3, fn2]);

			ee.addListeners({
				foo: [fn4],
				bar: fn5
			});
			expect(ee.getListeners('foo')).toEqual([fn1, fn4]);
			expect(ee.getListeners('bar')).toEqual([fn3, fn2, fn5]);
		});
	});

	describe('removeListeners', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){},
			fn3 = function(){},
			fn4 = function(){},
			fn5 = function(){};

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('removes with an array', function() {
			ee.addListeners('foo', [fn1, fn2, fn3, fn4, fn5]);
			ee.removeListeners('foo', [fn2, fn3]);
			expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn1]);

			ee.removeListeners('foo', [fn5, fn4]);
			expect(ee.getListeners('foo')).toEqual([fn1]);

			ee.removeListeners('foo', [fn1]);
			expect(ee.getListeners('foo')).toEqual([]);
		});

		it('removes with an object', function() {
			ee.addListeners({
				foo: [fn1, fn2, fn3, fn4, fn5],
				bar: [fn1, fn2, fn3, fn4, fn5]
			});

			ee.removeListeners({
				foo: fn2,
				bar: [fn3, fn4, fn5]
			});
			expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3, fn1]);
			expect(ee.getListeners('bar')).toEqual([fn2, fn1]);

			ee.removeListeners({
				foo: [fn3],
				bar: [fn2, fn1]
			});
			expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn1]);
			expect(ee.getListeners('bar')).toEqual([]);
		});
	});
});<commit_msg>Added removeListener(s) regex tests. #39<commit_after>define(['../EventEmitter'], function(EventEmitter) {
	// Configure the tests
	describe('getListeners', function() {
		var ee;

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('initialises the event object and a listener array', function() {
			ee.getListeners('foo');
			expect(ee._events).toEqual({
				foo: []
			});
		});

		it('does not overwrite listener arrays', function() {
			var listeners = ee.getListeners('foo');
			listeners.push('bar');

			expect(ee._events).toEqual({
				foo: ['bar']
			});

			ee.getListeners('foo');

			expect(ee._events).toEqual({
				foo: ['bar']
			});
		});

		it('allows you to fetch listeners by regex', function ()
		{
			var count = 0;

			ee.addListener('foo', function() { count++; });
			ee.addListener('bar', function() { count++; return 'bar'; });
			ee.addListener('baz', function() { count++; return 'baz'; });

			var listeners = ee.getListeners(/ba[rz]/);

			expect(listeners.length).toEqual(2);
			expect(listeners[0]()).toEqual('bar');
			expect(listeners[1]()).toEqual('baz');
		});
	});

	describe('addListener', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){};

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('adds a listener to the specified event', function() {
			ee.addListener('foo', fn1);
			expect(ee.getListeners('foo')).toEqual([fn1]);
		});

		it('does not allow duplicate listeners', function() {
			ee.addListener('bar', fn1);
			expect(ee.getListeners('bar')).toEqual([fn1]);

			ee.addListener('bar', fn2);
			expect(ee.getListeners('bar')).toEqual([fn1, fn2]);

			ee.addListener('bar', fn1);
			expect(ee.getListeners('bar')).toEqual([fn1, fn2]);
		});
	});

	describe('removeListener', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){},
			fn3 = function(){},
			fn4 = function(){},
			fnX = function(){};

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('does nothing when the listener is not found', function() {
			var orig = ee.getListeners('foo').length;
			ee.removeListener('foo', fn1);
			expect(ee.getListeners('foo').length).toEqual(orig);
		});

		it('can handle removing events that have not been added', function() {
			expect(ee._events).toBeUndefined();
			ee.removeEvent('foo');
			expect(ee._events).not.toBeUndefined();
		});

		it('actually removes events', function() {
			ee.removeEvent('foo');
			expect(ee._events.foo).toBeUndefined();
		});

		it('removes listeners', function() {
			var listeners = ee.getListeners('bar');

			ee.addListener('bar', fn1);
			ee.addListener('bar', fn2);
			ee.addListener('bar', fn3);
			ee.addListener('bar', fn3); // Make sure doubling up does nothing
			ee.addListener('bar', fn4);
			expect(listeners).toEqual([fn1, fn2, fn3, fn4]);

			ee.removeListener('bar', fn3);
			expect(listeners).toEqual([fn1, fn2, fn4]);

			ee.removeListener('bar', fnX);
			expect(listeners).toEqual([fn1, fn2, fn4]);

			ee.removeListener('bar', fn1);
			expect(listeners).toEqual([fn2, fn4]);

			ee.removeListener('bar', fn4);
			expect(listeners).toEqual([fn2]);

			ee.removeListener('bar', fn2);
			expect(ee._events.bar).toEqual(undefined);
		});

		it('removes with a regex', function() {
			ee.addListeners({
				foo: [fn1, fn2, fn3, fn4, fn5],
				bar: [fn1, fn2, fn3, fn4, fn5],
				baz: [fn1, fn2, fn3, fn4, fn5]
			});

			ee.removeListener(/ba[rz]/, fn3);
			expect(ee.getListeners('foo')).toEqual([fn1, fn2, fn3, fn4, fn5]);
			expect(ee.getListeners('bar')).toEqual([fn1, fn2, fn4, fn5]);
			expect(ee.getListeners('baz')).toEqual([fn1, fn2, fn4, fn5]);
		});
	});

	describe('removeEvent', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){},
			fn3 = function(){},
			fn4 = function(){},
			fn5 = function(){};

		beforeEach(function() {
			ee = new EventEmitter();

			ee.addListener('foo', fn1);
			ee.addListener('foo', fn2);
			ee.addListener('bar', fn3);
			ee.addListener('bar', fn4);
			ee.addListener('baz', fn5);
			expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
			expect(ee.getListeners('bar')).toEqual([fn3, fn4]);
			expect(ee.getListeners('baz')).toEqual([fn5]);
		});

		it('removes all listeners for the specified event', function() {
			ee.removeEvent('bar');
			expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
			expect(ee.getListeners('bar')).toEqual([]);
			expect(ee.getListeners('baz')).toEqual([fn5]);

			ee.removeEvent('baz');
			expect(ee.getListeners('foo')).toEqual([fn1, fn2]);
			expect(ee.getListeners('bar')).toEqual([]);
			expect(ee.getListeners('baz')).toEqual([]);
		});

		it('removes all events when no event is specified', function() {
			ee.removeEvent();
			expect(ee.getListeners('foo')).toEqual([]);
			expect(ee.getListeners('bar')).toEqual([]);
			expect(ee.getListeners('baz')).toEqual([]);
		});

		it('removes listeners when passed a regex', function ()
		{
			var count = 0;
			ee.removeEvent();

			ee.addListener('foo', function() { count++; return 'foo'; });
			ee.addListener('bar', function() { count++; return 'bar'; });
			ee.addListener('baz', function() { count++; return 'baz'; });

			ee.removeEvent(/ba[rz]/);
			var listeners = ee.getListeners('foo');

			expect(listeners.length).toEqual(1);
			expect(listeners[0]()).toEqual('foo');
		});
	});

	describe('emitEvent', function() {
		var ee;

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('executes attached listeners', function() {
			var run = false;

			ee.addListener('foo', function() {
				run = true;
			});
			ee.emitEvent('foo');

			expect(run).toEqual(true);
		});

		it('executes attached with a single argument', function() {
			var key = null;

			ee.addListener('bar', function(a) {
				key = a;
			});
			ee.emitEvent('bar', [50]);

			expect(key).toEqual(50);

			ee.emit('bar', 60);
			expect(key).toEqual(60);
		});

		it('executes attached with arguments', function() {
			var key = null;

			ee.addListener('bar2', function(a, b) {
				key = a + b;
			});
			ee.emitEvent('bar2', [40, 2]);

			expect(key).toEqual(42);
		});

		it('executes multiple listeners', function() {
			var count = 0;

			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });

			ee.emitEvent('baz');

			expect(count).toEqual(5);
		});

		it('executes multiple listeners after one has been removed', function() {
			var count = 0,
				toRemove = function() { count++; };

			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', toRemove);
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });

			ee.removeListener('baz', toRemove);

			ee.emitEvent('baz');

			expect(count).toEqual(4);
		});

		it('executes multiple listeners and removes those that return true', function() {
			var count = 0;

			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; return true; });
			ee.addListener('baz', function() { count++; return false; });
			ee.addListener('baz', function() { count++; return 1; });
			ee.addListener('baz', function() { count++; return true; });

			ee.emitEvent('baz');
			ee.emitEvent('baz');

			expect(count).toEqual(8);
		});

		it('executes all listeners that match a regular expression', function ()
		{
			var count = 0;

			ee.addListener('foo', function() { count++; });
			ee.addListener('bar', function() { count++; });
			ee.addListener('baz', function() { count++; });

			ee.emitEvent(/ba[rz]/);
			expect(count).toEqual(2);
		});
	});

	describe('manipulateListeners', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){},
			fn3 = function(){},
			fn4 = function(){},
			fn5 = function(){};

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('manipulates multiple with an array', function() {
			ee.manipulateListeners(false, 'foo', [fn1, fn2, fn3, fn4, fn5]);
			expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3, fn2, fn1]);

			ee.manipulateListeners(true, 'foo', [fn1, fn2]);
			expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3]);

			ee.manipulateListeners(true, 'foo', [fn3, fn5]);
			ee.manipulateListeners(false, 'foo', [fn4, fn1]);
			expect(ee.getListeners('foo')).toEqual([fn4, fn1]);

			ee.manipulateListeners(true, 'foo', [fn4, fn1]);
			expect(ee.getListeners('foo')).toEqual([]);
		});

		it('manipulates with an object', function() {
			ee.manipulateListeners(false, {
				foo: [fn1, fn2, fn3],
				bar: fn4
			});

			ee.manipulateListeners(false, {
				bar: [fn5, fn1]
			});

			expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1]);
			expect(ee.getListeners('bar')).toEqual([fn4, fn1, fn5]);

			ee.manipulateListeners(true, {
				foo: fn1,
				bar: [fn5, fn4]
			});

			expect(ee.getListeners('foo')).toEqual([fn3, fn2]);
			expect(ee.getListeners('bar')).toEqual([fn1]);

			ee.manipulateListeners(true, {
				foo: [fn3, fn2],
				bar: fn1
			});

			expect(ee.getListeners('foo')).toEqual([]);
			expect(ee.getListeners('bar')).toEqual([]);
		});

		it('does not execute listeners just after they are added in another listeners', function() {
			var count = 0;

			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() {
				count++;

				ee.addListener('baz', function() {
					count++;
				});
			});
			ee.addListener('baz', function() { count++; });
			ee.addListener('baz', function() { count++; });

			ee.emitEvent('baz');

			expect(count).toEqual(5);
		});
	});

	describe('addListeners', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){},
			fn3 = function(){},
			fn4 = function(){},
			fn5 = function(){};

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('adds with an array', function() {
			ee.addListeners('foo', [fn1, fn2, fn3]);
			expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1]);

			ee.addListeners('foo', [fn4, fn5]);
			expect(ee.getListeners('foo')).toEqual([fn3, fn2, fn1, fn5, fn4]);
		});

		it('adds with an object', function() {
			ee.addListeners({
				foo: fn1,
				bar: [fn2, fn3]
			});
			expect(ee.getListeners('foo')).toEqual([fn1]);
			expect(ee.getListeners('bar')).toEqual([fn3, fn2]);

			ee.addListeners({
				foo: [fn4],
				bar: fn5
			});
			expect(ee.getListeners('foo')).toEqual([fn1, fn4]);
			expect(ee.getListeners('bar')).toEqual([fn3, fn2, fn5]);
		});
	});

	describe('removeListeners', function() {
		var ee,
			fn1 = function(){},
			fn2 = function(){},
			fn3 = function(){},
			fn4 = function(){},
			fn5 = function(){};

		beforeEach(function() {
			ee = new EventEmitter();
		});

		it('removes with an array', function() {
			ee.addListeners('foo', [fn1, fn2, fn3, fn4, fn5]);
			ee.removeListeners('foo', [fn2, fn3]);
			expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn1]);

			ee.removeListeners('foo', [fn5, fn4]);
			expect(ee.getListeners('foo')).toEqual([fn1]);

			ee.removeListeners('foo', [fn1]);
			expect(ee.getListeners('foo')).toEqual([]);
		});

		it('removes with an object', function() {
			ee.addListeners({
				foo: [fn1, fn2, fn3, fn4, fn5],
				bar: [fn1, fn2, fn3, fn4, fn5]
			});

			ee.removeListeners({
				foo: fn2,
				bar: [fn3, fn4, fn5]
			});
			expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn3, fn1]);
			expect(ee.getListeners('bar')).toEqual([fn2, fn1]);

			ee.removeListeners({
				foo: [fn3],
				bar: [fn2, fn1]
			});
			expect(ee.getListeners('foo')).toEqual([fn5, fn4, fn1]);
			expect(ee.getListeners('bar')).toEqual([]);
		});

		it('removes with a regex', function() {
			ee.addListeners({
				foo: [fn1, fn2, fn3, fn4, fn5],
				bar: [fn1, fn2, fn3, fn4, fn5],
				baz: [fn1, fn2, fn3, fn4, fn5]
			});

			ee.removeListeners(/ba[rz]/, [fn3, fn4]);
			expect(ee.getListeners('foo')).toEqual([fn1, fn2, fn3, fn4, fn5]);
			expect(ee.getListeners('bar')).toEqual([fn1, fn2, fn5]);
			expect(ee.getListeners('baz')).toEqual([fn1, fn2, fn5]);
		});
	});
});<|endoftext|>


<commit_before>var ConvexHull4D = (function (scope) {
	function ConvexHull4D(){}

  ConvexHull4D.prototype.arrEqual = function(arr1, arr2) {
    if (arr1.length != arr2.length) {
      return false;
    }
    for (arr1_i = 0; arr1_i < arr1_i.length; arr1_i++) {
      if (arr1[arr1_i] != arr2[arr1_i]) return false;
    }
    return true;
  }

  ConvexHull4D.prototype.Arr1InArr2 = function(arr1, arr2) {
    for (var arr2_i = 0; arr2_i < arr2.length; arr2_i++) {
      if (this.arrEqual(arr1, arr2[arr2_i])) return true;
    }
    return false;
  }

  ConvexHull4D.prototype.CreateInitialSimplex = function() {
    // Create an initial simplex of d+1 points and return its facets
    return [[1,2,3,4],[4,3,2,0],[0,1,3,4],[4,2,1,0],[0,1,2,3]];
  }

  ConvexHull4D.prototype.vecSubtract = function(A, B) {
    var result = [];
    for (var i = 0; i < A.length; i++) {
      result.push(A[i] - B[i]);
    }
    return result;
  }

  ConvexHull4D.prototype.Cross = function(A,B,C) {
    // Calculate the normal vector to the hyperplane defined by vectors A, B, and C.
    // Values taken from a 4x4 determinant calculated by hand.
    // For more info, see the "multilinear algebra" section of
    // https://en.wikipedia.org/wiki/Cross_product#Generalizations

    var e0 = A[1]*B[3]*C[2] - A[1]*B[2]*C[3] + A[2]*B[1]*C[3] - A[2]*B[3]*C[1] - A[3]*B[1]*C[2] + A[3]*B[2]*C[1];
    var e1 = A[0]*B[2]*C[3] - A[0]*B[3]*C[2] - A[2]*B[0]*C[3] + A[2]*B[3]*C[0] + A[3]*B[0]*C[2] - A[3]*B[2]*C[0];
    var e2 = A[0]*B[3]*C[1] - A[0]*B[1]*C[3] + A[1]*B[0]*C[3] - A[1]*B[3]*C[0] - A[3]*B[0]*C[1] + A[3]*B[1]*C[0];
    var e3 = A[0]*B[1]*C[2] - A[0]*B[2]*C[1] - A[1]*B[0]*C[2] + A[1]*B[2]*C[0] + A[2]*B[0]*C[1] - A[2]*B[1]*C[0];
    return [e0, e1, e2, e3];
  }

  ConvexHull4D.prototype.Dot = function(A,B) {
  // The dot product of vectors A and B

    var dot_product = 0;
    for (var i = 0; i < 4; i++) {
      dot_product += A[i] * B[i];
    }
    return dot_product;
  }

  ConvexHull4D.prototype.IsPointAboveHyperplane = function(normal, p0, point) {
    // Take a normal vector and a point p0 that define a hyperplane
    // and determine if a point is above or below that hyperplane

    var vec = [];
    for (var i = 0; i < 4; i++) {
      vec.push(point[i] - p0[i]);
    }
    return this.Dot(normal, vec) < 0;
  }

  ConvexHull4D.prototype.GetHyperplaneOfFacet = function(facet, points) {
    // Return the normal and point representing the hyperplane that a facet lies on

    var v1 = this.vecSubtract(points[facet[1]], points[facet[0]]);
    var v2 = this.vecSubtract(points[facet[2]], points[facet[1]]);
    var v3 = this.vecSubtract(points[facet[3]], points[facet[2]]);
    var normal = this.Cross(v1, v2, v3);
    var p0 = points[facet[0]];
    return [normal, p0];
  }

  ConvexHull4D.prototype.IsPointAboveFacet = function(facet_index, point_index, hull) {
    var hyperplane = this.GetHyperplaneOfFacet(hull.facets[facet_index], hull.points);
    return this.IsPointAboveHyperplane(hyperplane[0], hyperplane[1], hull.points[point_index]);
  }

  ConvexHull4D.prototype.GetInitialOutsideSets = function(hull) {
    // for each facet F
    //   for each unassigned point p
    //     if p is above F
    //       assign p to F's outside set

    var outside_sets = [];
    for (var fi = 0; fi < hull.facets.length; fi++) {
      outside_sets.push([]);
      for (var pi = 5; pi < hull.points.length; pi++) {
        if (this.IsPointAboveFacet(fi, pi, hull)) {
          outside_sets[fi].push(pi);
        }
      }
    }
    return outside_sets;
  }

  ConvexHull4D.prototype.Magnitude = function(vec) {
    var sum = 0;
    for (var vi = 0; vi < vec.length; vi++) {
      sum += Math.pow(vec[vi], 2);
    }
    return Math.sqrt(sum);
  }

  ConvexHull4D.prototype.DistanceFromHyperplane = function(normal, p0, point) {
    // Calculate the distance of a point from a hyperplane.
    // For more information, see https://math.stackexchange.com/questions/1210545/distance-from-a-point-to-a-hyperplane

    var b = this.Dot(normal, this.vecSubtract([0,0,0,0],p0));
    var numerator = Math.abs(this.Dot(normal, point) + b);
    var denominator = this.Magnitude(normal);
    return numerator / denominator;
  }

  ConvexHull4D.prototype.GetFurthestOutsidePointFromFacet = function(facet_i, hull) {
    var hyperplane = this.GetHyperplaneOfFacet(hull.facets[facet_i], hull.points);
    var normal = hyperplane[0];
    var p0 = hyperplane[1];
    var furthest_distance = this.DistanceFromHyperplane(normal, p0, hull.points[0]);
    var furthest_point_i = 0;
    for (var i = 1; i < hull.points.length; i++) {
      if (this.DistanceFromHyperplane(normal, p0, hull.points[i]) > furthest_distance) {
        furthest_point_i = i;
      }
    }
    return furthest_point_i;
  }

  ConvexHull4D.prototype.GetRidgesOfFacet = function(facet) {
  // Following the threejs winding of a tetrahedron.

    return [[facet[0], facet[1], facet[2]],
            [facet[0], facet[2], facet[3]],
            [facet[3], facet[2], facet[1]],
            [facet[3], facet[1], facet[0]]];
  }

  ConvexHull4D.prototype.GetSharedRidges = function(facet_ridges, other_facet_ridges) {
    var shared_ridges = [];
    for (var fri = 0; fri < facet_ridges.length; fri++) {
      for (var ofri = 0; ofri < other_facet_ridges.length; ofri++) {
        var shared_points = 0;
        for (var frii = 0; frii < facet_ridges[fri].length; frii++) {
          for (var ofrii = 0; ofrii < other_facet_ridges[ofri].length; ofrii++) {
            if (facet_ridges[fri][frii] == other_facet_ridges[ofri][ofrii]) shared_points++;
          }
        }
        if (shared_points >= 3)  shared_ridges.push(facet_ridges[fri]);
      }
    }
    return shared_ridges;
  }

  ConvexHull4D.prototype.GetNeighborsOfFacet = function(facet_i, hull) {
    var neighbors = [];
    var facet_ridges = this.GetRidgesOfFacet(hull.facets[facet_i]);
    for (var i = 0; i < hull.facets.length; i++) {
      if (i == facet_i)
        continue;
      var other_facet_ridges = this.GetRidgesOfFacet(hull.facets[i]);
      if (this.GetSharedRidges(facet_ridges, other_facet_ridges) != [])
        neighbors.push(i);
    }
    return neighbors;
  }

  ConvexHull4D.prototype.GetHorizonRidges = function(visible_set, point_i, hull) {
    var horizon = [];
    for (var visible_set_i = 0; visible_set_i < visible_set.length; visible_set_i++) {
      var neighbors = this.GetNeighborsOfFacet(visible_set[visible_set_i], hull);

      // If our point of interest is a below a neighboring facet,
      // then the shared ridge ridge with that neighbor is part of the horizon.
      for (var neighbors_i = 0; neighbors_i < neighbors.length; neighbors_i++) {
        if (!this.IsPointAboveFacet(neighbors[neighbors_i], point_i, hull)) {
          var facet_ridges = this.GetRidgesOfFacet(hull.facets[visible_set[visible_set_i]]);
          var other_facet_ridges = this.GetRidgesOfFacet(hull.facets[neighbors[neighbors_i]]);
          var shared_ridges = this.GetSharedRidges(facet_ridges, other_facet_ridges);
          horizon = horizon.concat(shared_ridges);
        }
      }
    }

    return horizon;
  }

  ConvexHull4D.prototype.RemoveFacetsFromHull = function(facets, hull) {
    facets = facets.sort(function(a,b){ return a > b }); // ascending order
    for (var facets_i = facets.length - 1; facets_i >= 0; facets_i--) {
      hull.facets.splice(facets[facets_i], 1);
      hull.outside_sets.splice(facets[facets_i], 1);
    }
    return hull;
  }

  ConvexHull4D.prototype.CreateFacetsFromPointAndRidges = function(hull, ridges, point_i) {
    for (var ridges_i = 0; ridges_i < ridges.length; ridges_i++) {
      hull.facets.push(ridges[ridges_i].concat(point_i));
    }
    return hull;
  }

  ConvexHull4D.prototype.UpdateOutsideSets = function(outside_points_of_visible_set, start_of_new_facets, hull) {
    for (var new_facet_i = start_of_new_facets; new_facet_i < hull.facets.length; new_facet_i++) {
      hull.outside_sets.push([]);
      for (var opi = 0; opi < outside_points_of_visible_set.length; opi++) {
        if (this.IsPointAboveFacet(new_facet_i, outside_points_of_visible_set[opi], hull))
          hull.outside_sets[new_facet_i].push(outside_points_of_visible_set[opi]);
      }
    }

    return hull;
  }

  ConvexHull4D.prototype.GetOutsidePointsOfFacets = function(facets, hull) {
    var outside_points = [];
    for (var facets_i = 0; facets_i < facets.length; facets_i++) {
      var facet = facets[facets_i];
      for (var osii = 0; osii < hull.outside_sets[facet].length; osii++) {
        var outside_point = hull.outside_sets[facet][osii];
        if (outside_points.indexOf(outside_point) == -1) {
          outside_points.push(outside_point);
        }
      }
    }
    return outside_points;
  }

  ConvexHull4D.prototype.ConvexHull4D = function(points) {
    var hull = {};
    hull.points = points;
    hull.facets = this.CreateInitialSimplex();
    hull.outside_sets = this.GetInitialOutsideSets(hull);
    var counter = 0;
    for (var osi = 0; osi < hull.outside_sets.length; osi++) {
      if (hull.outside_sets[osi].length > 0) {
        var furthest_point_i = this.GetFurthestOutsidePointFromFacet(osi, hull);
        var visible_set = [osi];
        var neighbors = this.GetNeighborsOfFacet(visible_set[0], hull);

        for (var neighbors_i = 0; neighbors_i < neighbors.length; neighbors_i++) {
          if (this.IsPointAboveFacet(neighbors[neighbors_i], furthest_point_i, hull)) {
            visible_set.push(neighbors[neighbors_i]);
            var new_neighbors = this.GetNeighborsOfFacet(neighbors[neighbors_i], hull);
            for (var new_neighbors_i = 0; new_neighbors_i < new_neighbors.length; new_neighbors_i++) {
              if(neighbors.indexOf(new_neighbors[new_neighbors_i]) == -1 && new_neighbors[new_neighbors_i] != osi) {
                neighbors.push(new_neighbors[new_neighbors_i]);
              }
            }
          }
        }

        var horizon_ridges = this.GetHorizonRidges(visible_set, furthest_point_i, hull);
        var outside_points_of_visible_set  = this.GetOutsidePointsOfFacets(visible_set, hull);
        hull = this.RemoveFacetsFromHull(visible_set, hull);
        var start_of_new_facets = hull.facets.length;
        hull = this.CreateFacetsFromPointAndRidges(hull, horizon_ridges, furthest_point_i);
        hull = this.UpdateOutsideSets(outside_points_of_visible_set, start_of_new_facets, hull);

        osi = 0;
        counter++;
        if (counter >= 9) break;
      }
    }

    return hull.facets;
  }

scope.ConvexHull4D = ConvexHull4D;
return ConvexHull4D;
})(typeof exports === 'undefined' ? {} : exports);
<commit_msg>Added inline documentation to convexhull4d<commit_after>var ConvexHull4D = (function (scope) {
	function ConvexHull4D(){}

  ConvexHull4D.prototype.arrEqual = function(arr1, arr2) {
    if (arr1.length != arr2.length) {
      return false;
    }
    for (arr1_i = 0; arr1_i < arr1_i.length; arr1_i++) {
      if (arr1[arr1_i] != arr2[arr1_i]) return false;
    }
    return true;
  }

  ConvexHull4D.prototype.Arr1InArr2 = function(arr1, arr2) {
    for (var arr2_i = 0; arr2_i < arr2.length; arr2_i++) {
      if (this.arrEqual(arr1, arr2[arr2_i])) return true;
    }
    return false;
  }

  ConvexHull4D.prototype.CreateInitialSimplex = function() {
    // Create an initial simplex of d+1 points and return its facets
    return [[1,2,3,4],[4,3,2,0],[0,1,3,4],[4,2,1,0],[0,1,2,3]];
  }

  ConvexHull4D.prototype.vecSubtract = function(A, B) {
    var result = [];
    for (var i = 0; i < A.length; i++) {
      result.push(A[i] - B[i]);
    }
    return result;
  }

  ConvexHull4D.prototype.Cross = function(A,B,C) {
    // Calculate the normal vector to the hyperplane defined by vectors A, B, and C.
    // Values taken from a 4x4 determinant calculated by hand.
    // For more info, see the "multilinear algebra" section of
    // https://en.wikipedia.org/wiki/Cross_product#Generalizations

    var e0 = A[1]*B[3]*C[2] - A[1]*B[2]*C[3] + A[2]*B[1]*C[3] - A[2]*B[3]*C[1] - A[3]*B[1]*C[2] + A[3]*B[2]*C[1];
    var e1 = A[0]*B[2]*C[3] - A[0]*B[3]*C[2] - A[2]*B[0]*C[3] + A[2]*B[3]*C[0] + A[3]*B[0]*C[2] - A[3]*B[2]*C[0];
    var e2 = A[0]*B[3]*C[1] - A[0]*B[1]*C[3] + A[1]*B[0]*C[3] - A[1]*B[3]*C[0] - A[3]*B[0]*C[1] + A[3]*B[1]*C[0];
    var e3 = A[0]*B[1]*C[2] - A[0]*B[2]*C[1] - A[1]*B[0]*C[2] + A[1]*B[2]*C[0] + A[2]*B[0]*C[1] - A[2]*B[1]*C[0];
    return [e0, e1, e2, e3];
  }

  ConvexHull4D.prototype.Dot = function(A,B) {
  // The dot product of vectors A and B

    var dot_product = 0;
    for (var i = 0; i < 4; i++) {
      dot_product += A[i] * B[i];
    }
    return dot_product;
  }

  ConvexHull4D.prototype.IsPointAboveHyperplane = function(normal, p0, point) {
    // Take a normal vector and a point p0 that define a hyperplane
    // and determine if a point is above or below that hyperplane

    var vec = [];
    for (var i = 0; i < 4; i++) {
      vec.push(point[i] - p0[i]);
    }
    return this.Dot(normal, vec) < 0;
  }

  ConvexHull4D.prototype.GetHyperplaneOfFacet = function(facet, points) {
    // Return the normal and point representing the hyperplane that a facet lies on

    var v1 = this.vecSubtract(points[facet[1]], points[facet[0]]);
    var v2 = this.vecSubtract(points[facet[2]], points[facet[1]]);
    var v3 = this.vecSubtract(points[facet[3]], points[facet[2]]);
    var normal = this.Cross(v1, v2, v3);
    var p0 = points[facet[0]];
    return [normal, p0];
  }

  ConvexHull4D.prototype.IsPointAboveFacet = function(facet_index, point_index, hull) {
    var hyperplane = this.GetHyperplaneOfFacet(hull.facets[facet_index], hull.points);
    return this.IsPointAboveHyperplane(hyperplane[0], hyperplane[1], hull.points[point_index]);
  }

  ConvexHull4D.prototype.GetInitialOutsideSets = function(hull) {
    // for each facet F
    //   for each unassigned point p
    //     if p is above F
    //       assign p to F's outside set

    var outside_sets = [];
    for (var fi = 0; fi < hull.facets.length; fi++) {
      outside_sets.push([]);
      for (var pi = 5; pi < hull.points.length; pi++) {
        if (this.IsPointAboveFacet(fi, pi, hull)) {
          outside_sets[fi].push(pi);
        }
      }
    }
    return outside_sets;
  }

  ConvexHull4D.prototype.Magnitude = function(vec) {
    var sum = 0;
    for (var vi = 0; vi < vec.length; vi++) {
      sum += Math.pow(vec[vi], 2);
    }
    return Math.sqrt(sum);
  }

  ConvexHull4D.prototype.DistanceFromHyperplane = function(normal, p0, point) {
    // Calculate the distance of a point from a hyperplane.
    // For more information, see https://math.stackexchange.com/questions/1210545/distance-from-a-point-to-a-hyperplane

    var b = this.Dot(normal, this.vecSubtract([0,0,0,0],p0));
    var numerator = Math.abs(this.Dot(normal, point) + b);
    var denominator = this.Magnitude(normal);
    return numerator / denominator;
  }

  ConvexHull4D.prototype.GetFurthestOutsidePointFromFacet = function(facet_i, hull) {
    var hyperplane = this.GetHyperplaneOfFacet(hull.facets[facet_i], hull.points);
    var normal = hyperplane[0];
    var p0 = hyperplane[1];
    var furthest_distance = this.DistanceFromHyperplane(normal, p0, hull.points[0]);
    var furthest_point_i = 0;
    for (var i = 1; i < hull.points.length; i++) {
      if (this.DistanceFromHyperplane(normal, p0, hull.points[i]) > furthest_distance) {
        furthest_point_i = i;
      }
    }
    return furthest_point_i;
  }

  ConvexHull4D.prototype.GetRidgesOfFacet = function(facet) {
  // Following the threejs winding of a tetrahedron.

    return [[facet[0], facet[1], facet[2]],
            [facet[0], facet[2], facet[3]],
            [facet[3], facet[2], facet[1]],
            [facet[3], facet[1], facet[0]]];
  }

  ConvexHull4D.prototype.GetSharedRidges = function(facet_ridges, other_facet_ridges) {
    var shared_ridges = [];
    for (var fri = 0; fri < facet_ridges.length; fri++) {
      for (var ofri = 0; ofri < other_facet_ridges.length; ofri++) {
        var shared_points = 0;
        for (var frii = 0; frii < facet_ridges[fri].length; frii++) {
          for (var ofrii = 0; ofrii < other_facet_ridges[ofri].length; ofrii++) {
            if (facet_ridges[fri][frii] == other_facet_ridges[ofri][ofrii]) shared_points++;
          }
        }
        if (shared_points >= 3)  shared_ridges.push(facet_ridges[fri]);
      }
    }
    return shared_ridges;
  }

  ConvexHull4D.prototype.GetNeighborsOfFacet = function(facet_i, hull) {
    var neighbors = [];
    var facet_ridges = this.GetRidgesOfFacet(hull.facets[facet_i]);
    for (var i = 0; i < hull.facets.length; i++) {
      if (i == facet_i)
        continue;
      var other_facet_ridges = this.GetRidgesOfFacet(hull.facets[i]);
      if (this.GetSharedRidges(facet_ridges, other_facet_ridges) != [])
        neighbors.push(i);
    }
    return neighbors;
  }

  ConvexHull4D.prototype.GetHorizonRidges = function(visible_set, point_i, hull) {
    var horizon = [];
    for (var visible_set_i = 0; visible_set_i < visible_set.length; visible_set_i++) {
      var neighbors = this.GetNeighborsOfFacet(visible_set[visible_set_i], hull);

      // If our point of interest is a below a neighboring facet,
      // then the shared ridge ridge with that neighbor is part of the horizon.
      for (var neighbors_i = 0; neighbors_i < neighbors.length; neighbors_i++) {
        if (!this.IsPointAboveFacet(neighbors[neighbors_i], point_i, hull)) {
          var facet_ridges = this.GetRidgesOfFacet(hull.facets[visible_set[visible_set_i]]);
          var other_facet_ridges = this.GetRidgesOfFacet(hull.facets[neighbors[neighbors_i]]);
          var shared_ridges = this.GetSharedRidges(facet_ridges, other_facet_ridges);
          horizon = horizon.concat(shared_ridges);
        }
      }
    }

    return horizon;
  }

  ConvexHull4D.prototype.RemoveFacetsFromHull = function(facets, hull) {
    facets = facets.sort(function(a,b){ return a > b }); // ascending order
    for (var facets_i = facets.length - 1; facets_i >= 0; facets_i--) {
      hull.facets.splice(facets[facets_i], 1);
      hull.outside_sets.splice(facets[facets_i], 1);
    }
    return hull;
  }

  ConvexHull4D.prototype.CreateFacetsFromPointAndRidges = function(hull, ridges, point_i) {
    for (var ridges_i = 0; ridges_i < ridges.length; ridges_i++) {
      hull.facets.push(ridges[ridges_i].concat(point_i));
    }
    return hull;
  }

  ConvexHull4D.prototype.UpdateOutsideSets = function(outside_points_of_visible_set, start_of_new_facets, hull) {
    for (var new_facet_i = start_of_new_facets; new_facet_i < hull.facets.length; new_facet_i++) {
      hull.outside_sets.push([]);
      for (var opi = 0; opi < outside_points_of_visible_set.length; opi++) {
        if (this.IsPointAboveFacet(new_facet_i, outside_points_of_visible_set[opi], hull))
          hull.outside_sets[new_facet_i].push(outside_points_of_visible_set[opi]);
      }
    }

    return hull;
  }

  ConvexHull4D.prototype.GetOutsidePointsOfFacets = function(facets, hull) {
    var outside_points = [];
    for (var facets_i = 0; facets_i < facets.length; facets_i++) {
      var facet = facets[facets_i];
      for (var osii = 0; osii < hull.outside_sets[facet].length; osii++) {
        var outside_point = hull.outside_sets[facet][osii];
        if (outside_points.indexOf(outside_point) == -1) {
          outside_points.push(outside_point);
        }
      }
    }
    return outside_points;
  }

  ConvexHull4D.prototype.ConvexHull4D = function(points) {
    /*
      Takes an array of 4-arrays, so something like:
      [[x,y,z,w],[x,y,z,w],...]

      Returns an array of indices that make up the facets
    */
    var hull = {};
    hull.points = points;
    hull.facets = this.CreateInitialSimplex();
    hull.outside_sets = this.GetInitialOutsideSets(hull);
    var counter = 0;
    for (var osi = 0; osi < hull.outside_sets.length; osi++) {
      if (hull.outside_sets[osi].length > 0) {
        var furthest_point_i = this.GetFurthestOutsidePointFromFacet(osi, hull);
        var visible_set = [osi];
        var neighbors = this.GetNeighborsOfFacet(visible_set[0], hull);

        for (var neighbors_i = 0; neighbors_i < neighbors.length; neighbors_i++) {
          if (this.IsPointAboveFacet(neighbors[neighbors_i], furthest_point_i, hull)) {
            visible_set.push(neighbors[neighbors_i]);
            var new_neighbors = this.GetNeighborsOfFacet(neighbors[neighbors_i], hull);
            for (var new_neighbors_i = 0; new_neighbors_i < new_neighbors.length; new_neighbors_i++) {
              if(neighbors.indexOf(new_neighbors[new_neighbors_i]) == -1 && new_neighbors[new_neighbors_i] != osi) {
                neighbors.push(new_neighbors[new_neighbors_i]);
              }
            }
          }
        }

        var horizon_ridges = this.GetHorizonRidges(visible_set, furthest_point_i, hull);
        var outside_points_of_visible_set  = this.GetOutsidePointsOfFacets(visible_set, hull);
        hull = this.RemoveFacetsFromHull(visible_set, hull);
        var start_of_new_facets = hull.facets.length;
        hull = this.CreateFacetsFromPointAndRidges(hull, horizon_ridges, furthest_point_i);
        hull = this.UpdateOutsideSets(outside_points_of_visible_set, start_of_new_facets, hull);

        osi = 0;
        counter++;
        if (counter >= 9) break;
      }
    }

    return hull.facets;
  }

scope.ConvexHull4D = ConvexHull4D;
return ConvexHull4D;
})(typeof exports === 'undefined' ? {} : exports);
<|endoftext|>