<commit_before>/*
 * Copyright 2012, Mozilla Foundation and contributors
 *
 * 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.
 */

'use strict';
var examiner = exports;

var promise = require('../util/promise');
var util = require('../util/util');
var assert = require('./assert');
var stati = require('./status').stati;

/**
 * Test harness data
 */
examiner._suites = {};

/**
 * The gap between tests when running async
 */
var delay = 10;

/**
 * Add a test suite. Generally used like:
 * test.addSuite('foo', require('path/to/foo'));
 */
examiner.addSuite = function(name, suite) {
  examiner._suites[name] = new Suite(name, suite);
};

/**
 * Provide a clone of examiner._suites for external consumption
 */
Object.defineProperty(examiner, 'suites', {
  get: function() {
    var reply = {};
    Object.keys(examiner._suites).forEach(function(name) {
      reply[name] = examiner._suites[name];
    });
    return reply;
  },
  enumerable: true
});

/**
 * Run all the tests asynchronously
 */
examiner.run = function(options, callback) {
  var onComplete = function() {
    if (typeof callback === 'function') {
      callback.call();
    }
  };

  var suiteNames = Object.keys(examiner._suites);
  return util.promiseEach(suiteNames, function(suiteName) {
    return examiner._suites[suiteName].run(options);
  }).then(onComplete);
};

/**
 * Create a JSON object suitable for serialization
 */
examiner.toRemote = function() {
  return {
    suites: Object.keys(examiner._suites).map(function(suiteName) {
      return examiner._suites[suiteName].toRemote();
    }),
    summary: {
      checks: this.checks,
      status: this.status
    }
  };
};

/**
 * Reset all the tests to their original state
 */
examiner.reset = function() {
  Object.keys(examiner._suites).forEach(function(suiteName) {
    examiner._suites[suiteName].reset();
  }, this);
};

/**
 * The number of checks in this set of test suites is the sum of the checks in
 * the test suites.
 */
Object.defineProperty(examiner, 'checks', {
  get: function() {
    return  Object.keys(examiner._suites).reduce(function(current, suiteName) {
      return current + examiner._suites[suiteName].checks;
    }, 0);
  },
  enumerable: true
});

/**
 * The status of this set of test suites is the worst of the statuses of the
 * contained test suites.
 */
Object.defineProperty(examiner, 'status', {
  get: function() {
    return Object.keys(examiner._suites).reduce(function(status, suiteName) {
      var suiteStatus = examiner._suites[suiteName].status;
      return status.index > suiteStatus.index ? status : suiteStatus;
    }, stati.notrun);
  },
  enumerable: true
});

/**
 * Return a test summary
 */
examiner.detailedResultLog = function(name) {
  var reply = name + ' Summary: ' + this.status.name +
              ' (' + this.checks + ' checks)';

  if (this.status !== stati.pass) {
    reply += '\n';
    Object.keys(this.suites).forEach(function(suiteName) {
      var suite = examiner._suites[suiteName];
      if (suite.status !== stati.pass) {
        reply += '- ' + suite.name + ': ' + suite.status.name +
                 ' (funcs=' + Object.keys(suite.tests).length +
                 ', checks=' + suite.checks +
                 ', skipped=' + suite.skippedCount + ')\n';

        Object.keys(suite.tests).forEach(function(testName) {
          var test = suite.tests[testName];
          if (test.status !== stati.pass) {
            reply += '  - ' + test.name + ': ' + test.status.name + '\n';
            test.failures.forEach(function(failure) {
              reply += '    - ' + failure.message + '\n';
              if (failure.params) {
                reply += '      - (Actual)   P1: ' + failure.p1 + '\n';
                reply += '      - (Expected) P2: ' + failure.p2 + '\n';
              }
            }, this);
          }
        }, this);
      }
    }, this);
  }

  return reply;
};

/**
 * A suite is a group of tests
 */
function Suite(suiteName, suite) {
  this.name = suiteName.replace(/gcli\/test\//, '');
  this.suite = suite;

  this.tests = {};

  Object.keys(suite).forEach(function(testName) {
    if (testName !== 'setup' && testName !== 'shutdown') {
      var test = new Test(this, testName, suite[testName]);
      this.tests[testName] = test;
    }
  }, this);
}

/**
 * Reset all the tests to their original state
 */
Suite.prototype.reset = function() {
  Object.keys(this.tests).forEach(function(testName) {
    this.tests[testName].reset();
  }, this);
};

/**
 * Run all the tests in this suite asynchronously (includes doing a setup and
 * shutdown of the suite)
 */
Suite.prototype.run = function(options) {
  this._setup(options);

  var onComplete = function() {
    this._shutdown(options);
  }.bind(this);

  var testNames = Object.keys(this.tests);
  return util.promiseEach(testNames, function(testName) {
    return this.tests[testName].run(options);
  }.bind(this)).then(onComplete);
};

/**
 * Create a JSON object suitable for serialization
 */
Suite.prototype.toRemote = function() {
  return {
    name: this.name,
    tests: Object.keys(this.tests).map(function(testName) {
      return this.tests[testName].toRemote();
    }.bind(this))
  };
};

/**
 * The number of checks in this suite is the sum of the checks in the contained
 * tests.
 */
Object.defineProperty(Suite.prototype, 'checks', {
  get: function() {
    return Object.keys(this.tests).reduce(function(prevChecks, testName) {
      return prevChecks + this.tests[testName].checks;
    }.bind(this), 0);
  },
  enumerable: true
});

/**
 * The status of a test suite is the worst of the statuses of the contained
 * tests.
 */
Object.defineProperty(Suite.prototype, 'status', {
  get: function() {
    return Object.keys(this.tests).reduce(function(prevStatus, testName) {
      var suiteStatus = this.tests[testName].status;
      return prevStatus.index > suiteStatus.index ? prevStatus : suiteStatus;
    }.bind(this), stati.notrun);
  },
  enumerable: true
});

/**
 * The status of a test suite is the worst of the statuses of the contained
 * tests.
 */
Object.defineProperty(Suite.prototype, 'skippedCount', {
  get: function() {
    return Object.keys(this.tests).reduce(function(count, testName) {
      return count + this.tests[testName].skipped.length;
    }.bind(this), 0);
  },
  enumerable: true
});

/**
 * Defensively setup the test suite
 */
Suite.prototype._setup = function(options) {
  if (typeof this.suite.setup !== 'function') {
    return true;
  }

  try {
    this.suite.setup(options);
    return true;
  }
  catch (ex) {
    this._logToAllTests('' + ex);
    console.error(ex);
    if (ex.stack) {
      console.error(ex.stack);
    }
    return false;
  }
};

/**
 * Defensively shutdown the test suite
 */
Suite.prototype._shutdown = function(options) {
  if (typeof this.suite.shutdown !== 'function') {
    return true;
  }

  try {
    this.suite.shutdown(options);
    return true;
  }
  catch (ex) {
    this._logToAllTests('' + ex);
    console.error(ex);
    if (ex.stack) {
      console.error(ex.stack);
    }
    return false;
  }
};

/**
 * Something has gone wrong that affects all tests in this Suite
 */
Suite.prototype._logToAllTests = function(message) {
  var priorCurrentTest = assert.currentTest;
  Object.keys(this.tests).forEach(function(testName) {
    assert.currentTest = this.tests[testName];
    assert.ok(false, message);
  }.bind(this));
  assert.currentTest = priorCurrentTest;
};

/**
 * A test represents data about a single test function
 */
function Test(suite, name, func) {
  this.suite = suite;
  this.name = name;
  this.func = func;
  this.title = name.replace(/^test/, '').replace(/([A-Z])/g, ' $1');

  this.failures = [];
  this.skipped = [];
  this.status = stati.notrun;
  this.checks = 0;
}

Test.prototype.toString = function() {
  return this.suite.name + '.' + this.name;
};

/**
 * Reset the test to its original state
 */
Test.prototype.reset = function() {
  this.failures = [];
  this.skipped = [];
  this.status = stati.notrun;
  this.checks = 0;
};

/**
 * Run all the tests in this suite asynchronously
 */
Test.prototype.run = function(options) {
  assert.currentTest = this;
  this.status = stati.executing;

  if (assert.testLogging) {
    console.log('START: ' + assert.currentTest);
  }

  var deferred = promise.defer();
  setTimeout(function() {
    try {
      var reply = this.func.apply(this.suite, [ options ]);
      deferred.resolve(reply);
    }
    catch (ex) {
      deferred.reject(ex);
    }
  }.bind(this), delay);

  var onDone = function() {
    if (this.status === stati.executing) {
      this.status = this.failures.length === 0 ? stati.pass : stati.fail;
    }

    if (assert.testLogging) {
      console.log('END: ' + assert.currentTest);
    }

    assert.currentTest = null;
  }.bind(this);

  var onError = function(err) {
    assert.ok(false, 'Returned promise, rejected with: ' + toString(err));
    onDone();
  };

  return deferred.promise.then(onDone, onError);
};

/**
 * Object.toString could be a lot better
 */
function toString(err) {
  // Convert err to a string
  if (typeof err === 'string') {
    return err;
  }

  if (err instanceof Error) {
    return '' + err.stack;
  }

  // If an object has it's own toString, that's probably the best way
  if (err.toString !== Object.prototype.toString) {
    return err.toString();
  }

  // Next best is JSON, if the object is JSONable
  try {
    return JSON.stringify(err);
  }
  catch (ex) {
    // Resort to Object.toString otherwise
    err = '' + err;
  }
}

/**
 * Create a JSON object suitable for serialization
 */
Test.prototype.toRemote = function() {
  return {
    name: this.name,
    title: this.title,
    status: this.status,
    failures: this.failures,
    checks: this.checks
  };
};
<commit_msg>refactor-864370: Allow test setup/shutdown to be async<commit_after>/*
 * Copyright 2012, Mozilla Foundation and contributors
 *
 * 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.
 */

'use strict';
var examiner = exports;

var promise = require('../util/promise');
var util = require('../util/util');
var assert = require('./assert');
var stati = require('./status').stati;

/**
 * Test harness data
 */
examiner._suites = {};

/**
 * The gap between tests when running async
 */
var delay = 10;

/**
 * Add a test suite. Generally used like:
 * test.addSuite('foo', require('path/to/foo'));
 */
examiner.addSuite = function(name, suite) {
  examiner._suites[name] = new Suite(name, suite);
};

/**
 * Provide a clone of examiner._suites for external consumption
 */
Object.defineProperty(examiner, 'suites', {
  get: function() {
    var reply = {};
    Object.keys(examiner._suites).forEach(function(name) {
      reply[name] = examiner._suites[name];
    });
    return reply;
  },
  enumerable: true
});

/**
 * Run all the tests asynchronously
 */
examiner.run = function(options, callback) {
  var onComplete = function() {
    if (typeof callback === 'function') {
      callback.call();
    }
  };

  var suiteNames = Object.keys(examiner._suites);
  return util.promiseEach(suiteNames, function(suiteName) {
    return examiner._suites[suiteName].run(options);
  }).then(onComplete);
};

/**
 * Create a JSON object suitable for serialization
 */
examiner.toRemote = function() {
  return {
    suites: Object.keys(examiner._suites).map(function(suiteName) {
      return examiner._suites[suiteName].toRemote();
    }),
    summary: {
      checks: this.checks,
      status: this.status
    }
  };
};

/**
 * Reset all the tests to their original state
 */
examiner.reset = function() {
  Object.keys(examiner._suites).forEach(function(suiteName) {
    examiner._suites[suiteName].reset();
  }, this);
};

/**
 * The number of checks in this set of test suites is the sum of the checks in
 * the test suites.
 */
Object.defineProperty(examiner, 'checks', {
  get: function() {
    return  Object.keys(examiner._suites).reduce(function(current, suiteName) {
      return current + examiner._suites[suiteName].checks;
    }, 0);
  },
  enumerable: true
});

/**
 * The status of this set of test suites is the worst of the statuses of the
 * contained test suites.
 */
Object.defineProperty(examiner, 'status', {
  get: function() {
    return Object.keys(examiner._suites).reduce(function(status, suiteName) {
      var suiteStatus = examiner._suites[suiteName].status;
      return status.index > suiteStatus.index ? status : suiteStatus;
    }, stati.notrun);
  },
  enumerable: true
});

/**
 * Return a test summary
 */
examiner.detailedResultLog = function(name) {
  var reply = name + ' Summary: ' + this.status.name +
              ' (' + this.checks + ' checks)';

  if (this.status !== stati.pass) {
    reply += '\n';
    Object.keys(this.suites).forEach(function(suiteName) {
      var suite = examiner._suites[suiteName];
      if (suite.status !== stati.pass) {
        reply += '- ' + suite.name + ': ' + suite.status.name +
                 ' (funcs=' + Object.keys(suite.tests).length +
                 ', checks=' + suite.checks +
                 ', skipped=' + suite.skippedCount + ')\n';

        Object.keys(suite.tests).forEach(function(testName) {
          var test = suite.tests[testName];
          if (test.status !== stati.pass) {
            reply += '  - ' + test.name + ': ' + test.status.name + '\n';
            test.failures.forEach(function(failure) {
              reply += '    - ' + failure.message + '\n';
              if (failure.params) {
                reply += '      - (Actual)   P1: ' + failure.p1 + '\n';
                reply += '      - (Expected) P2: ' + failure.p2 + '\n';
              }
            }, this);
          }
        }, this);
      }
    }, this);
  }

  return reply;
};

/**
 * A suite is a group of tests
 */
function Suite(suiteName, suite) {
  this.name = suiteName.replace(/gcli\/test\//, '');
  this.suite = suite;

  this.tests = {};

  Object.keys(suite).forEach(function(testName) {
    if (testName !== 'setup' && testName !== 'shutdown') {
      var test = new Test(this, testName, suite[testName]);
      this.tests[testName] = test;
    }
  }, this);
}

/**
 * Reset all the tests to their original state
 */
Suite.prototype.reset = function() {
  Object.keys(this.tests).forEach(function(testName) {
    this.tests[testName].reset();
  }, this);
};

/**
 * Run all the tests in this suite asynchronously (includes doing a setup and
 * shutdown of the suite)
 */
Suite.prototype.run = function(options) {
  return promise.resolve(this._setup(options)).then(function() {
    var testNames = Object.keys(this.tests);
    var runTest = function(testName) {
      return this.tests[testName].run(options);
    }.bind(this);

    return util.promiseEach(testNames, runTest).then(function() {
      return this._shutdown(options);
    }.bind(this));
  }.bind(this));
};

/**
 * Create a JSON object suitable for serialization
 */
Suite.prototype.toRemote = function() {
  return {
    name: this.name,
    tests: Object.keys(this.tests).map(function(testName) {
      return this.tests[testName].toRemote();
    }.bind(this))
  };
};

/**
 * The number of checks in this suite is the sum of the checks in the contained
 * tests.
 */
Object.defineProperty(Suite.prototype, 'checks', {
  get: function() {
    return Object.keys(this.tests).reduce(function(prevChecks, testName) {
      return prevChecks + this.tests[testName].checks;
    }.bind(this), 0);
  },
  enumerable: true
});

/**
 * The status of a test suite is the worst of the statuses of the contained
 * tests.
 */
Object.defineProperty(Suite.prototype, 'status', {
  get: function() {
    return Object.keys(this.tests).reduce(function(prevStatus, testName) {
      var suiteStatus = this.tests[testName].status;
      return prevStatus.index > suiteStatus.index ? prevStatus : suiteStatus;
    }.bind(this), stati.notrun);
  },
  enumerable: true
});

/**
 * The status of a test suite is the worst of the statuses of the contained
 * tests.
 */
Object.defineProperty(Suite.prototype, 'skippedCount', {
  get: function() {
    return Object.keys(this.tests).reduce(function(count, testName) {
      return count + this.tests[testName].skipped.length;
    }.bind(this), 0);
  },
  enumerable: true
});

/**
 * Defensively setup the test suite
 */
Suite.prototype._setup = function(options) {
  if (typeof this.suite.setup !== 'function') {
    return true;
  }

  try {
    this.suite.setup(options);
    return true;
  }
  catch (ex) {
    this._logToAllTests('' + ex);
    console.error(ex);
    if (ex.stack) {
      console.error(ex.stack);
    }
    return false;
  }
};

/**
 * Defensively shutdown the test suite
 */
Suite.prototype._shutdown = function(options) {
  if (typeof this.suite.shutdown !== 'function') {
    return true;
  }

  try {
    this.suite.shutdown(options);
    return true;
  }
  catch (ex) {
    this._logToAllTests('' + ex);
    console.error(ex);
    if (ex.stack) {
      console.error(ex.stack);
    }
    return false;
  }
};

/**
 * Something has gone wrong that affects all tests in this Suite
 */
Suite.prototype._logToAllTests = function(message) {
  var priorCurrentTest = assert.currentTest;
  Object.keys(this.tests).forEach(function(testName) {
    assert.currentTest = this.tests[testName];
    assert.ok(false, message);
  }.bind(this));
  assert.currentTest = priorCurrentTest;
};

/**
 * A test represents data about a single test function
 */
function Test(suite, name, func) {
  this.suite = suite;
  this.name = name;
  this.func = func;
  this.title = name.replace(/^test/, '').replace(/([A-Z])/g, ' $1');

  this.failures = [];
  this.skipped = [];
  this.status = stati.notrun;
  this.checks = 0;
}

Test.prototype.toString = function() {
  return this.suite.name + '.' + this.name;
};

/**
 * Reset the test to its original state
 */
Test.prototype.reset = function() {
  this.failures = [];
  this.skipped = [];
  this.status = stati.notrun;
  this.checks = 0;
};

/**
 * Run all the tests in this suite asynchronously
 */
Test.prototype.run = function(options) {
  assert.currentTest = this;
  this.status = stati.executing;

  if (assert.testLogging) {
    console.log('START: ' + assert.currentTest);
  }

  var deferred = promise.defer();
  setTimeout(function() {
    try {
      var reply = this.func.apply(this.suite, [ options ]);
      deferred.resolve(reply);
    }
    catch (ex) {
      deferred.reject(ex);
    }
  }.bind(this), delay);

  var onDone = function() {
    if (this.status === stati.executing) {
      this.status = this.failures.length === 0 ? stati.pass : stati.fail;
    }

    if (assert.testLogging) {
      console.log('END: ' + assert.currentTest);
    }

    assert.currentTest = null;
  }.bind(this);

  var onError = function(err) {
    assert.ok(false, 'Returned promise, rejected with: ' + toString(err));
    onDone();
  };

  return deferred.promise.then(onDone, onError);
};

/**
 * Object.toString could be a lot better
 */
function toString(err) {
  // Convert err to a string
  if (typeof err === 'string') {
    return err;
  }

  if (err instanceof Error) {
    return '' + err.stack;
  }

  // If an object has it's own toString, that's probably the best way
  if (err.toString !== Object.prototype.toString) {
    return err.toString();
  }

  // Next best is JSON, if the object is JSONable
  try {
    return JSON.stringify(err);
  }
  catch (ex) {
    // Resort to Object.toString otherwise
    err = '' + err;
  }
}

/**
 * Create a JSON object suitable for serialization
 */
Test.prototype.toRemote = function() {
  return {
    name: this.name,
    title: this.title,
    status: this.status,
    failures: this.failures,
    checks: this.checks
  };
};
<|endoftext|>


<commit_before>export default {
  categoryOrder: {
    组件: 0,

    十大原则: 0,
    设计基础: 1,
    动画: 2,
  },
  typeOrder: {
    基本: 0,
    表单: 1,
    展示: 2,
    导航: 3,
    其它: 4,
  },

  redirects: {
    'docs/react/introduce': 'components/introduce',
    'docs/react/getting-started': 'components/getting-started',
    'docs/react/upgrade-notes': 'components/upgrade-notes',
    CHANGELOG: 'components/changelog',
  },

  docVersions: {
    '0.1.x': 'http://01x.antm.alipay.net'
  }
};
<commit_msg>oldVersion<commit_after>export default {
  categoryOrder: {
    组件: 0,

    十大原则: 0,
    设计基础: 1,
    动画: 2,
  },
  typeOrder: {
    基本: 0,
    表单: 1,
    展示: 2,
    导航: 3,
    其它: 4,
  },

  redirects: {
    'docs/react/introduce': 'components/introduce',
    'docs/react/getting-started': 'components/getting-started',
    'docs/react/upgrade-notes': 'components/upgrade-notes',
    CHANGELOG: 'components/changelog',
  },

  docVersions: {
    '0.1.x': 'http://01x.antm.alipay.net',
    '0.5.x': 'http://05x.antm.alipay.net'
  }
};
<|endoftext|>


<commit_before>/**
 * @fileOverview Lua virtual machine class.
 * @author Paul Cuthbertson
 * @copyright Gamesys Limited 2013
 */

var shine = shine || {};

/**
 * A Lua virtual machine.
 * @constructor
 * @extends shine.EventEmitter
 * @param {object} env Object containing global variables and methods from the host.
 */
shine.VM = function (env) {
	shine.EventEmitter.call(this);

	this._files = [];
	this._env = env || {};
	this._coroutineStack = [];

	this._resetGlobals();
};

shine.VM.prototype = new shine.EventEmitter ();
shine.VM.prototype.constructor = shine.VM;

/**
 * Resets all global variables to their original values.
 */
shine.VM.prototype._resetGlobals = function () {
	this._globals = this._bindLib(shine.lib);

	// Load standard lib into package.loaded:
	for (var i in this._globals) if (this._globals.hasOwnProperty(i) && this._globals[i] instanceof shine.Table) this._globals['package'].loaded[i] = this._globals[i];
	this._globals['package'].loaded._G = this._globals;

	// Load environment vars
	for (var i in this._env) if (this._env.hasOwnProperty(i)) this._globals[i] = this._env[i];
};

/**
 * Returns a copy of an object, with all functions bound to the VM. (recursive)
 */
shine.VM.prototype._bindLib = function (lib) {
	var result = shine.gc.createObject();

	for (var i in lib) {
		if (lib.hasOwnProperty(i)) {
			if (lib[i] && lib[i].constructor === Object) {
				result[i] = this._bindLib(lib[i]);

			} else if (typeof lib[i] == 'function') {
				result[i] = (function (func, context) {
					return function () { return func.apply(context, arguments); };
				})(lib[i], this);

			} else {
				result[i] = lib[i];
			}
		}
	}

	return new shine.Table(result);
};

/**
 * Loads a file containing compiled Luac code, decompiled to JSON.
 * @param {string} url The url of the file to load.
 * @param {boolean} [execute = true] Whether or not to execute the file once loaded.
 * @param {object} [coConfig] Coroutine configuration. Only applicable if execute == true.
 */
shine.VM.prototype.load = function (url, execute, coConfig) {
	var me = this,
		file;

	switch (typeof url) {

		case 'string':
			file = new shine.File(url);

			this._files.push(file);

			file.bind('loaded', function (data) {
				me._trigger('loaded-file', file);
				if (execute || execute === undefined) me.execute(coConfig, file);
			});

			this._trigger('loading-file', file);
			file.load();

			break;

		case 'object':
			file = new shine.File();
			file.data = url;
			if (execute || execute === undefined) me.execute(coConfig, file);

			break

		default:
			console.warn('Object of unknown type passed to shine.VM.load()');
	}

};

/**
 * Executes the loaded Luac data.
 * @param {object} [coConfig] Coroutine configuration.
 * @param {shine.File} [file] A specific file to execute. If not present, executes all files in the order loaded.
 */
shine.VM.prototype.execute = function (coConfig, file) {
	var me = this,
		files = file? [file] : this._files,
		index,
		file,
		thread;

	if (!files.length) throw new Error ('No files loaded.');

	for (index in files) {
		if (files.hasOwnProperty(index)) {

			file = files[index];
			if (!file.data) throw new Error('Tried to execute file before data loaded.');

			thread = this._thread = new shine.Function(this, file, file.data, this._globals);
			this._trigger('executing', [thread, coConfig]);

			try {
				if (!coConfig) {
					thread.call ();

				} else {
					var co = shine.lib.coroutine.wrap(thread),
						resume = function () {
							co();
							if (coConfig.uiOnly && co._coroutine.status != 'dead') window.setTimeout(resume, 1);
						};

					resume();
				}

			} catch (e) {
				shine.Error.catchExecutionError(e);
			}
		}
	}
};

/**
 * Creates or updates a global in the guest environment.
 * @param {String} name Name of the global variable.
 * @param {Object} value Value.
 */
shine.VM.prototype.setGlobal = function (name, value) {
	this._globals[name] = value;
};

/**
 * Dumps memory associated with the VM.
 */
shine.VM.prototype.dispose = function () {
	var thread;

	for (var i in this._files) if (this._files.hasOwnProperty(i)) this._files[i].dispose();

	if (thread = this._thread) thread.dispose();

	delete this._files;
	delete this._thread;
	delete this._globals;
	delete this._env;
	delete this._coroutineStack;

	// Clear static stacks -- Very dangerous for environments that contain multiple VMs!
	while (shine.Function._instances.length) shine.Function._instances.dispose(true);
	shine.Closure._graveyard.splice(0, shine.Closure._graveyard.length);
	shine.Coroutine._graveyard.splice(0, shine.Coroutine._graveyard.length);

};
<commit_msg>VM.getGlobal() added.<commit_after>/**
 * @fileOverview Lua virtual machine class.
 * @author Paul Cuthbertson
 * @copyright Gamesys Limited 2013
 */

var shine = shine || {};

/**
 * A Lua virtual machine.
 * @constructor
 * @extends shine.EventEmitter
 * @param {object} env Object containing global variables and methods from the host.
 */
shine.VM = function (env) {
	shine.EventEmitter.call(this);

	this._files = [];
	this._env = env || {};
	this._coroutineStack = [];

	this._resetGlobals();
};

shine.VM.prototype = new shine.EventEmitter ();
shine.VM.prototype.constructor = shine.VM;

/**
 * Resets all global variables to their original values.
 */
shine.VM.prototype._resetGlobals = function () {
	this._globals = this._bindLib(shine.lib);

	// Load standard lib into package.loaded:
	for (var i in this._globals) if (this._globals.hasOwnProperty(i) && this._globals[i] instanceof shine.Table) this._globals['package'].loaded[i] = this._globals[i];
	this._globals['package'].loaded._G = this._globals;

	// Load environment vars
	for (var i in this._env) if (this._env.hasOwnProperty(i)) this._globals[i] = this._env[i];
};

/**
 * Returns a copy of an object, with all functions bound to the VM. (recursive)
 */
shine.VM.prototype._bindLib = function (lib) {
	var result = shine.gc.createObject();

	for (var i in lib) {
		if (lib.hasOwnProperty(i)) {
			if (lib[i] && lib[i].constructor === Object) {
				result[i] = this._bindLib(lib[i]);

			} else if (typeof lib[i] == 'function') {
				result[i] = (function (func, context) {
					return function () { return func.apply(context, arguments); };
				})(lib[i], this);

			} else {
				result[i] = lib[i];
			}
		}
	}

	return new shine.Table(result);
};

/**
 * Loads a file containing compiled Luac code, decompiled to JSON.
 * @param {string} url The url of the file to load.
 * @param {boolean} [execute = true] Whether or not to execute the file once loaded.
 * @param {object} [coConfig] Coroutine configuration. Only applicable if execute == true.
 */
shine.VM.prototype.load = function (url, execute, coConfig) {
	var me = this,
		file;

	switch (typeof url) {

		case 'string':
			file = new shine.File(url);

			this._files.push(file);

			file.bind('loaded', function (data) {
				me._trigger('loaded-file', file);
				if (execute || execute === undefined) me.execute(coConfig, file);
			});

			this._trigger('loading-file', file);
			file.load();

			break;

		case 'object':
			file = new shine.File();
			file.data = url;
			if (execute || execute === undefined) me.execute(coConfig, file);

			break

		default:
			console.warn('Object of unknown type passed to shine.VM.load()');
	}

};

/**
 * Executes the loaded Luac data.
 * @param {object} [coConfig] Coroutine configuration.
 * @param {shine.File} [file] A specific file to execute. If not present, executes all files in the order loaded.
 */
shine.VM.prototype.execute = function (coConfig, file) {
	var me = this,
		files = file? [file] : this._files,
		index,
		file,
		thread;

	if (!files.length) throw new Error ('No files loaded.');

	for (index in files) {
		if (files.hasOwnProperty(index)) {

			file = files[index];
			if (!file.data) throw new Error('Tried to execute file before data loaded.');

			thread = this._thread = new shine.Function(this, file, file.data, this._globals);
			this._trigger('executing', [thread, coConfig]);

			try {
				if (!coConfig) {
					thread.call ();

				} else {
					var co = shine.lib.coroutine.wrap(thread),
						resume = function () {
							co();
							if (coConfig.uiOnly && co._coroutine.status != 'dead') window.setTimeout(resume, 1);
						};

					resume();
				}

			} catch (e) {
				shine.Error.catchExecutionError(e);
			}
		}
	}
};

/**
 * Creates or updates a global in the guest environment.
 * @param {String} name Name of the global variable.
 * @param {Object} value Value.
 */
shine.VM.prototype.setGlobal = function (name, value) {
	this._globals[name] = value;
};

/**
 * Retrieves a global from the guest environment.
 * @param {String} name Name of the global variable.
 * @returns {Object} Value of the global variable.
 */
shine.VM.prototype.getGlobal = function (name) {
	return this._globals[name];
};

/**
 * Dumps memory associated with the VM.
 */
shine.VM.prototype.dispose = function () {
	var thread;

	for (var i in this._files) if (this._files.hasOwnProperty(i)) this._files[i].dispose();

	if (thread = this._thread) thread.dispose();

	delete this._files;
	delete this._thread;
	delete this._globals;
	delete this._env;
	delete this._coroutineStack;

	// Clear static stacks -- Very dangerous for environments that contain multiple VMs!
	while (shine.Function._instances.length) shine.Function._instances.dispose(true);
	shine.Closure._graveyard.splice(0, shine.Closure._graveyard.length);
	shine.Coroutine._graveyard.splice(0, shine.Coroutine._graveyard.length);

};
<|endoftext|>


<commit_before>/**
 * @author kennethjiang / https://github.com/kennethjiang
 *
 *
 * Description: A THREE view port for STL models
 *
 * Usage:
 *  var viewPort = new THREE.STLViewPort(canvas, width, height, function() {
 *     //things to do when any model in the view port changes
 *  });
 *  viewPort.init();
 *  viewPort.loadSTL(url, fucntion(model) {
 *     viewPort.selectModel(model);
 *     //things to do when model is loaded
 *  });
 *  var scene = viewPort.scene; // direct access to the scene for to add THREE.Object
 *
 */

'use strict';

import { forEach } from 'lodash-es';
import * as THREE from 'three';
import { BufferGeometryAnalyzer, OrbitControls, TransformControls, STLLoader, PointerInteractions } from '3tk';
import { OrientationOptimizer } from './OrientationOptimizer';
import { Box3FromObject } from './Box3FromObject';

export function STLViewPort( canvas, width, height ) {

    var self = this;

    self.canvas = canvas;
    self.canvasWidth = width;
    self.canvasHeight = height;

    self.effectController = {
        metalness: 0.5,
        roughness: 0.5,
        modelInactiveColor: new THREE.Color("#60715b"),
        modelActiveColor: new THREE.Color("#34bf0d"),
        modelHoverColor: new THREE.Color("#84f25c"),
        ambientLightColor: new THREE.Color("#2b2b2b"),
        directionalLightColor: new THREE.Color("#ffffff"),
    };

    var eventType = { change: "change", add: "add", delete: "delete" };

    self.init = function() {

        self.camera = new THREE.PerspectiveCamera( 45, 1.0, 0.1, 5000 );

        self.camera.up.set( 0, 0, 1 );
        self.camera.position.set( -100, -200, 250 );

        self.scene = new THREE.Scene();

        // Lights
        var ambientLight = new THREE.AmbientLight( self.effectController.ambientLightColor );  // 0.2
        self.scene.add( ambientLight );
        var directionalLight = new THREE.DirectionalLight(self.effectController.directionalLightColor, 1.0);
        directionalLight.position.set( -100, -100, 500 );
        self.scene.add( directionalLight );
        var directionalLight2= new THREE.DirectionalLight(self.effectController.directionalLightColor, 1.0);
        directionalLight2.position.set( 100, 100, -500);
        self.scene.add( directionalLight2);
        var directionalLight3= new THREE.DirectionalLight(self.effectController.directionalLightColor, 0.2);
        directionalLight3.position.set( -300, 300, 500);
        self.scene.add( directionalLight3);

        self.renderer = new THREE.WebGLRenderer( { canvas: self.canvas, antialias: true } );

        self.renderer.setClearColor( 0xd8d8d8 );
        self.renderer.setSize( self.canvasWidth, self.canvasHeight );
        self.renderer.setPixelRatio( window.devicePixelRatio );

        self.renderer.gammaInput = true;
        self.renderer.gammaOutput = true;

        self.pointerInteractions = new PointerInteractions( self.renderer.domElement, self.camera, true ); // Need to use "recursive" as the intersection will be with the mesh, not the top level objects that are nothing but holder
        self.pointerInteractions.addEventListener("click", self.selectionChanged);
        self.pointerInteractions.addEventListener("hover", self.hoverChanged);

        self.orbitControls = new OrbitControls(self.camera, self.renderer.domElement, THREE.MOUSE.RIGHT);

        self.orbitControls.enableDamping = true;
        self.orbitControls.dampingFactor = 0.25;
        self.orbitControls.enablePan = false;
        self.orbitControls.addEventListener("change", self.render);
        self.orbitControls.addEventListener("start", self.startOrbit);
        self.orbitControls.addEventListener("end", self.endOrbit);

        // Must bind these before TransformControls because we want to attach it ourselves.
        // This will only work if events are run in the order that they are added, which is
        // true for modern browsers.
        self.renderer.domElement.addEventListener( "mousedown", self.onPointerDown, false );
        self.renderer.domElement.addEventListener( "touchstart", self.onPointerDown, false );

        self.transformControls = new TransformControls(self.camera, self.renderer.domElement);

        self.transformControls.setRotationSnap( THREE.Math.degToRad( 15 ) )
        self.transformControls.addEventListener("change", self.render);
        self.transformControls.addEventListener("transformStart", self.startTransform);
        self.transformControls.addEventListener("transformEnd", self.endTransform);
        self.transformControls.addEventListener("objectChange", self.onChange);
        self.transformControls.space = "world";
        self.transformControls.setHandles( 'translate', null );
        self.transformControls.setMode("translate");
        self.transformControls.axis = "XY";
        self.transformControls.setHandles( 'scale', null );
        self.scene.add(self.transformControls);

        window.addEventListener( 'keydown', self.onKeydown );
        window.addEventListener( 'keyup', self.onKeyup );

        self.animate();
    };

    self.dispose = function() {

        self.orbitControls.removeEventListener("change", self.render);
        self.orbitControls.removeEventListener("start", self.startOrbit);
        self.orbitControls.removeEventListener("end", self.endOrbit);
        self.transformControls.removeEventListener("change", self.render);
        self.transformControls.removeEventListener("transformStart", self.startTransform);
        self.transformControls.removeEventListener("transformEnd", self.endTransform);
        self.transformControls.removeEventListener("objectChange", self.onChange);
        self.renderer.domElement.removeEventListener( "mousedown", self.onPointerDown, false );
        self.renderer.domElement.removeEventListener( "touchstart", self.onPointerDown, false );
        window.removeEventListener( 'keydown', self.onKeydown );
        window.removeEventListener( 'keyup', self.onKeyup );

    }

    self.animate = function() {
        requestAnimationFrame( self.animate );

        self.update();
        self.transformControls.update();
        self.orbitControls.update();
        if (self.stats) self.stats.update();

        self.render();
    };

    self.update = function() {

        forEach( self.pointerInteractions.objects, function( model ) {
            if (model == self.selectedModel()) {
                model.children[0].material.color.copy(self.effectController.modelActiveColor);
            } else if ( self.pointerInteractions.hoveredObject && model == self.pointerInteractions.hoveredObject.parent ) {
                if ( self.transformControls.getMode() == "translate" ) {
                    model.children[0].material.color.copy(self.effectController.modelHoverColor);
                }
            } else {
                model.children[0].material.color.copy(self.effectController.modelInactiveColor);
            }
        });

    };

    self.render = function() {
        self.renderer.render( self.scene, self.camera );
    };

    self.loadSTL = function ( url, onLoad ) {
        new STLLoader().load(url, function ( geometry ) {
            self.addModelOfGeometry(geometry);
        });
    };

    self.addModelOfGeometry = function( geometry, modelToCopyTransformFrom ) {

        var material = new THREE.MeshStandardMaterial({
            color: self.effectController.modelInactiveColor,  // We'll mark it active below.
            shading: THREE.SmoothShading,
            side: THREE.DoubleSide,
            metalness: self.effectController.metalness,
            roughness: self.effectController.roughness,
            vertexColors: THREE.VertexColors });

        var stlModel = new THREE.Mesh( geometry, material );

        // center model's origin
        var model = new THREE.Object3D();
        model.add(stlModel);
        model.userData.box3FromObject = Box3FromObject(model);
        var center = model.userData.box3FromObject().getCenter();
        stlModel.position.copy(center.negate());
        if (modelToCopyTransformFrom) {
            model.rotation.copy(modelToCopyTransformFrom.rotation);
            model.scale.copy(modelToCopyTransformFrom.scale);
        }

        geometry.computeVertexNormals();
        model.orientationOptimizer = new OrientationOptimizer(geometry);
        self.recalculateOverhang(model);

        self.pointerInteractions.objects.push(model);
        self.pointerInteractions.update();

        self.scene.add(model);
        self.selectModel(model);

        self.dispatchEvent( { type: eventType.add, models: [ model ] } );
        return model;

    };

    // self.pointerInteractions is used to keep the source of truth for all models
    self.models = function() {
        return self.pointerInteractions.objects;
    }

    // self.transformControls is used to keep the source of truth for what model is currently selected
    self.selectedModel = function() {
        return self.transformControls.object;
    }

    self.setCursor = function(forceAuto=false) {
        if (self.transformControls.getMode() == "translate" && self.pointerInteractions.hoveredObject && !forceAuto) {
            $("#slicer-viewport").css("cursor", "move");
        } else {
            $("#slicer-viewport").css("cursor", "auto");
        }
    }

    /////////////////
    // EVENTS   /////
    // /////////////
    self.selectionChanged = function( event ) {
        if (event.current) {
            self.selectModel( event.current.parent );
        }
    };

    self.hoverChanged = function( event ) {
        self.setCursor();
    };

    self.onPointerDown = function( event ) {
        if ( self.pointerInteractions.hoveredObject && self.transformControls.getMode() == 'translate' ) {
            event.preventDefault();
            event.stopPropagation();
            self.transformControls.attach( self.pointerInteractions.hoveredObject.parent, event );
        }
    };

    self.onKeydown= function( event ) {
        switch ( event.keyCode ) {
            case 17: // Ctrl
                self.transformControls.setRotationSnap(null);
                break;
            case 46: // DEL key
            case 8: // backsapce key
                //       self.removeSelectedModel();
                break;
        }
    };

    self.onKeyup = function( event ) {
        switch ( event.keyCode ) {
            case 17: // Ctrl
                self.transformControls.setRotationSnap( THREE.Math.degToRad( 15 ) );
                break;
        }
    };

    self.onChange = function() {
        self.dispatchEvent( { type: eventType.change } );
    };

    var recentSelections = [];
    /**
     * params:
     *    m: model to make active. If m is undefined or not found, select from MRU.
     */
    self.selectModel = function(m) {
        if (self.pointerInteractions.objects.indexOf(m) > -1) {
            recentSelections.push(m);
            self.transformControls.attach(m);
        } else {
            // Requested model null or not found.  Look for a model to set active.
            while (recentSelections.length > 0) {
                var maybe = recentSelections.pop();
                if (self.pointerInteractions.objects.indexOf(maybe) > -1) {
                    recentSelections.push(maybe);
                    self.transformControls.attach(maybe);
                    break;
                }
            }
            if (recentSelections.length == 0) self.transformControls.detach();
        }

        self.onChange();
    };

    self.removeModel = function( model ) {
        if ( ! model )  return;

        var index = self.pointerInteractions.objects.indexOf(model);
        if (index > -1) {
            self.pointerInteractions.objects.splice(index, 1);
        }
        self.pointerInteractions.update();

        self.scene.remove(model);
        if ( model === self.selectedModel()) {
            self.selectModel(null);
        }
    };

    self.removeSelectedModel = function() {
        var model = self.selectedModel();
        self.removeModel( model );
        self.dispatchEvent( { type: eventType.delete, models: [model] } );
    };

    self.removeAllModels = function() {
        var arrayCopy = self.pointerInteractions.objects.slice(); // Removing element while iterating the array will cause trouble in JS
        forEach( arrayCopy, function( model ) {
            self.removeModel( model );
        });
        self.dispatchEvent( { type: eventType.delete, models: arrayCopy} );
    };

    self.laySelectedModelFlat = function(restricted) {

        var model = self.selectedModel();
        if (! model) return;

        var newOrientation;
        if (restricted) {
            newOrientation = model.orientationOptimizer.optimalOrientation( model.rotation, 0.7857); // Limit to 45 degree pivot
        } else {
            newOrientation = model.orientationOptimizer.optimalOrientation( model.rotation );
        }

        model.rotation.copy( newOrientation );
        self.recalculateOverhang(model);
        self.dispatchEvent( { type: eventType.change } );

    };

    self.duplicateSelectedModel = function( copies ) {
        for (var i = 0; i < copies; i++) {
            var originalModel = self.selectedModel();
            self.addModelOfGeometry( originalModel.children[0].geometry.clone(), originalModel);
        }
    };

    self.splitSelectedModel = function() {
        if (!self.selectedModel()) {
            return;
        }

        var originalModel = self.selectedModel()
        var geometry = originalModel.children[0].geometry;
        var newGeometries = BufferGeometryAnalyzer.isolatedGeometries(geometry);

        forEach(newGeometries, function(geometry) {
            self.addModelOfGeometry( geometry, originalModel );
        });

        self.removeModel( originalModel );
        self.dispatchEvent( { type: eventType.delete, models: [originalModel] } );
    };

    self.startOrbit = function () {
        self.setCursor(true);
    };

    self.endOrbit = function () {
        self.setCursor();
    };

    self.startTransform = function () {
        // Disable orbit controls
        self.orbitControls.enabled = false;
    };

    self.endTransform = function () {
        // Enable orbit controls
        self.orbitControls.enabled = true;

        self.recalculateOverhang( self.selectedModel() );
    };

    self.recalculateOverhang = function(model) {
        if (!model || !model.orientationOptimizer) return;
        if ( model.userData.previousRotation && model.rotation.equals(model.userData.previousRotation ) ) {
            model.userData.previousRotation = model.rotation.clone();
            return;
        }

        var orientation = model.orientationOptimizer.printabilityOfOrientationByRotation( model.rotation );
        self.tintSurfaces(model, null, 255, 255, 255); // Clear tints off the whole model
        self.tintSurfaces(model, orientation.overhang, 128, 16, 16);
        model.userData.previousRotation = model.rotation.clone();
    };

    self.tintSurfaces = function(model, surfaces, r, g, b) {

        var geometry = model.children[0].geometry;
        var colors = geometry.attributes.color !== undefined ? geometry.attributes.color.array : [];

        if (surfaces) {

            for ( var i = 0; i < surfaces.length; i++) {
                for ( var index of surfaces[i].faceIndices ) {
                    colors[index] = r/255;
                    colors[index+1] = g/255;
                    colors[index+2] = b/255;
                    colors[index+3] = r/255;
                    colors[index+4] = g/255;
                    colors[index+5] = b/255;
                    colors[index+6] = r/255;
                    colors[index+7] = g/255;
                    colors[index+8] = b/255;
                }
            }

        } else {

            for ( var i = 0; i < geometry.attributes.position.array.length; i++ ) colors[i] = 1;

        }
        setGeometryColors(geometry, colors);
    };

    function setGeometryColors(geometry, colors) {
        geometry.removeAttribute( 'color' );
        geometry.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) );
    }

}
STLViewPort.prototype = Object.create( THREE.EventDispatcher.prototype );
STLViewPort.prototype.constructor = STLViewPort;
<commit_msg>Delete key to remove model seems to work. Need to test on other browsers<commit_after>/**
 * @author kennethjiang / https://github.com/kennethjiang
 *
 *
 * Description: A THREE view port for STL models
 *
 * Usage:
 *  var viewPort = new THREE.STLViewPort(canvas, width, height, function() {
 *     //things to do when any model in the view port changes
 *  });
 *  viewPort.init();
 *  viewPort.loadSTL(url, fucntion(model) {
 *     viewPort.selectModel(model);
 *     //things to do when model is loaded
 *  });
 *  var scene = viewPort.scene; // direct access to the scene for to add THREE.Object
 *
 */

'use strict';

import { forEach } from 'lodash-es';
import * as THREE from 'three';
import { BufferGeometryAnalyzer, OrbitControls, TransformControls, STLLoader, PointerInteractions } from '3tk';
import { OrientationOptimizer } from './OrientationOptimizer';
import { Box3FromObject } from './Box3FromObject';

export function STLViewPort( canvas, width, height ) {

    var self = this;

    self.canvas = canvas;
    self.canvasWidth = width;
    self.canvasHeight = height;

    self.effectController = {
        metalness: 0.5,
        roughness: 0.5,
        modelInactiveColor: new THREE.Color("#60715b"),
        modelActiveColor: new THREE.Color("#34bf0d"),
        modelHoverColor: new THREE.Color("#84f25c"),
        ambientLightColor: new THREE.Color("#2b2b2b"),
        directionalLightColor: new THREE.Color("#ffffff"),
    };

    var eventType = { change: "change", add: "add", delete: "delete" };

    self.init = function() {

        self.camera = new THREE.PerspectiveCamera( 45, 1.0, 0.1, 5000 );

        self.camera.up.set( 0, 0, 1 );
        self.camera.position.set( -100, -200, 250 );

        self.scene = new THREE.Scene();

        // Lights
        var ambientLight = new THREE.AmbientLight( self.effectController.ambientLightColor );  // 0.2
        self.scene.add( ambientLight );
        var directionalLight = new THREE.DirectionalLight(self.effectController.directionalLightColor, 1.0);
        directionalLight.position.set( -100, -100, 500 );
        self.scene.add( directionalLight );
        var directionalLight2= new THREE.DirectionalLight(self.effectController.directionalLightColor, 1.0);
        directionalLight2.position.set( 100, 100, -500);
        self.scene.add( directionalLight2);
        var directionalLight3= new THREE.DirectionalLight(self.effectController.directionalLightColor, 0.2);
        directionalLight3.position.set( -300, 300, 500);
        self.scene.add( directionalLight3);

        self.renderer = new THREE.WebGLRenderer( { canvas: self.canvas, antialias: true } );

        self.renderer.setClearColor( 0xd8d8d8 );
        self.renderer.setSize( self.canvasWidth, self.canvasHeight );
        self.renderer.setPixelRatio( window.devicePixelRatio );

        self.renderer.gammaInput = true;
        self.renderer.gammaOutput = true;

        self.pointerInteractions = new PointerInteractions( self.renderer.domElement, self.camera, true ); // Need to use "recursive" as the intersection will be with the mesh, not the top level objects that are nothing but holder
        self.pointerInteractions.addEventListener("click", self.selectionChanged);
        self.pointerInteractions.addEventListener("hover", self.hoverChanged);

        self.orbitControls = new OrbitControls(self.camera, self.renderer.domElement, THREE.MOUSE.RIGHT);

        self.orbitControls.enableDamping = true;
        self.orbitControls.dampingFactor = 0.25;
        self.orbitControls.enablePan = false;
        self.orbitControls.addEventListener("change", self.render);
        self.orbitControls.addEventListener("start", self.startOrbit);
        self.orbitControls.addEventListener("end", self.endOrbit);

        // Must bind these before TransformControls because we want to attach it ourselves.
        // This will only work if events are run in the order that they are added, which is
        // true for modern browsers.
        self.renderer.domElement.addEventListener( "mousedown", self.onPointerDown, false );
        self.renderer.domElement.addEventListener( "touchstart", self.onPointerDown, false );

        self.transformControls = new TransformControls(self.camera, self.renderer.domElement);

        self.transformControls.setRotationSnap( THREE.Math.degToRad( 15 ) )
        self.transformControls.addEventListener("change", self.render);
        self.transformControls.addEventListener("transformStart", self.startTransform);
        self.transformControls.addEventListener("transformEnd", self.endTransform);
        self.transformControls.addEventListener("objectChange", self.onChange);
        self.transformControls.space = "world";
        self.transformControls.setHandles( 'translate', null );
        self.transformControls.setMode("translate");
        self.transformControls.axis = "XY";
        self.transformControls.setHandles( 'scale', null );
        self.scene.add(self.transformControls);

        window.addEventListener( 'keydown', self.onKeydown );
        window.addEventListener( 'keyup', self.onKeyup );

        self.animate();
    };

    self.dispose = function() {

        self.orbitControls.removeEventListener("change", self.render);
        self.orbitControls.removeEventListener("start", self.startOrbit);
        self.orbitControls.removeEventListener("end", self.endOrbit);
        self.transformControls.removeEventListener("change", self.render);
        self.transformControls.removeEventListener("transformStart", self.startTransform);
        self.transformControls.removeEventListener("transformEnd", self.endTransform);
        self.transformControls.removeEventListener("objectChange", self.onChange);
        self.renderer.domElement.removeEventListener( "mousedown", self.onPointerDown, false );
        self.renderer.domElement.removeEventListener( "touchstart", self.onPointerDown, false );
        window.removeEventListener( 'keydown', self.onKeydown );
        window.removeEventListener( 'keyup', self.onKeyup );

    }

    self.animate = function() {
        requestAnimationFrame( self.animate );

        self.update();
        self.transformControls.update();
        self.orbitControls.update();
        if (self.stats) self.stats.update();

        self.render();
    };

    self.update = function() {

        forEach( self.pointerInteractions.objects, function( model ) {
            if (model == self.selectedModel()) {
                model.children[0].material.color.copy(self.effectController.modelActiveColor);
            } else if ( self.pointerInteractions.hoveredObject && model == self.pointerInteractions.hoveredObject.parent ) {
                if ( self.transformControls.getMode() == "translate" ) {
                    model.children[0].material.color.copy(self.effectController.modelHoverColor);
                }
            } else {
                model.children[0].material.color.copy(self.effectController.modelInactiveColor);
            }
        });

    };

    self.render = function() {
        self.renderer.render( self.scene, self.camera );
    };

    self.loadSTL = function ( url, onLoad ) {
        new STLLoader().load(url, function ( geometry ) {
            self.addModelOfGeometry(geometry);
        });
    };

    self.addModelOfGeometry = function( geometry, modelToCopyTransformFrom ) {

        var material = new THREE.MeshStandardMaterial({
            color: self.effectController.modelInactiveColor,  // We'll mark it active below.
            shading: THREE.SmoothShading,
            side: THREE.DoubleSide,
            metalness: self.effectController.metalness,
            roughness: self.effectController.roughness,
            vertexColors: THREE.VertexColors });

        var stlModel = new THREE.Mesh( geometry, material );

        // center model's origin
        var model = new THREE.Object3D();
        model.add(stlModel);
        model.userData.box3FromObject = Box3FromObject(model);
        var center = model.userData.box3FromObject().getCenter();
        stlModel.position.copy(center.negate());
        if (modelToCopyTransformFrom) {
            model.rotation.copy(modelToCopyTransformFrom.rotation);
            model.scale.copy(modelToCopyTransformFrom.scale);
        }

        geometry.computeVertexNormals();
        model.orientationOptimizer = new OrientationOptimizer(geometry);
        self.recalculateOverhang(model);

        self.pointerInteractions.objects.push(model);
        self.pointerInteractions.update();

        self.scene.add(model);
        self.selectModel(model);

        self.dispatchEvent( { type: eventType.add, models: [ model ] } );
        return model;

    };

    // self.pointerInteractions is used to keep the source of truth for all models
    self.models = function() {
        return self.pointerInteractions.objects;
    }

    // self.transformControls is used to keep the source of truth for what model is currently selected
    self.selectedModel = function() {
        return self.transformControls.object;
    }

    self.setCursor = function(forceAuto=false) {
        if (self.transformControls.getMode() == "translate" && self.pointerInteractions.hoveredObject && !forceAuto) {
            $("#slicer-viewport").css("cursor", "move");
        } else {
            $("#slicer-viewport").css("cursor", "auto");
        }
    }

    /////////////////
    // EVENTS   /////
    // /////////////
    self.selectionChanged = function( event ) {
        if (event.current) {
            self.selectModel( event.current.parent );
        }
    };

    self.hoverChanged = function( event ) {
        self.setCursor();
    };

    self.onPointerDown = function( event ) {
        if ( self.pointerInteractions.hoveredObject && self.transformControls.getMode() == 'translate' ) {
            event.preventDefault();
            event.stopPropagation();
            self.transformControls.attach( self.pointerInteractions.hoveredObject.parent, event );
        }
    };

    self.onKeydown= function( event ) {
        switch ( event.keyCode ) {
            case 17: // Ctrl
                self.transformControls.setRotationSnap(null);
                break;
            case 46: // DEL key
            case 8: // backsapce key
                self.removeSelectedModel();
                break;
        }
    };

    self.onKeyup = function( event ) {
        switch ( event.keyCode ) {
            case 17: // Ctrl
                self.transformControls.setRotationSnap( THREE.Math.degToRad( 15 ) );
                break;
        }
    };

    self.onChange = function() {
        self.dispatchEvent( { type: eventType.change } );
    };

    var recentSelections = [];
    /**
     * params:
     *    m: model to make active. If m is undefined or not found, select from MRU.
     */
    self.selectModel = function(m) {
        if (self.pointerInteractions.objects.indexOf(m) > -1) {
            recentSelections.push(m);
            self.transformControls.attach(m);
        } else {
            // Requested model null or not found.  Look for a model to set active.
            while (recentSelections.length > 0) {
                var maybe = recentSelections.pop();
                if (self.pointerInteractions.objects.indexOf(maybe) > -1) {
                    recentSelections.push(maybe);
                    self.transformControls.attach(maybe);
                    break;
                }
            }
            if (recentSelections.length == 0) self.transformControls.detach();
        }

        self.onChange();
    };

    self.removeModel = function( model ) {
        if ( ! model )  return;

        var index = self.pointerInteractions.objects.indexOf(model);
        if (index > -1) {
            self.pointerInteractions.objects.splice(index, 1);
        }
        self.pointerInteractions.update();

        self.scene.remove(model);
        if ( model === self.selectedModel()) {
            self.selectModel(null);
        }
    };

    self.removeSelectedModel = function() {
        var model = self.selectedModel();
        self.removeModel( model );
        self.dispatchEvent( { type: eventType.delete, models: [model] } );
    };

    self.removeAllModels = function() {
        var arrayCopy = self.pointerInteractions.objects.slice(); // Removing element while iterating the array will cause trouble in JS
        forEach( arrayCopy, function( model ) {
            self.removeModel( model );
        });
        self.dispatchEvent( { type: eventType.delete, models: arrayCopy} );
    };

    self.laySelectedModelFlat = function(restricted) {

        var model = self.selectedModel();
        if (! model) return;

        var newOrientation;
        if (restricted) {
            newOrientation = model.orientationOptimizer.optimalOrientation( model.rotation, 0.7857); // Limit to 45 degree pivot
        } else {
            newOrientation = model.orientationOptimizer.optimalOrientation( model.rotation );
        }

        model.rotation.copy( newOrientation );
        self.recalculateOverhang(model);
        self.dispatchEvent( { type: eventType.change } );

    };

    self.duplicateSelectedModel = function( copies ) {
        for (var i = 0; i < copies; i++) {
            var originalModel = self.selectedModel();
            self.addModelOfGeometry( originalModel.children[0].geometry.clone(), originalModel);
        }
    };

    self.splitSelectedModel = function() {
        if (!self.selectedModel()) {
            return;
        }

        var originalModel = self.selectedModel()
        var geometry = originalModel.children[0].geometry;
        var newGeometries = BufferGeometryAnalyzer.isolatedGeometries(geometry);

        forEach(newGeometries, function(geometry) {
            self.addModelOfGeometry( geometry, originalModel );
        });

        self.removeModel( originalModel );
        self.dispatchEvent( { type: eventType.delete, models: [originalModel] } );
    };

    self.startOrbit = function () {
        self.setCursor(true);
    };

    self.endOrbit = function () {
        self.setCursor();
    };

    self.startTransform = function () {
        // Disable orbit controls
        self.orbitControls.enabled = false;
    };

    self.endTransform = function () {
        // Enable orbit controls
        self.orbitControls.enabled = true;

        self.recalculateOverhang( self.selectedModel() );
    };

    self.recalculateOverhang = function(model) {
        if (!model || !model.orientationOptimizer) return;
        if ( model.userData.previousRotation && model.rotation.equals(model.userData.previousRotation ) ) {
            model.userData.previousRotation = model.rotation.clone();
            return;
        }

        var orientation = model.orientationOptimizer.printabilityOfOrientationByRotation( model.rotation );
        self.tintSurfaces(model, null, 255, 255, 255); // Clear tints off the whole model
        self.tintSurfaces(model, orientation.overhang, 128, 16, 16);
        model.userData.previousRotation = model.rotation.clone();
    };

    self.tintSurfaces = function(model, surfaces, r, g, b) {

        var geometry = model.children[0].geometry;
        var colors = geometry.attributes.color !== undefined ? geometry.attributes.color.array : [];

        if (surfaces) {

            for ( var i = 0; i < surfaces.length; i++) {
                for ( var index of surfaces[i].faceIndices ) {
                    colors[index] = r/255;
                    colors[index+1] = g/255;
                    colors[index+2] = b/255;
                    colors[index+3] = r/255;
                    colors[index+4] = g/255;
                    colors[index+5] = b/255;
                    colors[index+6] = r/255;
                    colors[index+7] = g/255;
                    colors[index+8] = b/255;
                }
            }

        } else {

            for ( var i = 0; i < geometry.attributes.position.array.length; i++ ) colors[i] = 1;

        }
        setGeometryColors(geometry, colors);
    };

    function setGeometryColors(geometry, colors) {
        geometry.removeAttribute( 'color' );
        geometry.addAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) );
    }

}
STLViewPort.prototype = Object.create( THREE.EventDispatcher.prototype );
STLViewPort.prototype.constructor = STLViewPort;
<|endoftext|>


<commit_before>var _ = require('lodash');
var async = require('async');
var debug = require('debug')('seguir:comment');

module.exports = function (api) {
  var client = api.client;
  var q = client.queries;

  function createComment (keyspace, user, post, commented, commentdata, next) {
    var comment = client.generateId();
    var newCommentRow = [comment, user, post, commented, commentdata];

    debug('insert into comments:', 'comments', newCommentRow);
    client.execute(q(keyspace, 'insertComment'), newCommentRow, {}, function (err, result) {
      if (err) { return next(err); }

      var newCommentTimelineRow = [post, client.generateTimeId(commented), comment];
      debug('insert into comments timeline:', 'comments_timeline', newCommentTimelineRow);
      client.execute(q(keyspace, 'insertCommentsTimeline'), newCommentTimelineRow, {}, function (err, result) {
        if (err) { return next(err); }

        var countUpdate = [1, post.toString()];
        debug('update comment counts:', 'counts', countUpdate);
        client.execute(q(keyspace, 'updateCounter', {TYPE: 'comment'}), countUpdate, {cacheKey: 'count:comment:' + post}, function (err, result) {
          if (err) { return next(err); }

          var newComment = _.zipObject(['comment', 'user', 'post', 'commented', 'commentdata'], newCommentRow);
          api.metrics.increment('comment.add');
          api.user.mapUserIdToUser(keyspace, newComment, ['user'], null, next);
        });
      });
    });
  }

  function getComments (keyspace, post, options, next) {
    if (!next) {
      next = options;
      options = {};
    }

    client.get(q(keyspace, 'selectCount', {TYPE: 'comment'}), [post.toString()], {cacheKey: 'count:comment:' + post}, function (err, result) {
      if (err) { return next(err); }

      if (result && result.count) {
        var pageState = options.pageState;
        var pageSize = +result.count; // options.pageSize || 5; once we have pagination for comments

        api.metrics.increment('comments_timeline.list');
        debug('select comments timeline:', 'comments_timeline', [post]);
        client.execute(q(keyspace, 'selectCommentsTimeline'), [post], {pageState: pageState, pageSize: pageSize}, function (err, timeline, nextPageState) {
          if (err) { return next(err); }

          async.mapSeries(timeline, function (timelineEntry, cb) {
            debug('select comment:', 'comments', [timelineEntry.comment]);
            client.get(q(keyspace, 'selectComment'), [timelineEntry.comment], {cacheKey: 'comment:' + timelineEntry.comment}, function (err, comment) {
              if (err) { return cb(err); }
              cb(null, comment);
            });
          }, function (err, comments) {
            if (err) { return next(err); }

            api.user.mapUserIdToUser(keyspace, comments, ['user'], null, true, {}, function (err, commentsWithUser) {
              if (err) { return next(err); }

              next(null, {
                total: +result.count,
                comments: commentsWithUser,
                nextPageState: nextPageState
              });
            });
          });
        });
      } else {
        next(null, {
          total: 0,
          comments: [],
          nextPageState: null
        });
      }
    });
  }

  return {
    createComment: createComment,
    getComments: getComments
  };
};
<commit_msg>ignore deleted comments when get comments for a post, also fetch unto latest 5000 comments for now<commit_after>var _ = require('lodash');
var async = require('async');
var debug = require('debug')('seguir:comment');

module.exports = function (api) {
  var client = api.client;
  var q = client.queries;

  function createComment (keyspace, user, post, commented, commentdata, next) {
    var comment = client.generateId();
    var newCommentRow = [comment, user, post, commented, commentdata];

    debug('insert into comments:', 'comments', newCommentRow);
    client.execute(q(keyspace, 'insertComment'), newCommentRow, {}, function (err, result) {
      if (err) { return next(err); }

      var newCommentTimelineRow = [post, client.generateTimeId(commented), comment];
      debug('insert into comments timeline:', 'comments_timeline', newCommentTimelineRow);
      client.execute(q(keyspace, 'insertCommentsTimeline'), newCommentTimelineRow, {}, function (err, result) {
        if (err) { return next(err); }

        var countUpdate = [1, post.toString()];
        debug('update comment counts:', 'counts', countUpdate);
        client.execute(q(keyspace, 'updateCounter', {TYPE: 'comment'}), countUpdate, {cacheKey: 'count:comment:' + post}, function (err, result) {
          if (err) { return next(err); }

          var newComment = _.zipObject(['comment', 'user', 'post', 'commented', 'commentdata'], newCommentRow);
          api.metrics.increment('comment.add');
          api.user.mapUserIdToUser(keyspace, newComment, ['user'], null, next);
        });
      });
    });
  }

  // returns upto latest 5000 (default fetchSize of cassandra-driver) comments for a post
  function getComments (keyspace, post, options, next) {
    if (!next) {
      next = options;
      options = {};
    }

    client.get(q(keyspace, 'selectCount', {TYPE: 'comment'}), [post.toString()], {cacheKey: 'count:comment:' + post}, function (err, result) {
      if (err) { return next(err); }

      if (result && +result.count > 0) {
        api.metrics.increment('comments_timeline.list');
        debug('select comments timeline:', 'comments_timeline', [post]);
        client.execute(q(keyspace, 'selectCommentsTimeline'), [post], {}, function (err, timeline, nextPageState) {
          if (err) { return next(err); }

          async.mapSeries(timeline, function (timelineEntry, cb) {
            debug('select comment:', 'comments', [timelineEntry.comment]);
            client.get(q(keyspace, 'selectComment'), [timelineEntry.comment], {cacheKey: 'comment:' + timelineEntry.comment}, function (err, comment) {
              if (err) { return cb(err); }
              cb(null, comment);
            });
          }, function (err, comments) {
            if (err) { return next(err); }

            api.user.mapUserIdToUser(keyspace, comments.filter(_.identity), ['user'], null, true, {}, function (err, commentsWithUser) {
              if (err) { return next(err); }

              next(null, {
                total: +result.count,
                comments: commentsWithUser,
                nextPageState: nextPageState
              });
            });
          });
        });
      } else {
        next(null, {
          total: 0,
          comments: [],
          nextPageState: null
        });
      }
    });
  }

  return {
    createComment: createComment,
    getComments: getComments
  };
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Link } from 'react-router-dom';

import * as BooksAPI from './BooksAPI';
import SearchBooksText from './SearchBooksText';

class SearchBooks extends Component {
  state = {
    books: []
  }

  search = (text) => {
    return new Promise((resolve, reject) => {
      if(text === "") {
        this.setState({ books: [] });
        return resolve([]);
      }

      BooksAPI.search(text, 100).then((books) => {
        if(!Array.isArray(books)) {
          books = [];
        }

        this.setState({ books });
        resolve(books);
      });
    });
  }

  render() {
    const { books } = this.state;

    return (

            <Link className="close-search" to="/">Close</Link>

              {/*
                NOTES: The search from BooksAPI is limited to a particular set of search terms.
                You can find these search terms here:
                https://github.com/udacity/reactnd-project-myreads-starter/blob/master/SEARCH_TERMS.md

                However, remember that the BooksAPI.search method DOES search by title or author. So, don't worry if
                you don't find a specific author or title. Every search is limited by search terms.
              */}
              <SearchBooksText search={this.search}/>

              {books.map(book =>

                        <select>
                          <option value="none" disabled>Move to...</option>
                          <option value="currentlyReading">Currently Reading</option>
                          <option value="wantToRead">Want to Read</option>
                          <option value="read">Read</option>
                          <option value="none">None</option>
                        </select>

{book.title}

{/*book.authors.map(author => ({author} +
))*/}

              )}

    );
  }
}

export default SearchBooks<commit_msg>SearchBooks > Added book image<commit_after>import React, { Component } from 'react';
import { Link } from 'react-router-dom';

import * as BooksAPI from './BooksAPI';
import SearchBooksText from './SearchBooksText';

class SearchBooks extends Component {
  state = {
    books: []
  }

  search = (text) => {
    return new Promise((resolve, reject) => {
      if(text === "") {
        this.setState({ books: [] });
        return resolve([]);
      }

      BooksAPI.search(text, 100).then((books) => {
        if(!Array.isArray(books)) {
          books = [];
        }

        this.setState({ books });
        resolve(books);
      });
    });
  }

  render() {
    const { books } = this.state;

    return (

            <Link className="close-search" to="/">Close</Link>

              {/*
                NOTES: The search from BooksAPI is limited to a particular set of search terms.
                You can find these search terms here:
                https://github.com/udacity/reactnd-project-myreads-starter/blob/master/SEARCH_TERMS.md

                However, remember that the BooksAPI.search method DOES search by title or author. So, don't worry if
                you don't find a specific author or title. Every search is limited by search terms.
              */}
              <SearchBooksText search={this.search}/>

              {books.map(book =>

                        <select>
                          <option value="none" disabled>Move to...</option>
                          <option value="currentlyReading">Currently Reading</option>
                          <option value="wantToRead">Want to Read</option>
                          <option value="read">Read</option>
                          <option value="none">None</option>
                        </select>

{book.title}

{/*book.authors.map(author => ({author} +
))*/}

              )}

    );
  }
}

export default SearchBooks<|endoftext|>


<commit_before>/*
 * This program was produced for the U.S. Agency for International Development. It was prepared by the USAID | DELIVER PROJECT, Task Order 4. It is part of a project which utilizes code originally licensed under the terms of the Mozilla Public License (MPL) v2 and therefore is licensed under MPL v2 or later.
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the Mozilla Public License as published by the Mozilla Foundation, either version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public License for more details.
 *
 * You should have received a copy of the Mozilla Public License along with this program. If not, see http://www.mozilla.org/MPL/
 */

function SummaryReportController($scope, $filter, ngTableParams, SummaryReport, ReportSchedules, ReportPrograms, ReportPeriods, ProductCategoriesByProgram, ReportProductsByProgram, ReportFacilityTypes, GeographicZones, RequisitionGroupsByProgram, AllFacilites, $http, $routeParams, $location) {

  $scope.exportReport = function (type) {
    $scope.filterObject.pdformat = 1;
    var params = jQuery.param($scope.filterObject);
    var url = '/reports/download/summary/' + type + '?' + params;
    window.open(url);
  };

  $scope.OnFilterChanged = function() {
        // clear old data if there was any
        $scope.data = $scope.datarows = [];
        $scope.filter.max = 10000;
        SummaryReport.get($scope.filter, function(data) {
            if (data.pages !== undefined && data.pages.rows !== undefined) {
                $scope.data = data.pages.rows;
                $scope.paramsChanged($scope.tableParams);
            }
        });
    };

}
<commit_msg>Fix export feature on summary report<commit_after>/*
 * This program was produced for the U.S. Agency for International Development. It was prepared by the USAID | DELIVER PROJECT, Task Order 4. It is part of a project which utilizes code originally licensed under the terms of the Mozilla Public License (MPL) v2 and therefore is licensed under MPL v2 or later.
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the Mozilla Public License as published by the Mozilla Foundation, either version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public License for more details.
 *
 * You should have received a copy of the Mozilla Public License along with this program. If not, see http://www.mozilla.org/MPL/
 */

function SummaryReportController($scope, $filter, ngTableParams, SummaryReport, ReportSchedules, ReportPrograms, ReportPeriods, ProductCategoriesByProgram, ReportProductsByProgram, ReportFacilityTypes, GeographicZones, RequisitionGroupsByProgram, AllFacilites, $http, $routeParams, $location) {

  $scope.exportReport = function (type) {
    $scope.filter.pdformat = 1;
    var params = jQuery.param($scope.filter);
    var url = '/reports/download/summary/' + type + '?' + params;
    window.open(url);
  };

  $scope.OnFilterChanged = function() {
        // clear old data if there was any
        $scope.data = $scope.datarows = [];
        $scope.filter.max = 10000;
        SummaryReport.get($scope.filter, function(data) {
            if (data.pages !== undefined && data.pages.rows !== undefined) {
                $scope.data = data.pages.rows;
                $scope.paramsChanged($scope.tableParams);
            }
        });
    };

}
<|endoftext|>


<commit_before>require('dotenv').config()
const express = require('express')
const app = require('express')()
const bodyParser = require('body-parser')
const port = 1337

const MongoClient = require("mongodb").MongoClient
const MONGODB_URI = process.env.MONGODB_URI
const collections = {}

MongoClient.connect(MONGODB_URI, (err, database) => {
	if (err) return console.log(err)
	db = database
	collections.generators = db.collection('generators')
	collections.stands = db.collection('stands')
	collections.devices = db.collection('devices')
	collections.messages = db.collection('messages')
	collections.settings = db.collection('settings')
})

app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
	extended: true
}))

app
	.set('view engine', 'pug')
	.use(express.static('public'))
	.listen(process.env.PORT || port, () => {
		console.log('api server on http://localhost:' + port)
	})

app.get('/api/v1/settings', (req, res) => {
	collections.settings.findOne({}, function(err, setting) {
		res.render('components/settings', {
			setting
		})
	})
})

app.post('/api/v1/settings', (req, res) => {
	const multiplier = req.body.multiplier

	const data = {
		multiplier: multiplier
	}

	collections.settings.findOne({}, function(err, setting) {
		if (setting == null) {
			collections.settings.save(data, (err, result) => {
				if (err) return console.log(err)
			})
		} else {
			collections.settings.updateOne(setting, {
				$set: data
			}, (error, result) => {
				if (err) return console.log(err)
			})

		}
		res.redirect('/api/v1/settings')
	})
})

app.get('/api/v1/reset', (req, res) => {
	const updateData = {
		multiplier: 0,
		created_at: Date.now()
	}

	collections.settings.findOne({}, function(err, setting) {
		collections.settings.updateOne(setting, {
			$set: updateData
		}, (error, result) => {
			if (err) return console.log(err)
			console.info('Settings reset!')
			res.redirect('/api/v1/settings')
		})
	})

})

app.get('/api/v1/init/generator/:generator', (req, res) => {
	const generator = req.params.generator
	initGenerator(generator)
})

app.get('/api/v1/init/generator/:generator/stand/:stand', (req, res) => {
	const generator = req.params.generator
	const stand = req.params.stand
	initStand(generator, stand)
})

app.get('/api/v1/init/stand/:stand/device/:device', (req, res) => {
	const stand = req.params.stand
	const device = req.params.device
	initDevice(stand, device)
})

app.get('/api/v1/generator/:generator', (req, res) => {
	const generator = req.params.generator

	collections.generators.findOne({
		name: generator
	}, (err, generator) => {
		if (err) return console.log(err)
		collections.stands.find({
			"generator": generator._id
		}, {}).toArray(function(err, stands) {
			const response = {}
			response.generatorId = generator._id
			response.generatorName = generator.name
			response.stands = stands
			response.timestamp = Date.now()

			res.json(JSON.stringify(response))
		})
	})
})

app.get('/api/v1/stand/:stand', (req, res) => {
	const stand = req.params.stand

	collections.stands.findOne({
		name: stand
	}, (err, stand) => {
		if (err) return console.log(err)
		res.json(JSON.stringify(stand))
	})
})

app.get('/api/v1/stand/:stand/messages', (req, res) => {
	const stand = req.params.stand
	let quantity = parseInt(req.query.q)

	// check if quantity is given, otherwise return all messages
	if (quantity == NaN) {
		quantity = ''
	}

	collections.stands.findOne({
		name: stand
	}, (err, stand) => {
		if (err) return console.log(err)
		collections.messages.find({
			"stand": stand._id
		}, {}).limit(quantity).sort({
			$natural: -1
		}).toArray(function(err, messages) {
			const response = {}
			response.generatorId = messages[0].generator
			response.standId = stand._id
			response.standName = stand.name
			response.messages = messages
			response.timestamp = Date.now()

			res.json(response)
		})
	})
})

app.get('/api/v1/generator/:generator/messages', (req, res) => {
	const generator = req.params.generator
	let quantity = parseInt(req.query.q)

	// check if quantity is given, otherwise return all messages
	if (quantity == NaN) {
		quantity = ''
	}

	collections.generators.findOne({
		name: generator
	}, (err, generator) => {
		if (err) return console.log(err)
		collections.messages.find({
			"generator": generator._id
		}, {}).limit(quantity).sort({
			$natural: -1
		}).toArray(function(err, messages) {
			const response = {}
			response.generatorId = generator._id
			response.standName = generator.name
			response.messages = messages
			response.timestamp = Date.now()

			res.json(response)
		})
	})
})

const generate = () => {
	setInterval(function() {
		generateMessages()
	}, 1000)
}

const initGenerator = (generator) => {
	const data = {
		name: generator,
		created_at: Date.now()
	}

	collections.generators.save(data, (err, result) => {
		if (err) return console.log(err)
		console.info('Created generator called `' + data.name + '`')

	})
}

const initStand = (generator, stand) => {
	collections.generators.findOne({
		name: generator
	}, (err, generator) => {
		if (err) return console.log(err)
		const data = {
			name: stand,
			generator: generator._id,
			devices: [],
			created_at: Date.now()
		}

		collections.stands.save(data, (err, result) => {
			if (err) return console.log(err)
			console.info('Created stand called `' + data.name + '` that is connected to generator `' + generator.name + '`')
		})
	})
}

const initDevice = (stand, device) => {
	collections.stands.findOne({
		name: stand
	}, (err, stand) => {
		if (err) return console.log(err)
		const data = {
			name: device,
			stand: stand._id,
			created_at: Date.now()
		}

		// collections.devices.save(data, (err, result) => {
		// 	if (err) return console.log(err)
		// 	console.info('Created device called `' + data.name + '` that is connected to stand `' + stand.name + '`')
		// })

		const updateData = {}

		if (stand.devices == undefined) {
			updateData.devices = [data]
		} else {
			const devicesArr = stand.devices
			devicesArr.push(data)
			updateData.devices = devicesArr
		}

		collections.stands.findOne({
			_id: stand._id
		}, function(err, stand) {
			collections.stands.updateOne(stand, {
				$set: updateData
			}, (error, result) => {
				if (err) return console.log(err)
			})
		});

	})

}

const generateMessages = () => {
	console.log("generating")
	// return

	collections.stands.find({}, {}).toArray(function(err, stands) {
		stands.forEach((stand) => {
			let multiplier = 0
			collections.settings.findOne({}, function(err, setting) {
				if (err) return console.log(err)
				multiplier = setting.multiplier

				const standData = {
					type: 'stand',
					stand: stand.name,
					timestamp: Date.now(),
					avr_va: 0,
					min_va: 0,
					max_va: 0

				}
				stand.devices.forEach((device) => {
					const deviceData = {
						type: 'device',
						device: device.name,
						stand: device.stand,
						timestamp: Date.now(),
						avr_va: randomNum(905 * multiplier, 906 * multiplier),
						min_va: randomNum(865 * multiplier, 867 * multiplier),
						max_va: randomNum(954 * multiplier, 956 * multiplier)
					}

					standData.avr_va += deviceData.avr_va
					standData.min_va += deviceData.min_va
					standData.max_va += deviceData.max_va

					collections.messages.save(deviceData, (err, result) => {
						if (err) return console.log(err)
					})
				})

				collections.messages.save(standData, (err, result) => {
					if (err) return console.log(err)
				})
			})
		})
	})
}

const randomNum = (min, max) => {
	return Math.floor(Math.random() * (max - min)) + min
}

generate()<commit_msg>added getting messages for devices<commit_after>require('dotenv').config()
const express = require('express')
const app = require('express')()
const bodyParser = require('body-parser')
const port = 1337

const MongoClient = require("mongodb").MongoClient
const MONGODB_URI = process.env.MONGODB_URI
const collections = {}

MongoClient.connect(MONGODB_URI, (err, database) => {
	if (err) return console.log(err)
	db = database
	collections.generators = db.collection('generators')
	collections.stands = db.collection('stands')
	collections.devices = db.collection('devices')
	collections.messages = db.collection('messages')
	collections.settings = db.collection('settings')
})

app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
	extended: true
}))

app
	.set('view engine', 'pug')
	.use(express.static('public'))
	.listen(process.env.PORT || port, () => {
		console.log('api server on http://localhost:' + port)
	})

app.get('/api/v1/settings', (req, res) => {
	collections.settings.findOne({}, function(err, setting) {
		res.render('components/settings', {
			setting
		})
	})
})

app.post('/api/v1/settings', (req, res) => {
	const multiplier = req.body.multiplier

	const data = {
		multiplier: multiplier
	}

	collections.settings.findOne({}, function(err, setting) {
		if (setting == null) {
			collections.settings.save(data, (err, result) => {
				if (err) return console.log(err)
			})
		} else {
			collections.settings.updateOne(setting, {
				$set: data
			}, (error, result) => {
				if (err) return console.log(err)
			})

		}
		res.redirect('/api/v1/settings')
	})
})

app.get('/api/v1/reset', (req, res) => {
	const updateData = {
		multiplier: 0,
		created_at: Date.now()
	}

	collections.settings.findOne({}, function(err, setting) {
		collections.settings.updateOne(setting, {
			$set: updateData
		}, (error, result) => {
			if (err) return console.log(err)
			console.info('Settings reset!')
			res.redirect('/api/v1/settings')
		})
	})

})

app.get('/api/v1/init/generator/:generator', (req, res) => {
	const generator = req.params.generator
	initGenerator(generator)
})

app.get('/api/v1/init/generator/:generator/stand/:stand', (req, res) => {
	const generator = req.params.generator
	const stand = req.params.stand
	initStand(generator, stand)
})

app.get('/api/v1/init/stand/:stand/device/:device', (req, res) => {
	const stand = req.params.stand
	const device = req.params.device
	initDevice(stand, device)
})

app.get('/api/v1/generator/:generator', (req, res) => {
	const generator = req.params.generator

	collections.generators.findOne({
		name: generator
	}, (err, generator) => {
		if (err) return console.log(err)
		collections.stands.find({
			"generator": generator._id
		}, {}).toArray(function(err, stands) {
			const response = {}
			response.generatorId = generator._id
			response.generatorName = generator.name
			response.stands = stands
			response.timestamp = Date.now()

			res.json(JSON.stringify(response))
		})
	})
})

app.get('/api/v1/stand/:stand', (req, res) => {
	const stand = req.params.stand

	collections.stands.findOne({
		name: stand
	}, (err, stand) => {
		if (err) return console.log(err)
		res.json(JSON.stringify(stand))
	})
})

app.get('/api/v1/device/:device/messages', (req, res) => {
	const device = req.params.device
	let quantity = parseInt(req.query.q)

	// check if quantity is given, otherwise return all messages
	if (quantity == NaN) {
		quantity = ''
	}

	collections.devices.findOne({
		name: device
	}, (err, device) => {
		if (err) return console.log(err)
		collections.messages.find({
			"device": device.name,
			"type": 'device'
		}, {}).limit(quantity).sort({
			$natural: -1
		}).toArray(function(err, messages) {
			const response = {}
			response.generatorId = messages[0].generator
			response.deviceId = device._id
			response.deviceName = device.name
			response.messages = messages
			response.timestamp = Date.now()

			res.json(response)
		})
	})
})

app.get('/api/v1/stand/:stand/messages', (req, res) => {
	const stand = req.params.stand
	let quantity = parseInt(req.query.q)

	// check if quantity is given, otherwise return all messages
	if (quantity == NaN) {
		quantity = ''
	}

	collections.stands.findOne({
		name: stand
	}, (err, stand) => {
		if (err) return console.log(err)
		collections.messages.find({
			"stand": stand.name,
			"type": 'stand'
		}, {}).limit(quantity).sort({
			$natural: -1
		}).toArray(function(err, messages) {

			console.log(messages)
			const response = {}
			response.generatorId = messages[0].generator
			response.standId = stand._id
			response.standName = stand.name
			response.messages = messages
			response.timestamp = Date.now()

			res.json(response)
		})
	})
})

app.get('/api/v1/generator/:generator/messages', (req, res) => {
	const generator = req.params.generator
	let quantity = parseInt(req.query.q)

	// check if quantity is given, otherwise return all messages
	if (quantity == NaN) {
		quantity = ''
	}

	collections.generators.findOne({
		name: generator
	}, (err, generator) => {
		if (err) return console.log(err)
		collections.messages.find({
			"generator": generator._id
		}, {}).limit(quantity).sort({
			$natural: -1
		}).toArray(function(err, messages) {
			const response = {}
			response.generatorId = generator._id
			response.standName = generator.name
			response.messages = messages
			response.timestamp = Date.now()

			res.json(response)
		})
	})
})

const generate = () => {
	setInterval(function() {
		generateMessages()
	}, 1000)
}

const initGenerator = (generator) => {
	const data = {
		name: generator,
		created_at: Date.now()
	}

	collections.generators.save(data, (err, result) => {
		if (err) return console.log(err)
		console.info('Created generator called `' + data.name + '`')

	})
}

const initStand = (generator, stand) => {
	collections.generators.findOne({
		name: generator
	}, (err, generator) => {
		if (err) return console.log(err)
		const data = {
			name: stand,
			generator: generator._id,
			devices: [],
			created_at: Date.now()
		}

		collections.stands.save(data, (err, result) => {
			if (err) return console.log(err)
			console.info('Created stand called `' + data.name + '` that is connected to generator `' + generator.name + '`')
		})
	})
}

const initDevice = (stand, device) => {
	collections.stands.findOne({
		name: stand
	}, (err, stand) => {
		if (err) return console.log(err)
		const data = {
			name: device,
			stand: stand._id,
			created_at: Date.now()
		}

		collections.devices.save(data, (err, result) => {
			if (err) return console.log(err)
			console.info('Created device called `' + data.name + '` that is connected to stand `' + stand.name + '`')
		})

		const updateData = {}

		if (stand.devices == undefined) {
			updateData.devices = [data]
		} else {
			const devicesArr = stand.devices
			devicesArr.push(data)
			updateData.devices = devicesArr
		}

		collections.stands.findOne({
			_id: stand._id
		}, function(err, stand) {
			collections.stands.updateOne(stand, {
				$set: updateData
			}, (error, result) => {
				if (err) return console.log(err)
			})
		});

	})

}

const generateMessages = () => {
	console.log("generating")
	// return

	collections.stands.find({}, {}).toArray(function(err, stands) {
		stands.forEach((stand) => {
			let multiplier = 0
			collections.settings.findOne({}, function(err, setting) {
				if (err) return console.log(err)
				multiplier = setting.multiplier

				const standData = {
					type: 'stand',
					stand: stand.name,
					timestamp: Date.now(),
					avr_va: 0,
					min_va: 0,
					max_va: 0

				}
				stand.devices.forEach((device) => {
					const deviceData = {
						type: 'device',
						device: device.name,
						stand: device.stand,
						timestamp: Date.now(),
						avr_va: randomNum(905 * multiplier, 906 * multiplier),
						min_va: randomNum(865 * multiplier, 867 * multiplier),
						max_va: randomNum(954 * multiplier, 956 * multiplier)
					}

					standData.avr_va += deviceData.avr_va
					standData.min_va += deviceData.min_va
					standData.max_va += deviceData.max_va

					collections.messages.save(deviceData, (err, result) => {
						if (err) return console.log(err)
					})
				})

				collections.messages.save(standData, (err, result) => {
					if (err) return console.log(err)
				})
			})
		})
	})
}

const randomNum = (min, max) => {
	return Math.floor(Math.random() * (max - min)) + min
}

// generate()<|endoftext|>


<commit_before>'use strict';

// Modules
const _ = require('lodash');
const fs = require('fs');
const parse = require('csv-parse');
const crypto = require('crypto');

// Class
module.exports = class Submissions {

    constructor(params) {
        this.hashes = {};
        this.params = params;

        this.collect();
    }

    collect() {
        let submissions = {};

        const parser = parse({
            columns: true,
        });

        parser.on('finish', () => {
            this.hashes = _.values(submissions);

            console.log('Unique submission hashes: ' + this.hashes.length);

            this.params.callback();
        });

        parser.on('readable', () => {
            for (let row; row = parser.read();) {
                const email = row.email.trim().toUpperCase();
                const hash = crypto.createHash('md5').update(email).digest('hex');
                let submission = submissions[hash];

                if (!submission) {
                    submission = submissions[hash] = {
                        hash: hash,
                        row: row,
                        sources: {},
                    };
                }

                submission.sources[row.source] = true;

                delete row.created_at;
                delete row.source;
            }
        });

        fs.createReadStream(this.params.path).pipe(parser);
    }

}
<commit_msg>Saving creation date of submissions for later<commit_after>'use strict';

// Modules
const _ = require('lodash');
const fs = require('fs');
const parse = require('csv-parse');
const crypto = require('crypto');

// Class
module.exports = class Submissions {

    constructor(params) {
        this.hashes = {};
        this.params = params;

        this.collect();
    }

    collect() {
        let submissions = {};

        const parser = parse({
            columns: true,
        });

        parser.on('finish', () => {
            this.hashes = _.values(submissions);

            console.log('Unique submission hashes: ' + this.hashes.length);

            this.params.callback();
        });

        parser.on('readable', () => {
            for (let row; row = parser.read();) {
                const email = row.email.trim().toUpperCase();
                const hash = crypto.createHash('md5').update(email).digest('hex');
                let submission = submissions[hash];

                if (!submission) {
                    submission = submissions[hash] = {
                        hash: hash,
                        row: row,
                        sources: {},
                    };
                }

                submission.created = new Date(row.created_at);
                submission.sources[row.source] = true;

                delete row.created_at;
                delete row.source;
            }
        });

        fs.createReadStream(this.params.path).pipe(parser);
    }

}
<|endoftext|>