<commit_before>// Copyright (c) 2012 Titanium I.T. LLC. All rights reserved. See LICENSE.txt for details.
/*global desc, task, file, jake, rule, fail, complete, directory*/

(function() {
	"use strict";

	var startTime = Date.now();

	if (!process.env.loose) console.log("For more forgiving test settings, use 'loose=true'");

	var REQUIRED_BROWSERS = [
		"IE 8.0.0 (Windows 7)",
		"IE 9.0.0 (Windows 7)",
		"Firefox 35.0.0 (Mac OS X 10.10)",
		"Chrome 40.0.2214 (Mac OS X 10.10.2)",
		"Safari 8.0.3 (Mac OS X 10.10.2)",
		"Mobile Safari 7.0.0 (iOS 7.1)"
	];

	var GENERATED_DIR = "generated";
	var TEMP_TESTFILE_DIR = GENERATED_DIR + "/test";
	var BUILD_DIR = GENERATED_DIR + "/build";
	var BUILD_CLIENT_DIR = BUILD_DIR + "/client";

	directory(TEMP_TESTFILE_DIR);
	directory(BUILD_DIR);
	directory(BUILD_CLIENT_DIR);

	desc("Delete all generated files");
	task("clean", [], function() {
		jake.rmRf(GENERATED_DIR);
	});

	desc("Build and test");
	task("default", [ "lint", "test" ], function() {
		buildOk();
	});

	desc("Build and test fast targets only");
	task("quick", [ "lint", "testFast" ], function() {
		buildOk();
	});

	desc("Start Karma server for testing");
	task("karma", function() {
		karma().serve("build/karma.conf.js", complete, fail);
	}, {async: true});

	desc("Start WeeWikiPaint server for manual testing");
	task("run", [ "build" ], function() {
		var runServer = require("./src/_run_server.js");

		console.log("Running server. Press Ctrl-C to stop.");
		runServer.runInteractively();
		// We never call complete() because we want the task to hang until the user presses 'Ctrl-C'.
	}, {async: true});

	desc("Lint everything");
	task("lint", [ "lintNode", "lintClient" ]);

	task("lintNode", [ "nodeVersion" ], function() {
		var passed = lint().validateFileList(nodeLintFiles(), nodeLintOptions(), {});
		if (!passed) fail("Lint failed");
	});

	task("lintClient", function() {
		var passed = lint().validateFileList(clientLintFiles(), clientLintOptions(), clientGlobals());
		if (!passed) fail("Lint failed");
	});

	function logTime(starttime, desc) {
		var elapsedSeconds = (Date.now() - starttime) / 1000;
		console.log(desc + ": " + elapsedSeconds.toFixed(2) + "s");
	}

var pathTime = Date.now();
	var path = require("path");
	var lintRunner = lint();
logTime(pathTime, "require");

	task("lintspike2", function() {
		var fileTime = Date.now();
			var files = parallelNodeLintFiles(function(files) {
				logTime(fileTime, "determine files");

				jake.Task["lintspike"].invoke();
				complete();
			});

	}, { async: true });

var files = nodeLintFiles();

var createTaskTime = Date.now();
	task("lintspike", [ "generated/lint", "generated/lint/src", "generated/lint/build" ]);
	files.forEach(function(jsFile) {
		var lintFile = "generated/lint/" + jsFile.replace(/\.js$/, ".lint");
		var lintDirectory = path.dirname(lintFile);

		task("lintspike", [ lintDirectory, lintFile ]);
		directory(lintDirectory);
	});

	function lintSourceFile(name) {
		var result = name.replace(/^generated\/lint\//, "");
		return result.replace(/\.lint$/, ".js");
	}

	rule(".lint", lintSourceFile, function() {
		var fs = require("fs");

		var passed = lint().validateFile(this.source, nodeLintOptions(), {});
		if (passed) fs.writeFileSync(this.name, "lint ok");
		else fail("Lint failed");
	});

	directory("generated/lint");
	directory("generated/lint/src");
	directory("generated/lint/build");
logTime(createTaskTime, "create tasks");

var taskTime = Date.now();
task("lintspike", function() {
	var elapsedSeconds = (Date.now() - taskTime) / 1000;
	console.log("run tasks: " + elapsedSeconds.toFixed(2) + "s");
});

	function parallelNodeLintFiles(callback) {
		var javascriptFiles = new jake.FileList();
		javascriptFiles.include("*.js");
		javascriptFiles.include("build/util/*.js");
		javascriptFiles.include("src/server/**/*.js");
		javascriptFiles.include("src/*.js");

		callback(null, javascriptFiles.toArray());
		return javascriptFiles.toArray();
	}

	desc("Test everything");
	task("test", [ "testFast", "testSlow" ]);

	task("testFast", [ "testServer", "testClient" ]);

	task("testSlow", [ "testSmoke" ]);

	desc("Test server code");
	task("testServer", [ "nodeVersion", TEMP_TESTFILE_DIR ], function() {
		nodeunit().runTests(serverTestFiles(), complete, fail);
	}, {async: true});

	desc("Test client code");
	task("testClient", [], function() {
		karma().runTests(REQUIRED_BROWSERS, complete, fail);
	}, {async: true});

	desc("End-to-end smoke tests");
	task("testSmoke", [ "build" ], function() {
		nodeunit().runTests(smokeTestFiles(), complete, fail);
	}, {async: true});

	desc("Bundle and build code");
	task("build", [ BUILD_CLIENT_DIR ], function() {
		var fs = require("fs");
		var shell = require("shelljs");
		var browserify = require("browserify");

		shell.rm("-rf", BUILD_CLIENT_DIR + "/*");
		shell.cp(
			"-R",
			"src/client/*.html", "src/client/*.css", "src/client/images", "src/client/vendor",
			BUILD_CLIENT_DIR
		);

		console.log("Bundling client files with Browserify...");
		var b = browserify({ debug: true });
		b.require("./src/client/client.js", {expose: "./client.js"} );
		b.require("./src/client/html_element.js", {expose: "./html_element.js"} );
		b.bundle(function(err, bundle) {
			if (err) fail(err);
			fs.writeFileSync(BUILD_CLIENT_DIR + "/bundle.js", bundle);
			complete();
		});
	}, {async: true});

	desc("Deploy to Heroku");
	task("deploy", function() {
		console.log("To deploy to production:");
		console.log("1. Integrate ('jake integrate')");

		// Correction: Use "git push heroku integration:master" to deploy from integration branch.
		// Thanks to Jüri A, http://www.letscodejavascript.com/v3/comments/live/32#comment-798947003 .
		console.log("2. 'git push heroku integration:master' (or 'git push staging integration:master')");
		console.log("3. 'jake test'");
		console.log();
		console.log("To deploy latest code to staging server:");
		console.log("1. Make sure 'git status' is clean.");
		console.log("2. 'git push staging master");
		console.log("3. Visit http://wwp-staging.herokuapp.com/");
	});

//	desc("Ensure correct version of Node is present.");
	task("nodeVersion", [], function() {
		var versionChecker = require("./build/util/version_checker.js");

		var deployedVersion = "v" + require("./package.json").engines.node;
		versionChecker.check("Node", !process.env.loose, deployedVersion, process.version, fail);
	});

	desc("Integration checklist");
	task("integrate", [ "default" ], function() {
		console.log("1. Make sure 'git status' is clean.");
		console.log("2. Build on the integration box.");
		console.log("   a. Walk over to integration box.");
		console.log("   b. 'git pull'");
		console.log("   c. 'npm rebuild'");
		console.log("   d. Check status for files that need to be .gitignore'd");
		console.log("   e. 'jake'");
		console.log("   f. If jake fails, stop! Try again after fixing the issue.");
		console.log("3. 'git checkout integration'");
		console.log("4. 'git merge master --no-ff --log'");
		console.log("5. 'git checkout master'");
	});

	desc("End-of-episode checklist");
	task("episode", [], function() {
		console.log("1. Save recording.");
		console.log("2. Double-check sound and framing.");
		console.log("3. Commit source code.");
		console.log("4. Check Windows compatibility");
		console.log("   a. Switch to Windows VM");
		console.log("   b. 'git pull'");
		console.log("   c. 'npm rebuild'");
		console.log("   d. Check status for files that need to be .gitignore'd");
		console.log("   e. 'jake'");
		console.log("5. Tag episode: 'git tag -a episodeXX -m \"End of episode XX\"'");
	});

	function serverTestFiles() {
		var testFiles = new jake.FileList();
		testFiles.include("src/server/**/_*_test.js");
		testFiles = testFiles.toArray();
		return testFiles;
	}

	function smokeTestFiles() {
		var testFiles = new jake.FileList();
		testFiles.include("src/_*_test.js");
		testFiles = testFiles.toArray();
		return testFiles;
	}

	function nodeLintFiles() {
		var javascriptFiles = new jake.FileList();
		javascriptFiles.include("*.js");
		javascriptFiles.include("build/util/*.js");
		javascriptFiles.include("src/server/**/*.js");
		javascriptFiles.include("src/*.js");
		return javascriptFiles.toArray();
	}

	function clientLintFiles() {
		var javascriptFiles = new jake.FileList();
		javascriptFiles.include("src/client/*.js");
		return javascriptFiles.toArray();
	}

	function nodeLintOptions() {
		var options = sharedLintOptions();
		options.node = true;
		return options;
	}

	function clientLintOptions() {
		var options = sharedLintOptions();
		options.browser = true;
		return options;
	}

	function sharedLintOptions() {
		return {
			bitwise: true,
			curly: false,
			eqeqeq: true,
			forin: true,
			immed: true,
			latedef: false,
			newcap: true,
			noarg: true,
			noempty: true,
			nonew: true,
			regexp: true,
			undef: true,
			strict: true,
			trailing: true
		};
	}

	function clientGlobals() {
		return {
			// Browserify
			require: false,
			module: false,
			exports: false,

			// Mocha / expect.js
			describe: false,
			it: false,
			expect: false,
			dump: false,
			beforeEach: false,
			afterEach: false,
			before: false,
			after: false,

			// Browser
			console: false
		};
	}

	function buildOk() {
		var elapsedSeconds = (Date.now() - startTime) / 1000;
		console.log("\n\nBUILD OK (" + elapsedSeconds.toFixed(2) + "s)");
	}

	// We've factored our require statements into functions so we don't have the overhead of loading
	// modules we don't need. At the time this refactoring was done, module loading took about half a
	// second, which was 10% of our desired maximum of five seconds for a quick build.

	function lint() {
		return require("./build/util/lint_runner.js");
	}

	function nodeunit() {
		return require("./build/util/nodeunit_runner.js");
	}

	function karma() {
		return require("./build/util/karma_runner.js");
	}

}());
<commit_msg>Lintspike actually lints again (profiling introduced bug)<commit_after>// Copyright (c) 2012 Titanium I.T. LLC. All rights reserved. See LICENSE.txt for details.
/*global desc, task, file, jake, rule, fail, complete, directory*/

(function() {
	"use strict";

	var startTime = Date.now();

	if (!process.env.loose) console.log("For more forgiving test settings, use 'loose=true'");

	var REQUIRED_BROWSERS = [
		"IE 8.0.0 (Windows 7)",
		"IE 9.0.0 (Windows 7)",
		"Firefox 35.0.0 (Mac OS X 10.10)",
		"Chrome 40.0.2214 (Mac OS X 10.10.2)",
		"Safari 8.0.3 (Mac OS X 10.10.2)",
		"Mobile Safari 7.0.0 (iOS 7.1)"
	];

	var GENERATED_DIR = "generated";
	var TEMP_TESTFILE_DIR = GENERATED_DIR + "/test";
	var BUILD_DIR = GENERATED_DIR + "/build";
	var BUILD_CLIENT_DIR = BUILD_DIR + "/client";

	directory(TEMP_TESTFILE_DIR);
	directory(BUILD_DIR);
	directory(BUILD_CLIENT_DIR);

	desc("Delete all generated files");
	task("clean", [], function() {
		jake.rmRf(GENERATED_DIR);
	});

	desc("Build and test");
	task("default", [ "lint", "test" ], function() {
		buildOk();
	});

	desc("Build and test fast targets only");
	task("quick", [ "lint", "testFast" ], function() {
		buildOk();
	});

	desc("Start Karma server for testing");
	task("karma", function() {
		karma().serve("build/karma.conf.js", complete, fail);
	}, {async: true});

	desc("Start WeeWikiPaint server for manual testing");
	task("run", [ "build" ], function() {
		var runServer = require("./src/_run_server.js");

		console.log("Running server. Press Ctrl-C to stop.");
		runServer.runInteractively();
		// We never call complete() because we want the task to hang until the user presses 'Ctrl-C'.
	}, {async: true});

	desc("Lint everything");
	task("lint", [ "lintNode", "lintClient" ]);

	task("lintNode", [ "nodeVersion" ], function() {
		var passed = lint().validateFileList(nodeLintFiles(), nodeLintOptions(), {});
		if (!passed) fail("Lint failed");
	});

	task("lintClient", function() {
		var passed = lint().validateFileList(clientLintFiles(), clientLintOptions(), clientGlobals());
		if (!passed) fail("Lint failed");
	});

	function logTime(starttime, desc) {
		var elapsedSeconds = (Date.now() - starttime) / 1000;
		console.log(desc + ": " + elapsedSeconds.toFixed(2) + "s");
	}

var pathTime = Date.now();
	var path = require("path");
	var lintRunner = lint();
logTime(pathTime, "require");

	task("lintspike2", function() {
		var fileTime = Date.now();
			var files = parallelNodeLintFiles(function(files) {
				logTime(fileTime, "determine files");

				jake.Task.lintspike.invoke();
				complete();
			});

	}, { async: true });

var files = nodeLintFiles();

var createTaskTime = Date.now();
	task("lintspike", [ "generated/lint", "generated/lint/src", "generated/lint/build" ], function() {
		var elapsedSeconds = (Date.now() - taskTime) / 1000;
		console.log("run tasks: " + elapsedSeconds.toFixed(2) + "s");
	});
	files.forEach(function(jsFile) {
		var lintFile = "generated/lint/" + jsFile.replace(/\.js$/, ".lint");
		var lintDirectory = path.dirname(lintFile);

		task("lintspike", [ lintDirectory, lintFile ]);
		directory(lintDirectory);
	});

	function lintSourceFile(name) {
		var result = name.replace(/^generated\/lint\//, "");
		return result.replace(/\.lint$/, ".js");
	}

	rule(".lint", lintSourceFile, function() {
		var fs = require("fs");

		var passed = lint().validateFile(this.source, nodeLintOptions(), {});
		if (passed) fs.writeFileSync(this.name, "lint ok");
		else fail("Lint failed");
	});

	directory("generated/lint");
	directory("generated/lint/src");
	directory("generated/lint/build");
logTime(createTaskTime, "create tasks");

var taskTime = Date.now();

	function parallelNodeLintFiles(callback) {
		var javascriptFiles = new jake.FileList();
		javascriptFiles.include("*.js");
		javascriptFiles.include("build/util/*.js");
		javascriptFiles.include("src/server/**/*.js");
		javascriptFiles.include("src/*.js");

		callback(null, javascriptFiles.toArray());
		return javascriptFiles.toArray();
	}

	desc("Test everything");
	task("test", [ "testFast", "testSlow" ]);

	task("testFast", [ "testServer", "testClient" ]);

	task("testSlow", [ "testSmoke" ]);

	desc("Test server code");
	task("testServer", [ "nodeVersion", TEMP_TESTFILE_DIR ], function() {
		nodeunit().runTests(serverTestFiles(), complete, fail);
	}, {async: true});

	desc("Test client code");
	task("testClient", [], function() {
		karma().runTests(REQUIRED_BROWSERS, complete, fail);
	}, {async: true});

	desc("End-to-end smoke tests");
	task("testSmoke", [ "build" ], function() {
		nodeunit().runTests(smokeTestFiles(), complete, fail);
	}, {async: true});

	desc("Bundle and build code");
	task("build", [ BUILD_CLIENT_DIR ], function() {
		var fs = require("fs");
		var shell = require("shelljs");
		var browserify = require("browserify");

		shell.rm("-rf", BUILD_CLIENT_DIR + "/*");
		shell.cp(
			"-R",
			"src/client/*.html", "src/client/*.css", "src/client/images", "src/client/vendor",
			BUILD_CLIENT_DIR
		);

		console.log("Bundling client files with Browserify...");
		var b = browserify({ debug: true });
		b.require("./src/client/client.js", {expose: "./client.js"} );
		b.require("./src/client/html_element.js", {expose: "./html_element.js"} );
		b.bundle(function(err, bundle) {
			if (err) fail(err);
			fs.writeFileSync(BUILD_CLIENT_DIR + "/bundle.js", bundle);
			complete();
		});
	}, {async: true});

	desc("Deploy to Heroku");
	task("deploy", function() {
		console.log("To deploy to production:");
		console.log("1. Integrate ('jake integrate')");

		// Correction: Use "git push heroku integration:master" to deploy from integration branch.
		// Thanks to Jüri A, http://www.letscodejavascript.com/v3/comments/live/32#comment-798947003 .
		console.log("2. 'git push heroku integration:master' (or 'git push staging integration:master')");
		console.log("3. 'jake test'");
		console.log();
		console.log("To deploy latest code to staging server:");
		console.log("1. Make sure 'git status' is clean.");
		console.log("2. 'git push staging master");
		console.log("3. Visit http://wwp-staging.herokuapp.com/");
	});

//	desc("Ensure correct version of Node is present.");
	task("nodeVersion", [], function() {
		var versionChecker = require("./build/util/version_checker.js");

		var deployedVersion = "v" + require("./package.json").engines.node;
		versionChecker.check("Node", !process.env.loose, deployedVersion, process.version, fail);
	});

	desc("Integration checklist");
	task("integrate", [ "default" ], function() {
		console.log("1. Make sure 'git status' is clean.");
		console.log("2. Build on the integration box.");
		console.log("   a. Walk over to integration box.");
		console.log("   b. 'git pull'");
		console.log("   c. 'npm rebuild'");
		console.log("   d. Check status for files that need to be .gitignore'd");
		console.log("   e. 'jake'");
		console.log("   f. If jake fails, stop! Try again after fixing the issue.");
		console.log("3. 'git checkout integration'");
		console.log("4. 'git merge master --no-ff --log'");
		console.log("5. 'git checkout master'");
	});

	desc("End-of-episode checklist");
	task("episode", [], function() {
		console.log("1. Save recording.");
		console.log("2. Double-check sound and framing.");
		console.log("3. Commit source code.");
		console.log("4. Check Windows compatibility");
		console.log("   a. Switch to Windows VM");
		console.log("   b. 'git pull'");
		console.log("   c. 'npm rebuild'");
		console.log("   d. Check status for files that need to be .gitignore'd");
		console.log("   e. 'jake'");
		console.log("5. Tag episode: 'git tag -a episodeXX -m \"End of episode XX\"'");
	});

	function serverTestFiles() {
		var testFiles = new jake.FileList();
		testFiles.include("src/server/**/_*_test.js");
		testFiles = testFiles.toArray();
		return testFiles;
	}

	function smokeTestFiles() {
		var testFiles = new jake.FileList();
		testFiles.include("src/_*_test.js");
		testFiles = testFiles.toArray();
		return testFiles;
	}

	function nodeLintFiles() {
		var javascriptFiles = new jake.FileList();
		javascriptFiles.include("*.js");
		javascriptFiles.include("build/util/*.js");
		javascriptFiles.include("src/server/**/*.js");
		javascriptFiles.include("src/*.js");
		return javascriptFiles.toArray();
	}

	function clientLintFiles() {
		var javascriptFiles = new jake.FileList();
		javascriptFiles.include("src/client/*.js");
		return javascriptFiles.toArray();
	}

	function nodeLintOptions() {
		var options = sharedLintOptions();
		options.node = true;
		return options;
	}

	function clientLintOptions() {
		var options = sharedLintOptions();
		options.browser = true;
		return options;
	}

	function sharedLintOptions() {
		return {
			bitwise: true,
			curly: false,
			eqeqeq: true,
			forin: true,
			immed: true,
			latedef: false,
			newcap: true,
			noarg: true,
			noempty: true,
			nonew: true,
			regexp: true,
			undef: true,
			strict: true,
			trailing: true
		};
	}

	function clientGlobals() {
		return {
			// Browserify
			require: false,
			module: false,
			exports: false,

			// Mocha / expect.js
			describe: false,
			it: false,
			expect: false,
			dump: false,
			beforeEach: false,
			afterEach: false,
			before: false,
			after: false,

			// Browser
			console: false
		};
	}

	function buildOk() {
		var elapsedSeconds = (Date.now() - startTime) / 1000;
		console.log("\n\nBUILD OK (" + elapsedSeconds.toFixed(2) + "s)");
	}

	// We've factored our require statements into functions so we don't have the overhead of loading
	// modules we don't need. At the time this refactoring was done, module loading took about half a
	// second, which was 10% of our desired maximum of five seconds for a quick build.

	function lint() {
		return require("./build/util/lint_runner.js");
	}

	function nodeunit() {
		return require("./build/util/nodeunit_runner.js");
	}

	function karma() {
		return require("./build/util/karma_runner.js");
	}

}());
<|endoftext|>


<commit_before>// Copyright 2016 The Closure Library Authors. All Rights Reserved.
//
// 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.

/**
 * @fileoverview A utility for wrapping a JSTD test object so that any test
 * methods are receive a queue that is compatible with JSTD but supports the
 * JsUnit async API of returning a promise in the test method.
 *
 * To convert a JSTD object call convertToAsyncTestObj on it and run with the
 * JsUnit test runner.
 */

goog.provide('goog.testing.JsTdAsyncWrapper');

goog.require('goog.Promise');

/**
 * @param {Function|string} callback
 * @param {number=} opt_delay
 * @param {...*} var_args
 * @return {number}
 * @private
 */
goog.testing.JsTdAsyncWrapper.REAL_SET_TIMEOUT_FN_ = goog.global.setTimeout;

/**
 * Calls a function after a specified timeout. This uses the original setTimeout
 * to be resilient to tests that override it.
 * @param {Function} fn The function to call.
 * @param {number} timeout Timeout time in ms.
 * @private
 */
goog.testing.JsTdAsyncWrapper.REAL_SET_TIMEOUT_ = function(fn, timeout) {
  // Setting timeout into a variable is necessary to invoke the function in the
  // default global context. Inlining breaks chrome since it requires setTimeout
  // to be called with the global context, and IE8 doesn't support the call
  // method on setTimeout.
  var setTimeoutFn = goog.testing.JsTdAsyncWrapper.REAL_SET_TIMEOUT_FN_;
  setTimeoutFn(fn, timeout);
};

/**
 * Wraps an object's methods by passing in a Queue that is based on the JSTD
 * async API. The queue exposes a promise that resolves when the queue
 * completes. This promise can be used in JsUnit tests.
 * @param {!Object} original The original JSTD test object. The object should
 *     contain methods such as testXyz or setUp.
 * @return {!Object} A object that has all test methods wrapped in a fake
 *     testing queue.
 */
goog.testing.JsTdAsyncWrapper.convertToAsyncTestObj = function(original) {
  // Wraps a call to a test function and passes an instance of a fake queue
  // into the test function.
  var queueWrapperFn = function(fn) {
    return function() {
      var queue = new goog.testing.JsTdAsyncWrapper.Queue(this);
      fn.call(this, queue);
      return queue.startExecuting();
    };
  };

  var newTestObj = {};
  for (var prop in original) {
    // If this is a test or tearDown/setUp method wrap the method with a queue
    if (prop.indexOf('test') == 0 || prop == 'setUp' || prop == 'tearDown') {
      newTestObj[prop] = queueWrapperFn(original[prop]);
    } else {
      newTestObj[prop] = original[prop];
    }
  }
  return newTestObj;
};

/**
 * A queue that mirrors the JSTD Async Queue api but exposes a promise that
 * resolves once the queue is complete for compatibility with JsUnit.
 * @param {!Object} testObj The test object containing all test methods. This
 *     object is passed into queue callbacks as the "this" object.
 * @constructor
 * @final
 */
goog.testing.JsTdAsyncWrapper.Queue = function(testObj) {
  /**
   * The queue steps.
   * @private {!Array<!goog.testing.JsTdAsyncWrapper.Step_>}
   */
  this.steps_ = [];

  /**
   * A delegate that is used within a defer call.
   * @private {?goog.testing.JsTdAsyncWrapper.Queue}
   */
  this.delegate_ = null;

  /**
   * thisArg that should be used by default for addCallback function calls.
   * @private {!Object}
   */
  this.testObj_ = testObj;
};

/**
 * @param {string|function(!goog.testing.JsTdAsyncWrapper.Pool_=)} stepName
 *     The name of the current testing step, or the fn parameter if
 *     no stepName is desired.
 * @param {function(!goog.testing.JsTdAsyncWrapper.Pool_=)=} opt_fn A function
 *   that will be called.
 */
goog.testing.JsTdAsyncWrapper.Queue.prototype.defer = function(
    stepName, opt_fn) {
  var fn = opt_fn;
  if (!opt_fn && typeof stepName == 'function') {
    fn = stepName;
    stepName = '(Not named)';
  }
  // If another queue.defer is called within a pool callback it should be
  // executed after the current one. Any defer that is called within a defer
  // will be passed to a delegate and the current defer waits till all delegate
  // defer are resolved.
  if (this.delegate_) {
    this.delegate_.defer(stepName, fn);
    return;
  }
  this.steps_.push(new goog.testing.JsTdAsyncWrapper.Step_(
      /** @type {string} */ (stepName),
      /** @type {function(!goog.testing.JsTdAsyncWrapper.Pool_=)} */ (fn)));
};

/**
 * Starts the execution.
 * @return {!goog.Promise<void>}
 */
goog.testing.JsTdAsyncWrapper.Queue.prototype.startExecuting = function() {
  return new goog.Promise(goog.bind(function(resolve, reject) {
    this.executeNextStep_(resolve, reject);
  }, this));
};

/**
 * Executes the next step on the queue waiting for all pool callbacks and then
 * starts executing any delegate queues before it finishes.
 * @param {function()} callback
 * @param {function(*)} errback
 * @private
 */
goog.testing.JsTdAsyncWrapper.Queue.prototype.executeNextStep_ = function(
    callback, errback) {
  // Note: From this point on, we can no longer use goog.Promise (which uses
  // the goog.async.run queue) because it conflicts with MockClock, and we can't
  // use the native Promise because it is not supported on IE. So we revert to
  // using callbacks and setTimeout.
  if (!this.steps_.length) {
    callback();
    return;
  }
  var step = this.steps_.shift();
  this.delegate_ = new goog.testing.JsTdAsyncWrapper.Queue(this.testObj_);
  var pool = new goog.testing.JsTdAsyncWrapper.Pool_(
      this.testObj_, goog.bind(function() {
        goog.testing.JsTdAsyncWrapper.REAL_SET_TIMEOUT_(goog.bind(function() {
          this.executeDelegate_(callback, errback);
        }, this), 0);
      }, this), goog.bind(function(reason) {
        this.handleError_(errback, reason, step.name);
      }, this));
  try {
    step.fn.call(this.testObj_, pool);
  } catch (e) {
    this.handleError_(errback, e, step.name);
  }
  pool.maybeComplete();
};

/**
 * Execute the delegate queue.
 * @param {function()} callback
 * @param {function(*)} errback
 * @private
 */
goog.testing.JsTdAsyncWrapper.Queue.prototype.executeDelegate_ = function(
    callback, errback) {
  // Wait till the delegate queue completes before moving on to the
  // next step.
  if (!this.delegate_) {
    this.executeNextStep_(callback, errback);
    return;
  }
  this.delegate_.executeNextStep_(goog.bind(function() {
    this.delegate_ = null;
    goog.testing.JsTdAsyncWrapper.REAL_SET_TIMEOUT_(goog.bind(function() {
      this.executeNextStep_(callback, errback);
    }, this), 0);
  }, this), errback);
};

/**
 * @param {function(*)} errback
 * @param {*} reason
 * @param {string} stepName
 * @private
 */
goog.testing.JsTdAsyncWrapper.Queue.prototype.handleError_ = function(
    errback, reason, stepName) {
  var error = reason instanceof Error ? reason : Error(reason);
  error.message = 'In step ' + stepName + ', error: ' + error.message;
  errback(reason);
};

/**
 * A step to be executed.
 * @param {string} name
 * @param {function(!goog.testing.JsTdAsyncWrapper.Pool_=)} fn
 * @constructor
 * @private
 */
goog.testing.JsTdAsyncWrapper.Step_ = function(name, fn) {
  /** @final {string} */
  this.name = name;
  /** @final {function(!goog.testing.JsTdAsyncWrapper.Pool_=)} */
  this.fn = fn;
};

/**
 * A fake pool that mimics the JSTD AsyncTestCase's pool object.
 * @param {!Object} testObj The test object containing all test methods. This
 *     object is passed into queue callbacks as the "this" object.
 * @param {function()} callback
 * @param {function(*)} errback
 * @constructor
 * @private
 * @final
 */
goog.testing.JsTdAsyncWrapper.Pool_ = function(testObj, callback, errback) {

  /** @private {number} */
  this.outstandingCallbacks_ = 0;

  /** @private {function()} */
  this.callback_ = callback;

  /** @private {function(*)} */
  this.errback_ = errback;

  /**
   * thisArg that should be used by default for defer function calls.
   * @private {!Object}
   */
  this.testObj_ = testObj;
};

/**
 * @return {function()}
 */
goog.testing.JsTdAsyncWrapper.Pool_.prototype.noop = function() {
  return this.addCallback(function() {});
};

/**
 * @param {function(...*):*} fn The function to add to the pool.
 * @param {?number=} opt_n The number of permitted uses of the given callback;
 *     defaults to one.
 * @param {?number=} opt_timeout The timeout in milliseconds.
 *     This is not supported in the adapter for now. Specifying this argument
 *     will result in a test failure.
 * @param {?string=} opt_description The callback description.
 * @return {function()}
 */
goog.testing.JsTdAsyncWrapper.Pool_.prototype.addCallback = function(
    fn, opt_n, opt_timeout, opt_description) {
  // TODO(mtragut): This could be fixed if required by test cases.
  if (opt_timeout || opt_description) {
    throw Error(
        'Setting timeout or description in a pool callback is not supported.');
  }
  var numCallbacks = opt_n || 1;
  this.outstandingCallbacks_ = this.outstandingCallbacks_ + numCallbacks;
  return goog.bind(function() {
    try {
      fn.apply(this.testObj_, arguments);
    } catch (e) {
      if (opt_description) {
        e.message = opt_description + e.message;
      }
      this.errback_(e);
    }
    this.outstandingCallbacks_ = this.outstandingCallbacks_ - 1;
    if (this.outstandingCallbacks_ == 0) {
      this.callback_();
    }
  }, this);
};

/**
 * @param {function(...*):*} fn The function to add to the pool.
 * @param {?number=} opt_n The number of permitted uses of the given callback;
 *     defaults to one.
 * @param {?number=} opt_timeout The timeout in milliseconds.
 *     This is not supported in the adapter for now. Specifying this argument
 *     will result in a test failure.
 * @param {?string=} opt_description The callback description.
 * @return {function()}
 */
goog.testing.JsTdAsyncWrapper.Pool_.prototype.add =
    goog.testing.JsTdAsyncWrapper.Pool_.prototype.addCallback;

/**
 * @param {string} msg The message to print if the error callback gets called.
 * @return {function()}
 */
goog.testing.JsTdAsyncWrapper.Pool_.prototype.addErrback = function(msg) {
  return goog.bind(function() {
    var errorMsg = msg;
    if (arguments.length) {
      errorMsg += ' - Error callback called with params: ( ';
      for (var i = 0; i < arguments.length; i++) {
        var arg = arguments[i];
        errorMsg += arg + ' ';
        if (arg instanceof Error) {
          errorMsg += '\n' + arg.stack + '\n';
        }
      }
      errorMsg += ')';
    }
    this.errback_(errorMsg);
  }, this);
};

/**
 * Completes the pool if there are no outstanding callbacks.
 */
goog.testing.JsTdAsyncWrapper.Pool_.prototype.maybeComplete = function() {
  if (this.outstandingCallbacks_ == 0) {
    this.callback_();
  }
};
<commit_msg>Make JsTdAsyncWrapper great again.  Fixes bug causing JsTdAsyncWrapper to play fast and loose with the definition of "synchronous".  Due to timing issues it is possible for the DeferredQueue to execute multiple steps simultaneously creating a situation in which later steps complete before earlier steps (and can cause tearDown to happen before steps finish).<commit_after>// Copyright 2016 The Closure Library Authors. All Rights Reserved.
//
// 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.

/**
 * @fileoverview A utility for wrapping a JSTD test object so that any test
 * methods are receive a queue that is compatible with JSTD but supports the
 * JsUnit async API of returning a promise in the test method.
 *
 * To convert a JSTD object call convertToAsyncTestObj on it and run with the
 * JsUnit test runner.
 */

goog.provide('goog.testing.JsTdAsyncWrapper');

goog.require('goog.Promise');

/**
 * @param {Function|string} callback
 * @param {number=} opt_delay
 * @param {...*} var_args
 * @return {number}
 * @private
 */
goog.testing.JsTdAsyncWrapper.REAL_SET_TIMEOUT_FN_ = goog.global.setTimeout;

/**
 * Calls a function after a specified timeout. This uses the original setTimeout
 * to be resilient to tests that override it.
 * @param {Function} fn The function to call.
 * @param {number} timeout Timeout time in ms.
 * @private
 */
goog.testing.JsTdAsyncWrapper.REAL_SET_TIMEOUT_ = function(fn, timeout) {
  // Setting timeout into a variable is necessary to invoke the function in the
  // default global context. Inlining breaks chrome since it requires setTimeout
  // to be called with the global context, and IE8 doesn't support the call
  // method on setTimeout.
  var setTimeoutFn = goog.testing.JsTdAsyncWrapper.REAL_SET_TIMEOUT_FN_;
  setTimeoutFn(fn, timeout);
};

/**
 * Wraps an object's methods by passing in a Queue that is based on the JSTD
 * async API. The queue exposes a promise that resolves when the queue
 * completes. This promise can be used in JsUnit tests.
 * @param {!Object} original The original JSTD test object. The object should
 *     contain methods such as testXyz or setUp.
 * @return {!Object} A object that has all test methods wrapped in a fake
 *     testing queue.
 */
goog.testing.JsTdAsyncWrapper.convertToAsyncTestObj = function(original) {
  // Wraps a call to a test function and passes an instance of a fake queue
  // into the test function.
  var queueWrapperFn = function(fn) {
    return function() {
      var queue = new goog.testing.JsTdAsyncWrapper.Queue(this);
      fn.call(this, queue);
      return queue.startExecuting();
    };
  };

  var newTestObj = {};
  for (var prop in original) {
    // If this is a test or tearDown/setUp method wrap the method with a queue
    if (prop.indexOf('test') == 0 || prop == 'setUp' || prop == 'tearDown') {
      newTestObj[prop] = queueWrapperFn(original[prop]);
    } else {
      newTestObj[prop] = original[prop];
    }
  }
  return newTestObj;
};

/**
 * A queue that mirrors the JSTD Async Queue api but exposes a promise that
 * resolves once the queue is complete for compatibility with JsUnit.
 * @param {!Object} testObj The test object containing all test methods. This
 *     object is passed into queue callbacks as the "this" object.
 * @constructor
 * @final
 */
goog.testing.JsTdAsyncWrapper.Queue = function(testObj) {
  /**
   * The queue steps.
   * @private {!Array<!goog.testing.JsTdAsyncWrapper.Step_>}
   */
  this.steps_ = [];

  /**
   * A delegate that is used within a defer call.
   * @private {?goog.testing.JsTdAsyncWrapper.Queue}
   */
  this.delegate_ = null;

  /**
   * thisArg that should be used by default for addCallback function calls.
   * @private {!Object}
   */
  this.testObj_ = testObj;
};

/**
 * @param {string|function(!goog.testing.JsTdAsyncWrapper.Pool_=)} stepName
 *     The name of the current testing step, or the fn parameter if
 *     no stepName is desired.
 * @param {function(!goog.testing.JsTdAsyncWrapper.Pool_=)=} opt_fn A function
 *   that will be called.
 */
goog.testing.JsTdAsyncWrapper.Queue.prototype.defer = function(
    stepName, opt_fn) {
  var fn = opt_fn;
  if (!opt_fn && typeof stepName == 'function') {
    fn = stepName;
    stepName = '(Not named)';
  }
  // If another queue.defer is called within a pool callback it should be
  // executed after the current one. Any defer that is called within a defer
  // will be passed to a delegate and the current defer waits till all delegate
  // defer are resolved.
  if (this.delegate_) {
    this.delegate_.defer(stepName, fn);
    return;
  }
  this.steps_.push(new goog.testing.JsTdAsyncWrapper.Step_(
      /** @type {string} */ (stepName),
      /** @type {function(!goog.testing.JsTdAsyncWrapper.Pool_=)} */ (fn)));
};

/**
 * Starts the execution.
 * @return {!goog.Promise<void>}
 */
goog.testing.JsTdAsyncWrapper.Queue.prototype.startExecuting = function() {
  return new goog.Promise(goog.bind(function(resolve, reject) {
    this.executeNextStep_(resolve, reject);
  }, this));
};

/**
 * Executes the next step on the queue waiting for all pool callbacks and then
 * starts executing any delegate queues before it finishes.
 * @param {function()} callback
 * @param {function(*)} errback
 * @private
 */
goog.testing.JsTdAsyncWrapper.Queue.prototype.executeNextStep_ = function(
    callback, errback) {
  // Note: From this point on, we can no longer use goog.Promise (which uses
  // the goog.async.run queue) because it conflicts with MockClock, and we can't
  // use the native Promise because it is not supported on IE. So we revert to
  // using callbacks and setTimeout.
  if (!this.steps_.length) {
    callback();
    return;
  }
  var step = this.steps_.shift();
  this.delegate_ = new goog.testing.JsTdAsyncWrapper.Queue(this.testObj_);
  var pool = new goog.testing.JsTdAsyncWrapper.Pool_(
      this.testObj_, goog.bind(function() {
        goog.testing.JsTdAsyncWrapper.REAL_SET_TIMEOUT_(goog.bind(function() {
          this.executeDelegate_(callback, errback);
        }, this), 0);
      }, this), goog.bind(function(reason) {
        this.handleError_(errback, reason, step.name);
      }, this));
  try {
    step.fn.call(this.testObj_, pool);
  } catch (e) {
    this.handleError_(errback, e, step.name);
  }
  pool.maybeComplete();
};

/**
 * Execute the delegate queue.
 * @param {function()} callback
 * @param {function(*)} errback
 * @private
 */
goog.testing.JsTdAsyncWrapper.Queue.prototype.executeDelegate_ = function(
    callback, errback) {
  // Wait till the delegate queue completes before moving on to the
  // next step.
  if (!this.delegate_) {
    this.executeNextStep_(callback, errback);
    return;
  }
  this.delegate_.executeNextStep_(goog.bind(function() {
    this.delegate_ = null;
    goog.testing.JsTdAsyncWrapper.REAL_SET_TIMEOUT_(goog.bind(function() {
      this.executeNextStep_(callback, errback);
    }, this), 0);
  }, this), errback);
};

/**
 * @param {function(*)} errback
 * @param {*} reason
 * @param {string} stepName
 * @private
 */
goog.testing.JsTdAsyncWrapper.Queue.prototype.handleError_ = function(
    errback, reason, stepName) {
  var error = reason instanceof Error ? reason : Error(reason);
  error.message = 'In step ' + stepName + ', error: ' + error.message;
  errback(reason);
};

/**
 * A step to be executed.
 * @param {string} name
 * @param {function(!goog.testing.JsTdAsyncWrapper.Pool_=)} fn
 * @constructor
 * @private
 */
goog.testing.JsTdAsyncWrapper.Step_ = function(name, fn) {
  /** @final {string} */
  this.name = name;
  /** @final {function(!goog.testing.JsTdAsyncWrapper.Pool_=)} */
  this.fn = fn;
};

/**
 * A fake pool that mimics the JSTD AsyncTestCase's pool object.
 * @param {!Object} testObj The test object containing all test methods. This
 *     object is passed into queue callbacks as the "this" object.
 * @param {function()} callback
 * @param {function(*)} errback
 * @constructor
 * @private
 * @final
 */
goog.testing.JsTdAsyncWrapper.Pool_ = function(testObj, callback, errback) {

  /** @private {number} */
  this.outstandingCallbacks_ = 0;

  /** @private {function()} */
  this.callback_ = callback;

  /** @private {function(*)} */
  this.errback_ = errback;

  /**
   * thisArg that should be used by default for defer function calls.
   * @private {!Object}
   */
  this.testObj_ = testObj;

  /** @private {boolean} */
  this.callbackCalled_ = false;
};

/**
 * @return {function()}
 */
goog.testing.JsTdAsyncWrapper.Pool_.prototype.noop = function() {
  return this.addCallback(function() {});
};

/**
 * @param {function(...*):*} fn The function to add to the pool.
 * @param {?number=} opt_n The number of permitted uses of the given callback;
 *     defaults to one.
 * @param {?number=} opt_timeout The timeout in milliseconds.
 *     This is not supported in the adapter for now. Specifying this argument
 *     will result in a test failure.
 * @param {?string=} opt_description The callback description.
 * @return {function()}
 */
goog.testing.JsTdAsyncWrapper.Pool_.prototype.addCallback = function(
    fn, opt_n, opt_timeout, opt_description) {
  // TODO(mtragut): This could be fixed if required by test cases.
  if (opt_timeout || opt_description) {
    throw Error(
        'Setting timeout or description in a pool callback is not supported.');
  }
  var numCallbacks = opt_n || 1;
  this.outstandingCallbacks_ = this.outstandingCallbacks_ + numCallbacks;
  return goog.bind(function() {
    try {
      fn.apply(this.testObj_, arguments);
    } catch (e) {
      if (opt_description) {
        e.message = opt_description + e.message;
      }
      this.errback_(e);
    }
    this.outstandingCallbacks_ = this.outstandingCallbacks_ - 1;
    this.maybeComplete();
  }, this);
};

/**
 * @param {function(...*):*} fn The function to add to the pool.
 * @param {?number=} opt_n The number of permitted uses of the given callback;
 *     defaults to one.
 * @param {?number=} opt_timeout The timeout in milliseconds.
 *     This is not supported in the adapter for now. Specifying this argument
 *     will result in a test failure.
 * @param {?string=} opt_description The callback description.
 * @return {function()}
 */
goog.testing.JsTdAsyncWrapper.Pool_.prototype.add =
    goog.testing.JsTdAsyncWrapper.Pool_.prototype.addCallback;

/**
 * @param {string} msg The message to print if the error callback gets called.
 * @return {function()}
 */
goog.testing.JsTdAsyncWrapper.Pool_.prototype.addErrback = function(msg) {
  return goog.bind(function() {
    var errorMsg = msg;
    if (arguments.length) {
      errorMsg += ' - Error callback called with params: ( ';
      for (var i = 0; i < arguments.length; i++) {
        var arg = arguments[i];
        errorMsg += arg + ' ';
        if (arg instanceof Error) {
          errorMsg += '\n' + arg.stack + '\n';
        }
      }
      errorMsg += ')';
    }
    this.errback_(errorMsg);
  }, this);
};

/**
 * Completes the pool if there are no outstanding callbacks.
 */
goog.testing.JsTdAsyncWrapper.Pool_.prototype.maybeComplete = function() {
  if (this.outstandingCallbacks_ == 0 && !this.callbackCalled_) {
    this.callbackCalled_ = true;
    this.callback_();
  }
};
<|endoftext|>


<commit_before>var releaseTools = require('./lib/main');
var Step = require('step');

// Customize example file we want to document
releaseTools.setOptions({
  examplePaths: 'Jakefile'
});

// ## Tests task
// This task executes the package tests by calling the standard `npm test` command
desc("execute tests");
task("test",function() {
  var spawn = require('child_process').spawn;
  var child = spawn('npm', ['test']);

  console.log('executing the tests...');

  child.stderr.on('data', function(stderr) {
    process.stderr.write(stderr);
  });
  child.stdout.on('data', function(stdout) {
    process.stdout.write(stdout);
  });
  child.on('exit', function(code) {
    if (code !== 0) {
      fail(code);
    } else {
      console.log('Done!');
      complete();
    }
  });
}, true);

// Namespace with all the release related tasks
namespace('release', function() {
  desc('Modify the working copy with all the release information');
  task('build', ['test'], function(releaseType) {

    Step(
      function(){

        // ### Update Changelog
        // It updated the `History.md` file with all the commit messages since
        // last package release (detected by last created tag).
        console.log('Updating History.md file...');
        releaseTools.updateChangelog(this);
      },
      function(err){
        if (err) throw err;

        // ### Update Contributors
        // It overwrites the AUTHORS file with all the GIT commiters
        console.log('Updating AUTHORS file...');
        releaseTools.updateAuthorsFile(this);
      },
      function(err){
        if (err) throw err;

        // ### Create examples
        // It converts all the specified example files to
        // HTML files with inline annotated comments, using
        // [Docco](http://jashkenas.github.com/docco/)
        console.log('creating examples documentation...');
        releaseTools.createExamples(this);
      },
      function(err){
        if (err) throw err;

        // ### Create site
        // It creates the `docs/` folder with the following contents:
        // * All the assets in `site/javascripts` and `site/stylesheets`
        // * The `site/index.html` skeleton file with the contents of the
        //   specified markdown files
        console.log('Creating the public site page');
        releaseTools.createSite(this);
      },
      function(err){
        if (err) fail();
        else complete();
      }
    );
  }, true);

  desc('Publish to GitHub and NPM the new version');
  task('publish', ['test'] ,function() {

    Step(
      function() {
        // First of all check if the `History.md` is modified
        // (to ensure that the `release:build` task has been already executed)
        releaseTools.isWorkingCopyClean('History.md', this);
      },
      function(err, result) {
        if (err) throw('Error while checking if the git tree is clean: ' + err);
        if (result) throw('You must run jake release:build before publish');

        // ### Commit to Git
        // Makes the commit and creates the tag
        console.log('Bumping version and creating git tag...');
        releaseTools.commitToGit(this);
      },
      function(err) {
        if (err) throw err;

        // ### Update gh-pages branch
        // If the branch does not exist, it creates it with the contents of
        // the `docs/` folder. If it already exists it copies the new contents
        // of the `docs/` folder into the branch
        console.log('Merging changes into gh-pages branch...');
        releaseTools.updatePagesBranch(this);
      },
      function(err) {
        if (err) throw err;

        // ### Push to GitHub
        // It just does a `git push origin`
        console.log('Pushing changes to GitHub...');
        releaseTools.pushToGit(this);
      },
      function(err) {
        if (err) throw err;

        // ### Publish to NPM
        // The same as `npm publish`
        console.log('Publishing NPM package...');
        releaseTools.npmPublish(this);
      },
      function(err){
        if (err) fail();
        else complete();
      }
    );
  }, true);

  // ## Update package.json task
  // It accepts a parameter which can be patch, minor or major and then
  // upgrades the version in the `package.json` file based on the
  // [Semantic Versioning Spec](http://semver.org/).
  // If no parameter is specified, it uses `patch`.
  desc('Bump version in package.json');
  task('bump', function(releaseType) {
    releaseType = releaseType || 'patch';
    console.log('Bumping version in package.json...');
    releaseTools.updateVersion(releaseType, function(err, newVersion) {
      if (err) {
        fail('Error while updating version in package.json: ' + err);
      }
      version = newVersion;
      console.log('Done!');
      complete();
    });
  }, true);
});

desc('Default task is test');
task('default', ['test'], function(){}, true);<commit_msg>Updated Jakefile.js file<commit_after>var releaseTools = require('./lib/main');
var Step = require('step');

// Customize example files to document via docco
releaseTools.setOptions({
  examplePaths: 'Jakefile.js'
});

// ## Tests task
// This task executes the package tests by calling the standard `npm test` command
desc("execute tests");
task("test",function() {
  var spawn = require('child_process').spawn;
  var child = spawn('npm', ['test']);

  console.log('executing the tests...');

  child.stderr.on('data', function(stderr) {
    process.stderr.write(stderr);
  });
  child.stdout.on('data', function(stdout) {
    process.stdout.write(stdout);
  });
  child.on('exit', function(code) {
    if (code !== 0) {
      fail(code);
    } else {
      console.log('Done!');
      complete();
    }
  });
}, true);

// Namespace with all the release related tasks
namespace('release', function() {
  desc('Modify the working copy with all the release information');
  task('build', ['test'], function(releaseType) {

    Step(
      function(){

        // ### Update Changelog
        // It updated the `History.md` file with all the commit messages since
        // last package release (detected by last created tag).
        console.log('Updating History.md file...');
        releaseTools.updateChangelog(this);
      },
      function(err){
        if (err) throw err;

        // ### Update Contributors
        // It overwrites the AUTHORS file with all the GIT commiters
        console.log('Updating AUTHORS file...');
        releaseTools.updateAuthorsFile(this);
      },
      function(err){
        if (err) throw err;

        // ### Create examples
        // It converts all the specified example files to
        // HTML files with inline annotated comments, using
        // [Docco](http://jashkenas.github.com/docco/)
        console.log('creating examples documentation...');
        releaseTools.createExamples(this);
      },
      function(err){
        if (err) throw err;

        // ### Create site
        // It creates the `docs/` folder with the following contents:
        // * All the assets in `site/javascripts` and `site/stylesheets`
        // * The `site/index.html` skeleton file with the contents of the
        //   specified markdown files
        console.log('Creating the public site page');
        releaseTools.createSite(this);
      },
      function(err){
        if (err) fail();
        else complete();
      }
    );
  }, true);

  desc('Publish to GitHub and NPM the new version');
  task('publish', ['test'] ,function() {

    Step(
      function() {
        // First of all check if the `History.md` is modified
        // (to ensure that the `release:build` task has been already executed)
        releaseTools.isWorkingCopyClean('History.md', this);
      },
      function(err, result) {
        if (err) throw('Error while checking if the git tree is clean: ' + err);
        if (result) throw('You must run jake release:build before publish');

        // ### Commit to Git
        // Makes the commit and creates the tag
        console.log('Bumping version and creating git tag...');
        releaseTools.commitToGit(this);
      },
      function(err) {
        if (err) throw err;

        // ### Update gh-pages branch
        // If the branch does not exist, it creates it with the contents of
        // the `docs/` folder. If it already exists it copies the new contents
        // of the `docs/` folder into the branch
        console.log('Merging changes into gh-pages branch...');
        releaseTools.updatePagesBranch(this);
      },
      function(err) {
        if (err) throw err;

        // ### Push to GitHub
        // It just does a `git push origin`
        console.log('Pushing changes to GitHub...');
        releaseTools.pushToGit(this);
      },
      function(err) {
        if (err) throw err;

        // ### Publish to NPM
        // The same as `npm publish`
        console.log('Publishing NPM package...');
        releaseTools.npmPublish(this);
      },
      function(err){
        if (err) fail();
        else complete();
      }
    );
  }, true);

  // ## Update package.json task
  // It accepts a parameter which can be patch, minor or major and then
  // upgrades the version in the `package.json` file based on the
  // [Semantic Versioning Spec](http://semver.org/).
  // If no parameter is specified, it uses `patch`.
  desc('Bump version in package.json');
  task('bump', function(releaseType) {
    releaseType = releaseType || 'patch';
    console.log('Bumping version in package.json...');
    releaseTools.updateVersion(releaseType, function(err, newVersion) {
      if (err) {
        fail('Error while updating version in package.json: ' + err);
      }
      version = newVersion;
      console.log('Done!');
      complete();
    });
  }, true);
});

desc('Default task is test');
task('default', ['test'], function(){}, true);<|endoftext|>


<commit_before>void function(){

var whatKey = function(k){
  // if ('char' in k) {
  //   return function whatKey(e){
  //     return (e.char || '').toLowerCase();
  //   };
  // }
  if ('keyIdentifier' in k) {
    return function whatKey(e){
      return e.keyIdentifier.toLowerCase();
    };
  } else if ('charCode' in k) {
    return function whatKey(e){
      return (e.charCode || '').toLowerCase();
    };
  }
}(document.createEvent('KeyboardEvent'));

function Keyboard(view){
  var self = this;
  this.keys = {};
  this.view = view;
  this.ctrl = false;
  this.shift = false;
  this.alt = false;
  this.meta = false;

  var events = {
    keydown: function(e){
      self.update(e);
      self.emit('down', e);
    },
    keyup: function(e){
      self.update(e);
      self.emit('up', e);
    },
    keypress: function(e){
      self.update(e);
      self.emit('press', e);
    }
  };

  for (var k in events) {
    view.addEventListener(k, events[k], true);
  }
}

Keyboard.prototype = {
  constructor: Keyboard,
  update: function update(evt){
    this.lastKey = whatKey(evt);
    this.lasyEvent = evt;
    this.ctrl = evt.ctrlKey;
    this.shift = evt.shiftKey;
    this.alt = evt.altKey;
    this.meta = evt.metaKey;
  },
  emit: function emit(type, evt){
    var listeners = this.listeners[this.lastKey];
    if (listeners) {
      for (var i=0; i < listeners.length; i++) {
        listeners[i](type, evt);
      }
    }
  },
  on: function on(bind, listener){
    var self = this,
        current = 0,
        events = [],
        keys = bind.split('->');

    if (keys.length > 1) {

      keys.forEach(function(key, index){
        var listeners = self.keys[key] || (self.keys[key] = []);
        listeners.push(function(type, evt){
          if (type === 'down') {
            if (events.length === index) {
              events.push(evt);
              if (index === keys.length - 1) {
                listener.apply(self, events);
                events.length = 0;
              }
            }
          } else {
            events.length = 0;
          }
        });
      });

    } else if ((keys = bind.split('+')).length > 1) {

      keys.forEach(function(key, index){
        var listeners = self.keys[key] || (self.keys[key] = []);
        listeners.push(function(type, evt){
          if (evt.type === 'down') {
            current++;
            events[index] = evt;
            if (events.length === keys.length) {
              listener.apply(self, events);
              events.length = 0;
            }
          } else if (type === 'up') {
            current--;
            events[index] = null;
          }
        });
      });

    } else {
      var listeners = self.keys[bind] || (self.keys[bind] = []);
      listeners.push(function(type, evt){
        listener.call(self, evt);
      });
    }
  }
};

window.keyboard = new Keyboard(window);

}();
<commit_msg>fix listener -> keys<commit_after>void function(){

var whatKey = function(k){
  // if ('char' in k) {
  //   return function whatKey(e){
  //     return (e.char || '').toLowerCase();
  //   };
  // }
  if ('keyIdentifier' in k) {
    return function whatKey(e){
      return e.keyIdentifier.toLowerCase();
    };
  } else if ('charCode' in k) {
    return function whatKey(e){
      return (e.charCode || '').toLowerCase();
    };
  }
}(document.createEvent('KeyboardEvent'));

function Keyboard(view){
  var self = this;
  this.keys = {};
  this.view = view;
  this.ctrl = false;
  this.shift = false;
  this.alt = false;
  this.meta = false;

  var events = {
    keydown: function(e){
      self.update(e);
      self.emit('down', e);
    },
    keyup: function(e){
      self.update(e);
      self.emit('up', e);
    },
    keypress: function(e){
      self.update(e);
      self.emit('press', e);
    }
  };

  for (var k in events) {
    view.addEventListener(k, events[k], true);
  }
}

Keyboard.prototype = {
  constructor: Keyboard,
  update: function update(evt){
    this.lastKey = whatKey(evt);
    this.lasyEvent = evt;
    this.ctrl = evt.ctrlKey;
    this.shift = evt.shiftKey;
    this.alt = evt.altKey;
    this.meta = evt.metaKey;
  },
  emit: function emit(type, evt){
    var listeners = this.keys[this.lastKey];
    if (listeners) {
      for (var i=0; i < listeners.length; i++) {
        listeners[i](type, evt);
      }
    }
  },
  on: function on(bind, listener){
    var self = this,
        current = 0,
        events = [],
        keys = bind.split('->');

    if (keys.length > 1) {

      keys.forEach(function(key, index){
        var listeners = self.keys[key] || (self.keys[key] = []);
        listeners.push(function(type, evt){
          if (type === 'down') {
            if (events.length === index) {
              events.push(evt);
              if (index === keys.length - 1) {
                listener.apply(self, events);
                events.length = 0;
              }
            }
          } else {
            events.length = 0;
          }
        });
      });

    } else if ((keys = bind.split('+')).length > 1) {

      keys.forEach(function(key, index){
        var listeners = self.keys[key] || (self.keys[key] = []);
        listeners.push(function(type, evt){
          if (evt.type === 'down') {
            current++;
            events[index] = evt;
            if (events.length === keys.length) {
              listener.apply(self, events);
              events.length = 0;
            }
          } else if (type === 'up') {
            current--;
            events[index] = null;
          }
        });
      });

    } else {
      var listeners = self.keys[bind] || (self.keys[bind] = []);
      listeners.push(function(type, evt){
        listener.call(self, evt);
      });
    }
  }
};

window.keyboard = new Keyboard(window);

}();
<|endoftext|>


<commit_before>var portName = "/dev/ttyUSB0";
var tagType  = "iso15693"
var sys = require("sys");
var com = require("serialport");
var events = require("events");

// read reader config file
var readerConfig = require('./univelop_500b.json');

// Create new serialport pointer
var reader = new com.SerialPort(portName , {
  baudRate: 115200,
  dataBits: 8,
  parity: 'none',
  stopBits: 1,
  flowControl: false,
  parser: com.parsers.readline('\r\n')
}, true); // this is the openImmediately flag [default is true]

// data variables
var tagData = ''; // this stores the tag data
var readData = '';  // this stores the buffer

/* Workflow:
  Reader gets 'open' event, runs:
  * initialize
  * initcodes
  * turns on the read tag loop
*/
reader.on('open',function() {
  console.log('Port open');
  reader.emit('initialize', readerConfig.initialize['init']);
  scanLoop(readerConfig.protocols[tagType], function(data) {
    readTag(data, function(err,result) {
      if(!!result) {
        reader.emit('tagfound', result);
      }
      else {
        return (err);
      }
    });
  });
});

/*
  FUNCTIONS
*/

// Hex string to ASCII
var hex2a = function(hex) {
  var str = '';
  for (var i = 0; i < hex.length; i += 2)
      str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
  return str;
}

// query command
var query = function(cmd, callback) {
  reader.write(cmd, function(err) {
    if (err){ callback(err) }
    else {
      console.log("ran cmd: "+cmd+"...waiting for data");
    }
  });
}

// inventory command
var inventory = function(cmd, callback) {
  reader.write(cmd, function(err) {
    if (err) {
      console.log("err: "+err);
      callback(err)
    }
    else {
      console.log("ran inventory!")
    }
  });
}

// tag loop
var scanLoop = function(protocol, callback) {
  setInterval(function (){
    // run inventory check in intervals
    inventory(protocol['inventory'], function(err) {
      if (err) { callback(err) }
      else {
        return tag;
      }
    });
  }, 1000);
}

// read loop
var readTag = function(protocol, callback) {
  setInterval(function (){
    query(protocol['inventory'], function(err) {
      if (err) { callback(err) }
    });
  }, 1000);
}

// EVENT LISTENERS

// initialize
reader.on('initialize', function(cmd, callback) {
  reader.write(cmd, function(err) {
    if (err){ callback(err)}
    else {
      console.log('initialized reader...')
      // initialized? run initcodes
      reader.emit('initcodes', readerConfig.protocols[tagType]['initcodes']);
      }
  });
});

// initcodes
reader.on('initcodes', function(cmd, callback) {
  reader.write(cmd['register_write_request'], function(err) {
    if (err){ callback(err)}
    else {
      reader.write(cmd['agc_enable'], function(err) {
        if (err){ callback(err)}
        else {
          reader.write(cmd['am_input'], function(err) {
          if (err){ callback(err)}
          else {
            console.log("finished initializing!");
            }
          });
        }
      });
    }
  });
});

// tagresult
reader.on('tagfound', function( data ) {
  console.log("got tag: "+data);
});

// handling of all data
reader.on('data', function( data ) {

  if (/,..]/.test(data) == true) { // we have a tag id! (followed by comma and position)
    console.log("received: "+data);
    var tag=/\[([0-9A-F]+)\,..\]/.exec(data);  // strip away empty tag location ids (eg. ',40)
    reader.emit('tag', tag);
  }
  else if (/\[.+\]/.test(data) == true) { // then we have received data
    reader.emit('rfiddata', data);
  }
});

// tag
reader.on('tag', function( msg ) {
  console.log("tag id: " + msg );
});

// rfiddata
reader.on('rfiddata', function( msg ) {
  console.log("rfiddata: " + msg );
});

// error
reader.on('error', function( msg ) {
  console.log("error: " + msg );
});

// close
reader.on('close', function ( err ) {
  console.log('port closed');
});

// End Event Listeners

<commit_msg>moved more code<commit_after>var sys = require("sys");
var com = require("serialport");
var events = require("events");

// read reader config file
var readerConfig = require('./univelop_500b.json');

// reader variables
var portName = "/dev/ttyUSB0";
var tagType  = "iso15693"
var length_to_read = 5;  // total length to read - 1
var bytes_per_read = 0;  // no bytes per read - 1

// data variables
var tagData = ''; // this stores the tag data
var readData = '';  // this stores the read buffer
var start_offset = 1;

// Create new serialport pointer
var reader = new com.SerialPort(portName , {
  baudRate: 115200,
  dataBits: 8,
  parity: 'none',
  stopBits: 1,
  flowControl: false,
  parser: com.parsers.readline('\r\n')
}, true); // this is the openImmediately flag [default is true]

/* Workflow:
  Reader gets 'open' event, runs:
  * emit initialize event
  * turns on the scan loop
*/
reader.on('open',function() {
  console.log('Port open');
  reader.emit('initialize', readerConfig.initialize['init']);
  scanLoop(readerConfig.protocols[tagType], function(err) {
    if (err) {console.log("err: "+err};
  });
});

/*
  FUNCTIONS
*/

// Hex string to ASCII
var hex2a = function(hex) {
  var str = '';
  for (var i = 0; i < hex.length; i += 2)
      str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
  return str;
}

var dec2hex = function(d) {
  return ("0"+(Number(d).toString(16))).slice(-2).toUpperCase()
}

// query command
var query = function(cmd, callback) {
  reader.write(cmd, function(err) {
    if (err){ callback(err) }
    else {
      console.log("ran cmd: "+cmd+"...waiting for data");
    }
  });
}

// inventory command
var inventory = function(cmd, callback) {
  reader.write(cmd, function(err) {
    if (err) {
      console.log("err: "+err);
      callback(err)
    }
    else {
      console.log("ran inventory!")
    }
  });
}

// tag loop
var scanLoop = function(protocol, callback) {
  setInterval(function (){
    // run inventory check in intervals
    inventory(protocol['inventory'], function(err) {
      if (err) { callback(err) }
    });
  }, 1000);
}

// read loop
var readTag = function(tag, callback) {
  query(protocol['inventory'], function(err) {
    if (err) { callback(err) }
  });
}

// EVENT LISTENERS

// initialize reader and emit initcodes event
reader.on('initialize', function(cmd, callback) {
  reader.write(cmd, function(err) {
    if (err){ callback(err)}
    else {
      console.log('initialized reader...')
      // initialized? emit initcodes
      reader.emit('initcodes', readerConfig.protocols[tagType]['initcodes']);
    }
  });
});

// initcodes
reader.on('initcodes', function(cmd, callback) {
  reader.write(cmd['register_write_request'], function(err) {
    if (err){ callback(err)}
    else {
      reader.write(cmd['agc_enable'], function(err) {
        if (err){ callback(err)}
        else {
          reader.write(cmd['am_input'], function(err) {
          if (err){ callback(err)}
          else {
            console.log("finished initializing!");
            }
          });
        }
      });
    }
  });
});

// on data event, if
// fire 'tag' event if comma in result
// fire rfiddata if data in square brackets
reader.on('data', function( data ) {
  console.log("received: "+data);
  if (/,..]/.test(data) == true) { // we have a tag id! (followed by comma and position)
    var tag=/\[([0-9A-F]+)\,..\]/.exec(data);  // strip away empty tag location ids (eg. ',40)
    reader.emit('tag', tag);
  }
  else if (/\[.+\]/.test(data) == true) { // then we have received data
    reader.emit('rfiddata', data);
  }
});

// tag
reader.on('tag', function( tag ) {
  console.log("tag id: " + tag );
  tagData = '';  // reset data
  var offset = start_offset;
  reader.emit('tagdata', offset);
});

// rfiddata received
reader.on('rfiddata', function( data ) {
  console.log("rfiddata received: " + data );
  tagData += data;
  if (tagData.length == 16 || data == 'W_OK') {
    console.log("got full tag: "+tagData);
  } else {
    offset += bytes_per_read + 1
    reader.emit('tagdata', offset);
  }
});

// tagdata
// from rfidgeek:
// def issue_command(protocol, cmd, cmd_length, options={})
// read = issue_command(protocol, "18", "0C", :command_code => "23", :offset => "%02X" % offset, :bytes_per_read => "%02X" % bytes_per_read)
// @command = "01" + cmd_length.to_s + "000304" + cmd.to_s + options[:flags] + options[:command_code] + options[:offset] + options[:bytes_per_read] + "0000"

reader.on('tagdata', function( offset ) {
  cmd = ['01','0C','00','03','04','18','00','23', dec2hex(offset), dec2hex(bytes_per_read), '00', '00'].join('');
  console.log("tagdata cmd: " + cmd );
  reader.write(cmd);
});

// error
reader.on('error', function( msg ) {
  console.log("error: " + msg );
});

// close
reader.on('close', function ( err ) {
  console.log('port closed');
});

// End Event Listeners

<|endoftext|>


<commit_before>/* eslint-disable max-len */
import 'newrelic'
import 'babel-polyfill'
import 'isomorphic-fetch'

import express from 'express'
import morgan from 'morgan'
import throng from 'throng'
import librato from 'librato-node'
import path from 'path'
import fs from 'fs'
import React from 'react'
import { renderToString } from 'react-dom/server'
import { match, RouterContext } from 'react-router'
import { Provider } from 'react-redux'
import store from './src/store'
import { updateStrings as updateTimeAgoStrings } from './src/vendor/time_ago_in_words'
import addOauthRoute from './oauth'
import routes from './src/routes'
import { replacePath } from 'redux-simple-router'

// load env vars first
require('dotenv').load({ silent: process.env.NODE_ENV === 'production' })
global.ENV = require('./env')
updateTimeAgoStrings({ about: '' })

const app = express()

// Log requests with Morgan
app.use(morgan('combined'))

// Send stats to Librato
librato.configure({ email: process.env.LIBRATO_EMAIL,
                    token: process.env.LIBRATO_TOKEN })
librato.start()
app.use(librato.middleware())

let indexStr = ''
// grab out the index.html string first thing
fs.readFile(path.join(__dirname, './public/index.html'), 'utf-8', (err, data) => {
  if (!err) {
    indexStr = data
  }
})

// Wire up OAuth route
addOauthRoute(app)

// Assets
app.use(express.static('public'))
app.use('/static', express.static('public/static'))

// Return promises for initial loads
function preRender(renderProps) {
  const promises = renderProps.components.map(component => (component && component.preRender) ? component.preRender(store, renderProps) : null).filter(component => !!component)
  return Promise.all(promises)
}

function renderFromServer(req, res) {
  match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
    // populate the rouer store object for initial render
    store.dispatch(replacePath(renderProps.location.pathname, {}, { avoidRouterUpdate: true }))
    if (error) {
      console.log('match error', error)
    } else if (redirectLocation) {
      console.log('handle redirect', redirectLocation)
    } else if (!renderProps) { return }
    preRender(renderProps).then(() => {
      const InitialComponent = (
        <Provider store={store}>
          <RouterContext {...renderProps} />
        </Provider>
      )
      const componentHTML = renderToString(InitialComponent)
      const state = store.getState()
      const initialStateTag = `<script id="initial-state">window.__INITIAL_STATE__ = ${JSON.stringify(state)}</script>`
      indexStr = indexStr.replace('

', `<div id="root">${componentHTML}</div>${initialStateTag}`)
      res.send(indexStr)
    }).catch((err) => {
      // this will give you a js error like:
      // `window is not defined`
      console.log('CATCH ERROR', err)
    })
  })
}

const loggedOutPaths = {
  find: /^\/find$/,
  explore: /^\/explore/,
  explore_recent: /^\/explore\/recent/,
  explore_trending: /^\/explore\/trending/,
  signup: /^\/signup/,
}

app.use((req, res) => {
  let isLoggedOutPath = false
  for (const re in loggedOutPaths) {
    if (req.url.match(loggedOutPaths[re])) {
      isLoggedOutPath = true
      break
    }
  }
  console.log('url', req.url, isLoggedOutPath)
  if (isLoggedOutPath) {
    renderFromServer(req, res)
  } else {
    res.send(indexStr)
  }
})

const port = process.env.PORT || 6660
const WORKERS = process.env.WEB_CONCURRENCY || 1;
const start = () => {
  app.listen(port, (err) => {
    if (err) {
      console.log(err)
      return
    }
    console.log('Listening at http://localhost:' + port)
  })
}

throng(start, {
  workers: WORKERS,
  lifetime: Infinity,
});
<commit_msg>Adds an error handler for librato.<commit_after>/* eslint-disable max-len */
import 'newrelic'
import 'babel-polyfill'
import 'isomorphic-fetch'

import express from 'express'
import morgan from 'morgan'
import throng from 'throng'
import librato from 'librato-node'
import path from 'path'
import fs from 'fs'
import React from 'react'
import { renderToString } from 'react-dom/server'
import { match, RouterContext } from 'react-router'
import { Provider } from 'react-redux'
import store from './src/store'
import { updateStrings as updateTimeAgoStrings } from './src/vendor/time_ago_in_words'
import addOauthRoute from './oauth'
import routes from './src/routes'
import { replacePath } from 'redux-simple-router'

// load env vars first
require('dotenv').load({ silent: process.env.NODE_ENV === 'production' })
global.ENV = require('./env')
updateTimeAgoStrings({ about: '' })

const app = express()

// Log requests with Morgan
app.use(morgan('combined'))

// Send stats to Librato
librato.configure({ email: process.env.LIBRATO_EMAIL,
                    token: process.env.LIBRATO_TOKEN })
librato.start()
app.use(librato.middleware())

librato.on('error', (err) => {
  console.log('ELLO LIBRATO ERROR', err)
})

let indexStr = ''
// grab out the index.html string first thing
fs.readFile(path.join(__dirname, './public/index.html'), 'utf-8', (err, data) => {
  if (!err) {
    indexStr = data
  }
})

// Wire up OAuth route
addOauthRoute(app)

// Assets
app.use(express.static('public'))
app.use('/static', express.static('public/static'))

// Return promises for initial loads
function preRender(renderProps) {
  const promises = renderProps.components.map(component => (component && component.preRender) ? component.preRender(store, renderProps) : null).filter(component => !!component)
  return Promise.all(promises)
}

function renderFromServer(req, res) {
  match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
    // populate the rouer store object for initial render
    store.dispatch(replacePath(renderProps.location.pathname, {}, { avoidRouterUpdate: true }))
    if (error) {
      console.log('match error', error)
    } else if (redirectLocation) {
      console.log('handle redirect', redirectLocation)
    } else if (!renderProps) { return }
    preRender(renderProps).then(() => {
      const InitialComponent = (
        <Provider store={store}>
          <RouterContext {...renderProps} />
        </Provider>
      )
      const componentHTML = renderToString(InitialComponent)
      const state = store.getState()
      const initialStateTag = `<script id="initial-state">window.__INITIAL_STATE__ = ${JSON.stringify(state)}</script>`
      indexStr = indexStr.replace('

', `<div id="root">${componentHTML}</div>${initialStateTag}`)
      res.send(indexStr)
    }).catch((err) => {
      // this will give you a js error like:
      // `window is not defined`
      console.log('CATCH ERROR', err)
    })
  })
}

const loggedOutPaths = {
  find: /^\/find$/,
  explore: /^\/explore/,
  explore_recent: /^\/explore\/recent/,
  explore_trending: /^\/explore\/trending/,
  signup: /^\/signup/,
}

app.use((req, res) => {
  let isLoggedOutPath = false
  for (const re in loggedOutPaths) {
    if (req.url.match(loggedOutPaths[re])) {
      isLoggedOutPath = true
      break
    }
  }
  console.log('url', req.url, isLoggedOutPath)
  if (isLoggedOutPath) {
    renderFromServer(req, res)
  } else {
    res.send(indexStr)
  }
})

const port = process.env.PORT || 6660
const WORKERS = process.env.WEB_CONCURRENCY || 1;
const start = () => {
  app.listen(port, (err) => {
    if (err) {
      console.log(err)
      return
    }
    console.log('Listening at http://localhost:' + port)
  })
}

throng(start, {
  workers: WORKERS,
  lifetime: Infinity,
});
<|endoftext|>


<commit_before>const mongoose = require('mongoose')
const { composeWithMongoose } = require('graphql-compose-mongoose')

const ProviderSchema = new mongoose.Schema(
  {
    id: String,
    token: String
  },
  {
    _id: false, // disable `_id` field for `Authen` schema
  }
)

const UserSchema = new mongoose.Schema({
  id: String,
  name: String,
  last_name: String,
  first_name: String,
  email: String,
  token: String,
  verified: { type: 'boolean', default: false },
  phones: String,
  facebook: { type: ProviderSchema },
  twitter: { type: ProviderSchema },
  google: { type: ProviderSchema },
  github: { type: ProviderSchema },
  role: { type: String, default: 'user' }
},
{
  timestamps: true,
})

// - - - - - - Plugins - - - - - -
// User roles
const role = require('mongoose-role')
UserSchema.plugin(role, {
  roles: ['public', 'user', 'admin'],
  accessLevels: {
    'public': ['public', 'user', 'admin'],
    'anon': ['public'],
    'user': ['user', 'admin'],
    'admin': ['admin']
  }
})

const User = mongoose.model('User', UserSchema)
const UserTC = composeWithMongoose(User)

const Provider = mongoose.model('Provider', ProviderSchema)
module.exports = { User, UserTC, Provider }
<commit_msg>Add separator<commit_after>const mongoose = require('mongoose')
const { composeWithMongoose } = require('graphql-compose-mongoose')

const ProviderSchema = new mongoose.Schema(
  {
    id: String,
    token: String
  },
  {
    _id: false, // disable `_id` field for `Authen` schema
  }
)

const UserSchema = new mongoose.Schema({
  id: String,
  name: String,
  last_name: String,
  first_name: String,
  email: String,
  token: String,
  verified: { type: 'boolean', default: false },
  phones: String,
  facebook: { type: ProviderSchema },
  twitter: { type: ProviderSchema },
  google: { type: ProviderSchema },
  github: { type: ProviderSchema },
  role: { type: String, default: 'user' }
},
{
  timestamps: true,
})

// - - - - - - Plugins - - - - - -
// User roles
const role = require('mongoose-role')
UserSchema.plugin(role, {
  roles: ['public', 'user', 'admin'],
  accessLevels: {
    'public': ['public', 'user', 'admin'],
    'anon': ['public'],
    'user': ['user', 'admin'],
    'admin': ['admin']
  }
})

const User = mongoose.model('User', UserSchema)
const UserTC = composeWithMongoose(User)

const Provider = mongoose.model('Provider', ProviderSchema)

// - - - - - - Exports - - - - - -

module.exports = { User, UserTC, Provider }
<|endoftext|>


<commit_before>/**
 * Created by robin on 20/08/14.
 */
var last_search;
var movie_time = 0;

$( document ).ready(function() {
    console.log( "ready!" );

    //init autohide navbar
    init_autohide_navbar();

    //init masonry
    init_masonry();
});

window.onunload = function(){
    stop_stream();
    console.log("stopped stream");
};

function init_autohide_navbar(){
    $("div.navbar-fixed-top").autoHidingNavbar();
}

function init_masonry(){
    var container = document.querySelector('#card-layout');

    var masonry = new Masonry(container, {
        columnWidth: 10,
        itemSelector: '.card',
        isFitWidth: false,
        isAnimated: false,
        transitionDuration: 0
    });
    /*window.addEventListener('resize', function(event){
     if(document.body.clientWidth < 820){
     mansory.isFitWidth = false;
     }else{
     mansory.isFitWidth = true;
     }
     });*/
}

function search(search){
    console.log(search);

    var this_search = new Date().getTime();
    last_search = this_search;

    //ajax request to for the search:
    $.ajax({
        url: "get.php?search=" + search
    }).done(function( data ) {
        if ( console && console.log ) {
            if(last_search == this_search){
                var lib = JSON.parse(data);
                var movies = [];
                var html = "";

                //get movies
                for(var movie in lib.movies){
                    movies.push([movie, lib.movies[movie]]);
                    html += movie_to_html(lib.movies[movie]);
                }
                $("div#card-layout").html(html);
                init_masonry();
            }
        }
    });
}

function create_videoplayer(source, path, poster){
    video = $("video")[0];

    if(video == undefined){
        movie = {path: path, poster: poster};
        console.log("creating player: " + source);
        var template = $('#movie-player-template').html();
        var html = Mustache.to_html(template, movie);
        $("div#player-layout").html(html);

        video = $("video")[0];

        video.addEventListener("loadedmetadata", function(){
           video.play();
        }, false);

        video.addEventListener('waiting', function() {
            console.log('waiting');
        }, false);

        video.addEventListener('loadedmetadata', function () {

            video.currentTime = movie_time;
        });

        video.addEventListener("error",function () {
            if(!video.paused){
                console.log("error, restarting stream "+ video.src);
                start_stream(path, poster);
            }
            /*
            window.setTimeout(function(){
                if(!video.src != null && video.src.match("/null/i") != null){

                }
            }, 1000);*/
        }, false);

    }

}

function play(source){
    var video = document.getElementsByTagName('video')[0];
    if(video != undefined){
        video.src = source + "?buffer=5";
        video.play();
        video.addEventListener('click',function(){
            video.play();
        },false);

        console.log("Playing: " + video.src);
    }
}

function pause(){
    var video = document.getElementsByTagName('video')[0];
    if(video != undefined){
        video.pause();
    }
}

function movie_to_html(movie){
    var template = $('#movie-card-template').html();
    var html = Mustache.to_html(template, movie);
    return html;
}

function start_stream(path, poster){
    pause();
    var feed = "feed.ffm";
    var stream = "test.mkv"
    var stream_url = "http://" + window.location.hostname + ":8090/" + stream;
    var stream_ajax_url = "stream.php?i=" + path + "&f=" + feed;

    console.log("starting stream: " + stream_ajax_url);
    $.ajax({
        url: stream_ajax_url
    }).done(function( data ) {
        console.log("stream started on server side");
        play(stream_url);
    });

    create_videoplayer(stream_url, path, poster);

    return stream_url;
}

function stop_stream(){
    var video = document.getElementsByTagName('video')[0];
    if(video != undefined){
        video.pause();
        //video.src = null;
    }
    console.log("Killing ffmpeg on server...");
    $.ajax({
        url: "stream.php"
    }).done(function( data ) {
        //this is when the file is done i think
    });
}<commit_msg>fixed poster so that it changes correctly. Also saved that when the videoplayer fails, it restarts the right stream and not the stream that created the video player<commit_after>/**
 * Created by robin on 20/08/14.
 */
var last_search;
var movie_time = 0;
var video_path = "";
var video_poster= "";
var video_loading = false;

$( document ).ready(function() {
    console.log( "ready!" );

    //init autohide navbar
    init_autohide_navbar();

    //init masonry
    init_masonry();
});

window.onunload = function(){
    stop_stream();
    console.log("stopped stream");
};

function init_autohide_navbar(){
    $("div.navbar-fixed-top").autoHidingNavbar();
}

function init_masonry(){
    var container = document.querySelector('#card-layout');

    var masonry = new Masonry(container, {
        columnWidth: 10,
        itemSelector: '.card',
        isFitWidth: false,
        isAnimated: false,
        transitionDuration: 0
    });
    /*window.addEventListener('resize', function(event){
     if(document.body.clientWidth < 820){
     mansory.isFitWidth = false;
     }else{
     mansory.isFitWidth = true;
     }
     });*/
}

function search(search){
    console.log(search);

    var this_search = new Date().getTime();
    last_search = this_search;

    //ajax request to for the search:
    $.ajax({
        url: "get.php?search=" + search
    }).done(function( data ) {
        if ( console && console.log ) {
            if(last_search == this_search){
                var lib = JSON.parse(data);
                var movies = [];
                var html = "";

                //get movies
                for(var movie in lib.movies){
                    movies.push([movie, lib.movies[movie]]);
                    html += movie_to_html(lib.movies[movie]);
                }
                $("div#card-layout").html(html);
                init_masonry();
            }
        }
    });
}

function create_videoplayer(source){
    video = $("video")[0];

    if(video == undefined){
        movie = {path: video_path, poster: video_poster};
        console.log("creating player: " + source);
        var template = $('#movie-player-template').html();
        var html = Mustache.to_html(template, movie);
        $("div#player-layout").html(html);

        video = $("video")[0];

        video.addEventListener("loadedmetadata", function(){
           video.play();
        }, false);

        video.addEventListener('waiting', function() {
            console.log('waiting');
        }, false);

        video.addEventListener('loadedmetadata', function () {

            video.currentTime = movie_time;
        });

        video.addEventListener("error",function () {
            if(!video.paused){
                console.log("error, restarting stream "+ video.src);
                start_stream(video_path, video_poster);
            }
            /*
            window.setTimeout(function(){
                if(!video.src != null && video.src.match("/null/i") != null){

                }
            }, 1000);*/
        }, false);

    }else{
        video.poster = video_poster;
    }

}

function play(source){
    var video = document.getElementsByTagName('video')[0];
    if(video != undefined){
        video.src = source + "?buffer=5";
        video.play();
        video.addEventListener('click',function(){
            video.play();
        },false);

        console.log("Playing: " + video.src);
    }
}

function pause(){
    var video = document.getElementsByTagName('video')[0];
    if(video != undefined){
        video.pause();
    }
}

function movie_to_html(movie){
    var template = $('#movie-card-template').html();
    var html = Mustache.to_html(template, movie);
    return html;
}

function start_stream(path, poster){
    pause();
    var feed = "feed.ffm";
    var stream = "test.mkv"
    var stream_url = "http://" + window.location.hostname + ":8090/" + stream;
    var stream_ajax_url = "stream.php?i=" + path + "&f=" + feed;

    if(video_loading == false){
        video_loading = true;
        video_path = path;
        video_poster = poster;
        console.log("starting stream: " + stream_ajax_url);
        $.ajax({
            url: stream_ajax_url
        }).done(function( data ) {
            console.log("stream started on server side");
            video_loading = false;
            play(stream_url);
        });
        create_videoplayer(stream_url);
    }
    return stream_url;

}

function stop_stream(){
    var video = document.getElementsByTagName('video')[0];
    if(video != undefined){
        video.pause();
        //video.src = null;
    }
    console.log("Killing ffmpeg on server...");
    $.ajax({
        url: "stream.php"
    }).done(function( data ) {
        //this is when the file is done i think
    });
}<|endoftext|>


<commit_before>/******************************************
 * Form Handlers and page                 *
 * generators for TSSAA WebApp Fat Client *
 *****************************************/
var Credentials = {
	username: "",
	secret: ""
};

$.fn.serializeObject = function () {
	var o = {};
	var a = this.serializeArray();

	$.each(a, function() {
		if (o[this.name] !== undefined) {
			if (!o[this.name].push) {
				o[this.name] = [o[this.name]];
			}
			o[this.name].push(this.value || '');
		} else {
			o[this.name] = this.value || '';
		}
	});
	return o;
};

function generateAuthHeader(creds) {
	var nonce = generateNonce(16);
	var nonce64 = base64encode(nonce);

	var created = ISODateString(new Date());

	var digest = b64_sha1(nonce + created + creds.secret);

	var x_wsse_header = "UsernameToken Username=\""
		+ creds.user + "\", PasswordDigest=\""
		+ digest + "\", Nonce=\""
		+ nonce64 + "\", Created=\""
		+ created + "\"";

	return {'X-WSSE': x_wsse_header};
}

/**
 * AJAX convenience wrapper
 * @param uri target uri for request
 * @param args object comprised of args for ajax call
 */
function service_call(uri, args) {
	if (!args.hasOwnProperty('creds')) {
		args.creds = Credentials;
	}

	$.ajax(uri, {
		//type: args.hasOwnProperty("request_params") ? "POST" : "GET",
		type: 'POST',
		// JSON.stringify will return undefined if args.request_params is undef
		//data: ,//JSON.stringify(args.request_params),
		beforeSend: function (xhr) {
			xhr.setRequestHeader(generateAuthHeader(args.creds));
		},
		success: on_success,
		error: console.err(err),
		complete: on_complete,
	});

	function on_success (response, textStatus, jqXHR) {
		console.log("log: on_success: " + textStatus);

		data = JSON.parse(response);

		if (data.status === "success") {
			// TODO check if payload prop
			args.on_success(data.payload);
		} else {
			// TODO exception definitions
			args.on_failure(textStatus, data.exception);
		}
	}

	function on_failure (jqXHR, textStatus, errorThrown) {
		console.log("log: on_failure: " + textStatus);

		if (args.on_failure) {
			args.on_failure(textStatus, errorThrown);
		} else {
			// Do nothing
		}
	}

	function on_complete (jqXHR, textStatus) {
		console.log("log: on_complete: " + textStatus);

		if (args.on_complete) {
			args.on_complete(jqXHR, textStatus);
		} else {
			// Do nothing
		}
	}
	return false;
}

/**
 * Login form ajax callback
 * TODO session management handled here?
 */
function loginSuccess(login_response) {
	$("h2#options_welcome_banner strong").text(login_response.payload);
	$.mobile.changePage($("#options_page"), {
		transition: "slideup",
		reverse: true,
	});
}

/**
 * DB Dialog ajax success callback
 */
function popDBDialog(response) {
	$("#response").text("Success! New school added!");
	$.mobile.changePage("#db_confirm_dialog");
}

/**
 * School List response handler
 * generates ul of schools returned from DB
 */
function generateSchoolList(school_data) {
	var schools_html = [];

	for (school in school_data) {
		school = school_data[school];
		var button = 'Edit This School';

		var block = '

' +
			school.name + '

Phone: ' +
			school.phone + '

Address: ' +
			school.address + '
' + button + '
';
		schools_html.push(block);
	}

	$('div#school_list').html(schools_html.join(''));

	$('div#school_list').on('click', 'a.edit_school', function (e) {
		var index = $(this).attr("ks_school_id");
		var school = school_data[index];
		$.each($("form#edit_school_form input"), function() {
			var key = $(this).attr("name");
			$(this).attr("value", school[key]);
		});
		editSchoolEntity(school);
	});
	$.mobile.changePage($("#school_list_page"));
};

function editSchoolEntity(school) {
	$("#edit_school_form").on("submit", function (e) {
		var form_data = $("#edit_school_form").serializeObject();
		if( !form_data.id){
			form_data.id = school.id;
		}

		service_call("app_dev.php/update_school", {
			request_params: form_data,
			on_success: function () {$.mobile.changePage("#school_list_page")}
		});

		return false;
	});

	$.mobile.changePage("#edit_school_dialog", {
		transistion: "pop"
	});

}

$(document).on("pageinit", function(e, obj) {
	/**
	 * Login form handler
	 */
	$("#login_page").on("submit", function(e, obj) {
		var args = {};
		args.creds = {
			user: $("#login_input").val(),
			password: $("#pass_input").val()
		};
		console.info(serializeObject("serialized obj"), args.creds);

		service_call("app_dev/login", args);
		console.info('post service_call');

		return false;
	});

	/**
	 * Add school form ajax handler
	 */
	$('#add_school_submit').on('click', function(e, obj) {
		var  formData = $('#add_school_form').serializeObject();

		service_call("app_dev.php/add_school", {
			request_params: formData,
			on_success: popDBDialog
		});

		return false;
	});
});

/**
 * Get school list ajax handler
 */
$(document).on("pagebeforechange", function(e, obj) {
	var url= $.mobile.path.parseUrl(obj.toPage);

	if ( url.hash  === "#school_list_page") {
		service_call("app_dev.php/get_school_list", {
			on_success: generateSchoolList
		});

		e.preventDefault();
	};
});

<commit_msg>figure out what a hole in the ground is w/ref to<commit_after>/******************************************
 * Form Handlers and page                 *
 * generators for TSSAA WebApp Fat Client *
 *****************************************/
var Credentials = {
	username: "",
	secret: ""
};

$.fn.serializeObject = function () {
	var o = {};
	var a = this.serializeArray();

	$.each(a, function() {
		if (o[this.name] !== undefined) {
			if (!o[this.name].push) {
				o[this.name] = [o[this.name]];
			}
			o[this.name].push(this.value || '');
		} else {
			o[this.name] = this.value || '';
		}
	});
	return o;
};

function generateAuthHeader(creds) {
	var nonce = generateNonce(16);
	var nonce64 = base64encode(nonce);

	var created = ISODateString(new Date());

	var digest = b64_sha1(nonce + created + creds.secret);

	var x_wsse_header = "UsernameToken Username=\""
		+ creds.user + "\", PasswordDigest=\""
		+ digest + "\", Nonce=\""
		+ nonce64 + "\", Created=\""
		+ created + "\"";

	return {'X-WSSE': x_wsse_header};
}

/**
 * AJAX convenience wrapper
 * @param uri target uri for request
 * @param args object comprised of args for ajax call
 */
function service_call(uri, args) {
	if (!args.hasOwnProperty('creds')) {
		args.creds = Credentials;
	}

	$.ajax(uri, {
		//type: args.hasOwnProperty("request_params") ? "POST" : "GET",
		type: 'POST',
		// JSON.stringify will return undefined if args.request_params is undef
		//data: ,//JSON.stringify(args.request_params),
		beforeSend: function (xhr) {
			xhr.setRequestHeader(generateAuthHeader(args.creds));
		},
		success: on_success,
		error: console.err(err),
		complete: on_complete,
	});

	function on_success (response, textStatus, jqXHR) {
		console.log("log: on_success: " + textStatus);

		data = JSON.parse(response);

		if (data.status === "success") {
			// TODO check if payload prop
			args.on_success(data.payload);
		} else {
			// TODO exception definitions
			args.on_failure(textStatus, data.exception);
		}
	}

	function on_failure (jqXHR, textStatus, errorThrown) {
		console.log("log: on_failure: " + textStatus);

		if (args.on_failure) {
			args.on_failure(textStatus, errorThrown);
		} else {
			// Do nothing
		}
	}

	function on_complete (jqXHR, textStatus) {
		console.log("log: on_complete: " + textStatus);

		if (args.on_complete) {
			args.on_complete(jqXHR, textStatus);
		} else {
			// Do nothing
		}
	}
	return false;
}

/**
 * Login form ajax callback
 * TODO session management handled here?
 */
function loginSuccess(login_response) {
	$("h2#options_welcome_banner strong").text(login_response.payload);
	$.mobile.changePage($("#options_page"), {
		transition: "slideup",
		reverse: true,
	});
}

/**
 * DB Dialog ajax success callback
 */
function popDBDialog(response) {
	$("#response").text("Success! New school added!");
	$.mobile.changePage("#db_confirm_dialog");
}

/**
 * School List response handler
 * generates ul of schools returned from DB
 */
function generateSchoolList(school_data) {
	var schools_html = [];

	for (school in school_data) {
		school = school_data[school];
		var button = 'Edit This School';

		var block = '

' +
			school.name + '

Phone: ' +
			school.phone + '

Address: ' +
			school.address + '
' + button + '
';
		schools_html.push(block);
	}

	$('div#school_list').html(schools_html.join(''));

	$('div#school_list').on('click', 'a.edit_school', function (e) {
		var index = $(this).attr("ks_school_id");
		var school = school_data[index];
		$.each($("form#edit_school_form input"), function() {
			var key = $(this).attr("name");
			$(this).attr("value", school[key]);
		});
		editSchoolEntity(school);
	});
	$.mobile.changePage($("#school_list_page"));
};

function editSchoolEntity(school) {
	$("#edit_school_form").on("submit", function (e) {
		var form_data = $("#edit_school_form").serializeObject();
		if( !form_data.id){
			form_data.id = school.id;
		}

		service_call("app_dev.php/update_school", {
			request_params: form_data,
			on_success: function () {$.mobile.changePage("#school_list_page")}
		});

		return false;
	});

	$.mobile.changePage("#edit_school_dialog", {
		transistion: "pop"
	});

}

$(document).on("pageinit", function(e, obj) {
	/**
	 * Login form handler
	 */
	$("#login_page").on("submit", function(e, obj) {
		var args = {};
		args.creds = {
			user: $("#login_input").val(),
			password: $("#pass_input").val()
		};
		console.info("serialized obj", serializeObject(args.creds));

		service_call("app_dev/login", args);
		console.info('post service_call');

		return false;
	});

	/**
	 * Add school form ajax handler
	 */
	$('#add_school_submit').on('click', function(e, obj) {
		var  formData = $('#add_school_form').serializeObject();

		service_call("app_dev.php/add_school", {
			request_params: formData,
			on_success: popDBDialog
		});

		return false;
	});
});

/**
 * Get school list ajax handler
 */
$(document).on("pagebeforechange", function(e, obj) {
	var url= $.mobile.path.parseUrl(obj.toPage);

	if ( url.hash  === "#school_list_page") {
		service_call("app_dev.php/get_school_list", {
			on_success: generateSchoolList
		});

		e.preventDefault();
	};
});

<|endoftext|>