<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

const gulp = require('gulp');
const filter = require('gulp-filter');
const es = require('event-stream');
const gulpeslint = require('gulp-eslint');
const tsfmt = require('typescript-formatter');
const VinylFile = require('vinyl');
const vfs = require('vinyl-fs');
const path = require('path');
const fs = require('fs');
const pall = require('p-all');
const task = require('./lib/task');

/**
 * Hygiene works by creating cascading subsets of all our files and
 * passing them through a sequence of checks. Here are the current subsets,
 * named according to the checks performed on them. Each subset contains
 * the following one, as described in mathematical notation:
 *
 * all ⊃ eol ⊇ indentation ⊃ copyright ⊃ typescript
 */

const all = [
	'*',
	'build/**/*',
	'extensions/**/*',
	'scripts/**/*',
	'src/**/*',
	'test/**/*',
	'!**/node_modules/**'
];

const indentationFilter = [
	'**',

	// except specific files
	'!ThirdPartyNotices.txt',
	'!LICENSE.{txt,rtf}',
	'!LICENSES.chromium.html',
	'!**/LICENSE',
	'!src/vs/nls.js',
	'!src/vs/nls.build.js',
	'!src/vs/css.js',
	'!src/vs/css.build.js',
	'!src/vs/loader.js',
	'!src/vs/base/common/insane/insane.js',
	'!src/vs/base/common/marked/marked.js',
	'!src/vs/base/node/terminateProcess.sh',
	'!src/vs/base/node/cpuUsage.sh',
	'!test/assert.js',

	// except specific folders
	'!test/automation/out/**',
	'!test/smoke/out/**',
	'!extensions/vscode-api-tests/testWorkspace/**',
	'!extensions/vscode-api-tests/testWorkspace2/**',
	'!build/monaco/**',
	'!build/win32/**',

	// except multiple specific files
	'!**/package.json',
	'!**/yarn.lock',
	'!**/yarn-error.log',

	// except multiple specific folders
	'!**/codicon/**',
	'!**/fixtures/**',
	'!**/lib/**',
	'!extensions/**/out/**',
	'!extensions/**/snippets/**',
	'!extensions/**/syntaxes/**',
	'!extensions/**/themes/**',
	'!extensions/**/colorize-fixtures/**',

	// except specific file types
	'!src/vs/*/**/*.d.ts',
	'!src/typings/**/*.d.ts',
	'!extensions/**/*.d.ts',
	'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot,md,ps1,template,yaml,yml,d.ts.recipe,ico,icns}',
	'!build/{lib,download}/**/*.js',
	'!build/**/*.sh',
	'!build/azure-pipelines/**/*.js',
	'!build/azure-pipelines/**/*.config',
	'!**/Dockerfile',
	'!**/Dockerfile.*',
	'!**/*.Dockerfile',
	'!**/*.dockerfile',
	'!extensions/markdown-language-features/media/*.js'
];

const copyrightFilter = [
	'**',
	'!**/*.desktop',
	'!**/*.json',
	'!**/*.html',
	'!**/*.template',
	'!**/*.md',
	'!**/*.bat',
	'!**/*.cmd',
	'!**/*.ico',
	'!**/*.icns',
	'!**/*.xml',
	'!**/*.sh',
	'!**/*.txt',
	'!**/*.xpm',
	'!**/*.opts',
	'!**/*.disabled',
	'!**/*.code-workspace',
	'!**/*.js.map',
	'!**/promise-polyfill/polyfill.js',
	'!build/**/*.init',
	'!resources/linux/snap/snapcraft.yaml',
	'!resources/linux/snap/electron-launch',
	'!resources/win32/bin/code.js',
	'!resources/completions/**',
	'!extensions/markdown-language-features/media/highlight.css',
	'!extensions/html-language-features/server/src/modes/typescript/*',
	'!extensions/*/server/bin/*',
	'!src/vs/editor/test/node/classification/typescript-test.ts',
	'!scripts/code-web.js'
];

const jsHygieneFilter = [
	'src/**/*.js',
	'build/gulpfile.*.js',
	'!src/vs/loader.js',
	'!src/vs/css.js',
	'!src/vs/nls.js',
	'!src/vs/css.build.js',
	'!src/vs/nls.build.js',
	'!src/**/insane.js',
	'!src/**/marked.js',
	'!**/test/**'
];

const tsHygieneFilter = [
	'src/**/*.ts',
	'test/**/*.ts',
	'extensions/**/*.ts',
	'!**/fixtures/**',
	'!**/typings/**',
	'!**/node_modules/**',
	'!extensions/typescript-basics/test/colorize-fixtures/**',
	'!extensions/vscode-api-tests/testWorkspace/**',
	'!extensions/vscode-api-tests/testWorkspace2/**',
	'!extensions/**/*.test.ts',
	'!extensions/html-language-features/server/lib/jquery.d.ts'
];

const copyrightHeaderLines = [
	'/*---------------------------------------------------------------------------------------------',
	' *  Copyright (c) Microsoft Corporation. All rights reserved.',
	' *  Licensed under the MIT License. See License.txt in the project root for license information.',
	' *--------------------------------------------------------------------------------------------*/'
];

gulp.task('eslint', () => {
	return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
		.pipe(filter(jsHygieneFilter.concat(tsHygieneFilter)))
		.pipe(gulpeslint({
			configFile: '.eslintrc.json',
			rulePaths: ['./build/lib/eslint']
		}))
		.pipe(gulpeslint.formatEach('compact'))
		.pipe(gulpeslint.results(results => {
			if (results.warningCount > 0 || results.errorCount > 0) {
				throw new Error('eslint failed with warnings and/or errors');
			}
		}));
});

function checkPackageJSON(actualPath) {
	const actual = require(path.join(__dirname, '..', actualPath));
	const rootPackageJSON = require('../package.json');

	for (let depName in actual.dependencies) {
		const depVersion = actual.dependencies[depName];
		const rootDepVersion = rootPackageJSON.dependencies[depName];
		if (!rootDepVersion) {
			// missing in root is allowed
			continue;
		}
		if (depVersion !== rootDepVersion) {
			this.emit('error', `The dependency ${depName} in '${actualPath}' (${depVersion}) is different than in the root package.json (${rootDepVersion})`);
		}
	}
}

const checkPackageJSONTask = task.define('check-package-json', () => {
	return gulp.src('package.json')
		.pipe(es.through(function () {
			checkPackageJSON.call(this, 'remote/package.json');
			checkPackageJSON.call(this, 'remote/web/package.json');
		}));
});
gulp.task(checkPackageJSONTask);

function hygiene(some) {
	let errorCount = 0;

	const productJson = es.through(function (file) {
		const product = JSON.parse(file.contents.toString('utf8'));

		if (product.extensionsGallery) {
			console.error('product.json: Contains "extensionsGallery"');
			errorCount++;
		}

		this.emit('data', file);
	});

	const indentation = es.through(function (file) {
		const lines = file.contents.toString('utf8').split(/\r\n|\r|\n/);
		file.__lines = lines;

		lines
			.forEach((line, i) => {
				if (/^\s*$/.test(line)) {
					// empty or whitespace lines are OK
				} else if (/^[\t]*[^\s]/.test(line)) {
					// good indent
				} else if (/^[\t]* \*/.test(line)) {
					// block comment using an extra space
				} else {
					console.error(file.relative + '(' + (i + 1) + ',1): Bad whitespace indentation');
					errorCount++;
				}
			});

		this.emit('data', file);
	});

	const copyrights = es.through(function (file) {
		const lines = file.__lines;

		for (let i = 0; i < copyrightHeaderLines.length; i++) {
			if (lines[i] !== copyrightHeaderLines[i]) {
				console.error(file.relative + ': Missing or bad copyright statement');
				errorCount++;
				break;
			}
		}

		this.emit('data', file);
	});

	const formatting = es.map(function (file, cb) {
		tsfmt.processString(file.path, file.contents.toString('utf8'), {
			verify: false,
			tsfmt: true,
			// verbose: true,
			// keep checkJS happy
			editorconfig: undefined,
			replace: undefined,
			tsconfig: undefined,
			tsconfigFile: undefined,
			tsfmtFile: undefined,
			vscode: undefined,
			vscodeFile: undefined
		}).then(result => {
			let original = result.src.replace(/\r\n/gm, '\n');
			let formatted = result.dest.replace(/\r\n/gm, '\n');

			if (original !== formatted) {
				console.error('File not formatted. Run the \'Format Document\' command to fix it:', file.relative);
				errorCount++;
			}
			cb(null, file);

		}, err => {
			cb(err);
		});
	});

	let input;

	if (Array.isArray(some) || typeof some === 'string' || !some) {
		const options = { base: '.', follow: true, allowEmpty: true };
		if (some) {
			input = vfs.src(some, options).pipe(filter(all)); // split this up to not unnecessarily filter all a second time
		} else {
			input = vfs.src(all, options);
		}
	} else {
		input = some;
	}

	const productJsonFilter = filter('product.json', { restore: true });

	const result = input
		.pipe(filter(f => !f.stat.isDirectory()))
		.pipe(productJsonFilter)
		.pipe(process.env['BUILD_SOURCEVERSION'] ? es.through() : productJson)
		.pipe(productJsonFilter.restore)
		.pipe(filter(indentationFilter))
		.pipe(indentation)
		.pipe(filter(copyrightFilter))
		.pipe(copyrights);

	const typescript = result
		.pipe(filter(tsHygieneFilter))
		.pipe(formatting);

	const javascript = result
		.pipe(filter(jsHygieneFilter.concat(tsHygieneFilter)))
		.pipe(gulpeslint({
			configFile: '.eslintrc.json',
			rulePaths: ['./build/lib/eslint']
		}))
		.pipe(gulpeslint.formatEach('compact'))
		.pipe(gulpeslint.results(results => {
			errorCount += results.warningCount;
			errorCount += results.errorCount;
		}));

	let count = 0;
	return es.merge(typescript, javascript)
		.pipe(es.through(function (data) {
			count++;
			if (process.env['TRAVIS'] && count % 10 === 0) {
				process.stdout.write('.');
			}
			this.emit('data', data);
		}, function () {
			process.stdout.write('\n');
			if (errorCount > 0) {
				this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.');
			} else {
				this.emit('end');
			}
		}));
}

function createGitIndexVinyls(paths) {
	const cp = require('child_process');
	const repositoryPath = process.cwd();

	const fns = paths.map(relativePath => () => new Promise((c, e) => {
		const fullPath = path.join(repositoryPath, relativePath);

		fs.stat(fullPath, (err, stat) => {
			if (err && err.code === 'ENOENT') { // ignore deletions
				return c(null);
			} else if (err) {
				return e(err);
			}

			cp.exec(`git show :${relativePath}`, { maxBuffer: 2000 * 1024, encoding: 'buffer' }, (err, out) => {
				if (err) {
					return e(err);
				}

				c(new VinylFile({
					path: fullPath,
					base: repositoryPath,
					contents: out,
					stat
				}));
			});
		});
	}));

	return pall(fns, { concurrency: 4 })
		.then(r => r.filter(p => !!p));
}

gulp.task('hygiene', task.series(checkPackageJSONTask, () => hygiene()));

// this allows us to run hygiene as a git pre-commit hook
if (require.main === module) {
	const cp = require('child_process');

	process.on('unhandledRejection', (reason, p) => {
		console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
		process.exit(1);
	});

	if (process.argv.length > 2) {
		hygiene(process.argv.slice(2)).on('error', err => {
			console.error();
			console.error(err);
			process.exit(1);
		});
	} else {
		cp.exec('git diff --cached --name-only', { maxBuffer: 2000 * 1024 }, (err, out) => {
			if (err) {
				console.error();
				console.error(err);
				process.exit(1);
				return;
			}

			const some = out
				.split(/\r?\n/)
				.filter(l => !!l);

			if (some.length > 0) {
				console.log('Reading git index versions...');

				createGitIndexVinyls(some)
					.then(vinyls => new Promise((c, e) => hygiene(es.readArray(vinyls))
						.on('end', () => c())
						.on('error', e)))
					.catch(err => {
						console.error();
						console.error(err);
						process.exit(1);
					});
			}
		});
	}
}
<commit_msg>Fix hygiene glob<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

const gulp = require('gulp');
const filter = require('gulp-filter');
const es = require('event-stream');
const gulpeslint = require('gulp-eslint');
const tsfmt = require('typescript-formatter');
const VinylFile = require('vinyl');
const vfs = require('vinyl-fs');
const path = require('path');
const fs = require('fs');
const pall = require('p-all');
const task = require('./lib/task');

/**
 * Hygiene works by creating cascading subsets of all our files and
 * passing them through a sequence of checks. Here are the current subsets,
 * named according to the checks performed on them. Each subset contains
 * the following one, as described in mathematical notation:
 *
 * all ⊃ eol ⊇ indentation ⊃ copyright ⊃ typescript
 */

const all = [
	'*',
	'build/**/*',
	'extensions/**/*',
	'scripts/**/*',
	'src/**/*',
	'test/**/*',
	'!**/node_modules/**'
];

const indentationFilter = [
	'**',

	// except specific files
	'!ThirdPartyNotices.txt',
	'!LICENSE.{txt,rtf}',
	'!LICENSES.chromium.html',
	'!**/LICENSE',
	'!src/vs/nls.js',
	'!src/vs/nls.build.js',
	'!src/vs/css.js',
	'!src/vs/css.build.js',
	'!src/vs/loader.js',
	'!src/vs/base/common/insane/insane.js',
	'!src/vs/base/common/marked/marked.js',
	'!src/vs/base/node/terminateProcess.sh',
	'!src/vs/base/node/cpuUsage.sh',
	'!test/unit/assert.js',

	// except specific folders
	'!test/automation/out/**',
	'!test/smoke/out/**',
	'!extensions/vscode-api-tests/testWorkspace/**',
	'!extensions/vscode-api-tests/testWorkspace2/**',
	'!build/monaco/**',
	'!build/win32/**',

	// except multiple specific files
	'!**/package.json',
	'!**/yarn.lock',
	'!**/yarn-error.log',

	// except multiple specific folders
	'!**/codicon/**',
	'!**/fixtures/**',
	'!**/lib/**',
	'!extensions/**/out/**',
	'!extensions/**/snippets/**',
	'!extensions/**/syntaxes/**',
	'!extensions/**/themes/**',
	'!extensions/**/colorize-fixtures/**',

	// except specific file types
	'!src/vs/*/**/*.d.ts',
	'!src/typings/**/*.d.ts',
	'!extensions/**/*.d.ts',
	'!**/*.{svg,exe,png,bmp,scpt,bat,cmd,cur,ttf,woff,eot,md,ps1,template,yaml,yml,d.ts.recipe,ico,icns}',
	'!build/{lib,download}/**/*.js',
	'!build/**/*.sh',
	'!build/azure-pipelines/**/*.js',
	'!build/azure-pipelines/**/*.config',
	'!**/Dockerfile',
	'!**/Dockerfile.*',
	'!**/*.Dockerfile',
	'!**/*.dockerfile',
	'!extensions/markdown-language-features/media/*.js'
];

const copyrightFilter = [
	'**',
	'!**/*.desktop',
	'!**/*.json',
	'!**/*.html',
	'!**/*.template',
	'!**/*.md',
	'!**/*.bat',
	'!**/*.cmd',
	'!**/*.ico',
	'!**/*.icns',
	'!**/*.xml',
	'!**/*.sh',
	'!**/*.txt',
	'!**/*.xpm',
	'!**/*.opts',
	'!**/*.disabled',
	'!**/*.code-workspace',
	'!**/*.js.map',
	'!**/promise-polyfill/polyfill.js',
	'!build/**/*.init',
	'!resources/linux/snap/snapcraft.yaml',
	'!resources/linux/snap/electron-launch',
	'!resources/win32/bin/code.js',
	'!resources/completions/**',
	'!extensions/markdown-language-features/media/highlight.css',
	'!extensions/html-language-features/server/src/modes/typescript/*',
	'!extensions/*/server/bin/*',
	'!src/vs/editor/test/node/classification/typescript-test.ts',
	'!scripts/code-web.js'
];

const jsHygieneFilter = [
	'src/**/*.js',
	'build/gulpfile.*.js',
	'!src/vs/loader.js',
	'!src/vs/css.js',
	'!src/vs/nls.js',
	'!src/vs/css.build.js',
	'!src/vs/nls.build.js',
	'!src/**/insane.js',
	'!src/**/marked.js',
	'!**/test/**'
];

const tsHygieneFilter = [
	'src/**/*.ts',
	'test/**/*.ts',
	'extensions/**/*.ts',
	'!**/fixtures/**',
	'!**/typings/**',
	'!**/node_modules/**',
	'!extensions/typescript-basics/test/colorize-fixtures/**',
	'!extensions/vscode-api-tests/testWorkspace/**',
	'!extensions/vscode-api-tests/testWorkspace2/**',
	'!extensions/**/*.test.ts',
	'!extensions/html-language-features/server/lib/jquery.d.ts'
];

const copyrightHeaderLines = [
	'/*---------------------------------------------------------------------------------------------',
	' *  Copyright (c) Microsoft Corporation. All rights reserved.',
	' *  Licensed under the MIT License. See License.txt in the project root for license information.',
	' *--------------------------------------------------------------------------------------------*/'
];

gulp.task('eslint', () => {
	return vfs.src(all, { base: '.', follow: true, allowEmpty: true })
		.pipe(filter(jsHygieneFilter.concat(tsHygieneFilter)))
		.pipe(gulpeslint({
			configFile: '.eslintrc.json',
			rulePaths: ['./build/lib/eslint']
		}))
		.pipe(gulpeslint.formatEach('compact'))
		.pipe(gulpeslint.results(results => {
			if (results.warningCount > 0 || results.errorCount > 0) {
				throw new Error('eslint failed with warnings and/or errors');
			}
		}));
});

function checkPackageJSON(actualPath) {
	const actual = require(path.join(__dirname, '..', actualPath));
	const rootPackageJSON = require('../package.json');

	for (let depName in actual.dependencies) {
		const depVersion = actual.dependencies[depName];
		const rootDepVersion = rootPackageJSON.dependencies[depName];
		if (!rootDepVersion) {
			// missing in root is allowed
			continue;
		}
		if (depVersion !== rootDepVersion) {
			this.emit('error', `The dependency ${depName} in '${actualPath}' (${depVersion}) is different than in the root package.json (${rootDepVersion})`);
		}
	}
}

const checkPackageJSONTask = task.define('check-package-json', () => {
	return gulp.src('package.json')
		.pipe(es.through(function () {
			checkPackageJSON.call(this, 'remote/package.json');
			checkPackageJSON.call(this, 'remote/web/package.json');
		}));
});
gulp.task(checkPackageJSONTask);

function hygiene(some) {
	let errorCount = 0;

	const productJson = es.through(function (file) {
		const product = JSON.parse(file.contents.toString('utf8'));

		if (product.extensionsGallery) {
			console.error('product.json: Contains "extensionsGallery"');
			errorCount++;
		}

		this.emit('data', file);
	});

	const indentation = es.through(function (file) {
		const lines = file.contents.toString('utf8').split(/\r\n|\r|\n/);
		file.__lines = lines;

		lines
			.forEach((line, i) => {
				if (/^\s*$/.test(line)) {
					// empty or whitespace lines are OK
				} else if (/^[\t]*[^\s]/.test(line)) {
					// good indent
				} else if (/^[\t]* \*/.test(line)) {
					// block comment using an extra space
				} else {
					console.error(file.relative + '(' + (i + 1) + ',1): Bad whitespace indentation');
					errorCount++;
				}
			});

		this.emit('data', file);
	});

	const copyrights = es.through(function (file) {
		const lines = file.__lines;

		for (let i = 0; i < copyrightHeaderLines.length; i++) {
			if (lines[i] !== copyrightHeaderLines[i]) {
				console.error(file.relative + ': Missing or bad copyright statement');
				errorCount++;
				break;
			}
		}

		this.emit('data', file);
	});

	const formatting = es.map(function (file, cb) {
		tsfmt.processString(file.path, file.contents.toString('utf8'), {
			verify: false,
			tsfmt: true,
			// verbose: true,
			// keep checkJS happy
			editorconfig: undefined,
			replace: undefined,
			tsconfig: undefined,
			tsconfigFile: undefined,
			tsfmtFile: undefined,
			vscode: undefined,
			vscodeFile: undefined
		}).then(result => {
			let original = result.src.replace(/\r\n/gm, '\n');
			let formatted = result.dest.replace(/\r\n/gm, '\n');

			if (original !== formatted) {
				console.error('File not formatted. Run the \'Format Document\' command to fix it:', file.relative);
				errorCount++;
			}
			cb(null, file);

		}, err => {
			cb(err);
		});
	});

	let input;

	if (Array.isArray(some) || typeof some === 'string' || !some) {
		const options = { base: '.', follow: true, allowEmpty: true };
		if (some) {
			input = vfs.src(some, options).pipe(filter(all)); // split this up to not unnecessarily filter all a second time
		} else {
			input = vfs.src(all, options);
		}
	} else {
		input = some;
	}

	const productJsonFilter = filter('product.json', { restore: true });

	const result = input
		.pipe(filter(f => !f.stat.isDirectory()))
		.pipe(productJsonFilter)
		.pipe(process.env['BUILD_SOURCEVERSION'] ? es.through() : productJson)
		.pipe(productJsonFilter.restore)
		.pipe(filter(indentationFilter))
		.pipe(indentation)
		.pipe(filter(copyrightFilter))
		.pipe(copyrights);

	const typescript = result
		.pipe(filter(tsHygieneFilter))
		.pipe(formatting);

	const javascript = result
		.pipe(filter(jsHygieneFilter.concat(tsHygieneFilter)))
		.pipe(gulpeslint({
			configFile: '.eslintrc.json',
			rulePaths: ['./build/lib/eslint']
		}))
		.pipe(gulpeslint.formatEach('compact'))
		.pipe(gulpeslint.results(results => {
			errorCount += results.warningCount;
			errorCount += results.errorCount;
		}));

	let count = 0;
	return es.merge(typescript, javascript)
		.pipe(es.through(function (data) {
			count++;
			if (process.env['TRAVIS'] && count % 10 === 0) {
				process.stdout.write('.');
			}
			this.emit('data', data);
		}, function () {
			process.stdout.write('\n');
			if (errorCount > 0) {
				this.emit('error', 'Hygiene failed with ' + errorCount + ' errors. Check \'build/gulpfile.hygiene.js\'.');
			} else {
				this.emit('end');
			}
		}));
}

function createGitIndexVinyls(paths) {
	const cp = require('child_process');
	const repositoryPath = process.cwd();

	const fns = paths.map(relativePath => () => new Promise((c, e) => {
		const fullPath = path.join(repositoryPath, relativePath);

		fs.stat(fullPath, (err, stat) => {
			if (err && err.code === 'ENOENT') { // ignore deletions
				return c(null);
			} else if (err) {
				return e(err);
			}

			cp.exec(`git show :${relativePath}`, { maxBuffer: 2000 * 1024, encoding: 'buffer' }, (err, out) => {
				if (err) {
					return e(err);
				}

				c(new VinylFile({
					path: fullPath,
					base: repositoryPath,
					contents: out,
					stat
				}));
			});
		});
	}));

	return pall(fns, { concurrency: 4 })
		.then(r => r.filter(p => !!p));
}

gulp.task('hygiene', task.series(checkPackageJSONTask, () => hygiene()));

// this allows us to run hygiene as a git pre-commit hook
if (require.main === module) {
	const cp = require('child_process');

	process.on('unhandledRejection', (reason, p) => {
		console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
		process.exit(1);
	});

	if (process.argv.length > 2) {
		hygiene(process.argv.slice(2)).on('error', err => {
			console.error();
			console.error(err);
			process.exit(1);
		});
	} else {
		cp.exec('git diff --cached --name-only', { maxBuffer: 2000 * 1024 }, (err, out) => {
			if (err) {
				console.error();
				console.error(err);
				process.exit(1);
				return;
			}

			const some = out
				.split(/\r?\n/)
				.filter(l => !!l);

			if (some.length > 0) {
				console.log('Reading git index versions...');

				createGitIndexVinyls(some)
					.then(vinyls => new Promise((c, e) => hygiene(es.readArray(vinyls))
						.on('end', () => c())
						.on('error', e)))
					.catch(err => {
						console.error();
						console.error(err);
						process.exit(1);
					});
			}
		});
	}
}
<|endoftext|>


<commit_before>
var Class = require('../../utils/Class');
var GameObject = require('../GameObject');
var Components = require('../components');
var Render = require('./LightLayerRender');
var Light = require('./Light');
var SpriteNormalPair = require('./SpriteNormalPair');
var WebGLSupportedExtensions = require('../../renderer/webgl/WebGLSupportedExtensions');
var TexturedAndNormalizedTintedShader = require('../../renderer/webgl/shaders/TexturedAndNormalizedTintedShader');
var Const = require('./Const');
var Matrix = require('../components/TransformMatrix');
var TempMatrix = new Matrix();

// http://cpetry.github.io/NormalMap-Online/

var LightLayer = new Class({

    Extends: GameObject,

    Mixins: [
        Components.Alpha,
        Components.BlendMode,
        Components.Origin,
        Components.RenderTarget,
        Components.ScrollFactor,
        Components.Visible,
        Render
    ],

    initialize:

    function LightLayer (scene)
    {
        GameObject.call(this, scene, 'LightLayer');

        var resourceManager = scene.game.renderer.resourceManager;
        var deferred = WebGLSupportedExtensions.has('WEBGL_draw_buffers');

        this.renderer = scene.game.renderer;
        this.passShader = null;
        this.gl = null;
        this.ambientLightColorR = 0.0;
        this.ambientLightColorG = 0.0;
        this.ambientLightColorB = 0.0;
        this.lightPool = [];
        this.spritePool = [];
        this.lights = [];
        this.sprites = [];
        this.lightsLocations = [];
        this._z = 0;

        if (resourceManager !== undefined && !deferred)
        {
            this.gl = scene.game.renderer.gl;
            this.passShader = resourceManager.createShader('Phong2DShaderForward', {vert: TexturedAndNormalizedTintedShader.vert, frag: `
                precision mediump float;

                struct Light
                {
                    vec3 position;
                    vec3 color;
                    float attenuation;
                };

                uniform vec2 uResolution;
                uniform sampler2D uMainTexture;
                uniform sampler2D uNormTexture;
                uniform vec3 uAmbientLightColor;
                uniform Light uLights[` + Const.MAX_LIGHTS + `];

                varying vec2 v_tex_coord;
                varying vec3 v_color;
                varying float v_alpha;

                void main()
                {
                    vec3 finalColor = vec3(0.0, 0.0, 0.0);
                    vec4 spriteColor = texture2D(uMainTexture, v_tex_coord) * vec4(v_color, v_alpha);
                    vec3 spriteNormal = texture2D(uNormTexture, v_tex_coord).rgb;
                    vec3 normal = normalize(vec3(spriteNormal * 2.0 - 1.0));

                    for (int index = 0; index < ` + Const.MAX_LIGHTS + `; ++index)
                    {
                        Light light = uLights[index];
                        float lightY = uResolution.y - light.position.y;
                        vec3 lightDir = vec3((vec2(light.position.x, lightY) / uResolution) - (gl_FragCoord.xy / uResolution), light.position.z);
                        vec3 lightNormal = normalize(lightDir);
                        float distToSurf = length(lightDir);
                        float diffuseFactor = max(dot(normal, lightNormal), 0.0);
                        float attenuation = 1.0 / (1.0 + light.attenuation * (distToSurf * distToSurf));
                        vec3 diffuse = light.color * spriteColor.rgb * diffuseFactor;
                        finalColor += attenuation * diffuse;
                    }

                    gl_FragColor = vec4(uAmbientLightColor + finalColor, spriteColor.a);
                }
            `});
            this.ambientLightColorLoc = this.passShader.getUniformLocation('uAmbientLightColor');
            this.uMainTextureLoc = this.passShader.getUniformLocation('uMainTexture');
            this.uNormTextureLoc = this.passShader.getUniformLocation('uNormTexture');
            this.uResolutionLoc = this.passShader.getUniformLocation('uResolution');

            this.passShader.setConstantInt1(this.uMainTextureLoc, 0);
            this.passShader.setConstantInt1(this.uNormTextureLoc, 1);

            for (var index = 0; index < Const.MAX_LIGHTS; ++index)
            {
                this.lightsLocations[index] = {
                    position: this.passShader.getUniformLocation('uLights[' + index + '].position'),
                    color: this.passShader.getUniformLocation('uLights[' + index + '].color'),
                    attenuation: this.passShader.getUniformLocation('uLights[' + index + '].attenuation')
                };
            }
        }
        else
        {
            Const.MAX_LIGHTS = 100;
            var gl = this.gl = scene.game.renderer.gl;
            this.ext = scene.game.renderer.getExtension('WEBGL_draw_buffers');
            this.gBufferShaderPass = resourceManager.createShader('GBufferShader', {vert: TexturedAndNormalizedTintedShader.vert, frag: `
                #extension GL_EXT_draw_buffers : require

                precision mediump float;

                uniform vec2 uResolution;
                uniform sampler2D uMainTexture;
                uniform sampler2D uNormTexture;

                varying vec2 v_tex_coord;
                varying vec3 v_color;
                varying float v_alpha;

                void main()
                {
                    vec4 spriteColor = texture2D(uMainTexture, v_tex_coord) * vec4(v_color, v_alpha);
                    vec3 spriteNormal = texture2D(uNormTexture, v_tex_coord).rgb;

                    gl_FragData[0] = spriteColor;
                    gl_FragData[1] = vec4(spriteNormal, spriteColor.a);
                }
            `});
            this.lightPassShader = resourceManager.createShader('Phong2DShaderDeferred', {
                vert: `
                precision mediump float;
                attribute vec2 vertexPosition;
                void main()
                {
                    gl_Position = vec4(vertexPosition, 0.0, 1.0);
                }
                `,
                frag: `
                precision mediump float;

                struct Light
                {
                    vec3 position;
                    vec3 color;
                    float attenuation;
                };

                uniform vec2 uResolution;
                uniform sampler2D uGbufferColor;
                uniform sampler2D uGbufferNormal;
                uniform vec3 uAmbientLightColor;
                uniform Light uLights[` + Const.MAX_LIGHTS + `];

                void main()
                {
                    vec2 uv = vec2(gl_FragCoord.xy / uResolution);
                    vec3 finalColor = vec3(0.0, 0.0, 0.0);
                    vec4 gbColor = texture2D(uGbufferColor, uv);
                    vec3 gbNormal = texture2D(uGbufferNormal, uv).rgb;
                    vec3 normal = normalize(vec3(gbNormal * 2.0 - 1.0));

                    for (int index = 0; index < ` + Const.MAX_LIGHTS + `; ++index)
                    {
                        Light light = uLights[index];
                        float lightY = uResolution.y - light.position.y;
                        vec3 lightDir = vec3((vec2(light.position.x, lightY) / uResolution) - uv, light.position.z);
                        vec3 lightNormal = normalize(lightDir);
                        float distToSurf = length(lightDir);
                        float diffuseFactor = max(dot(normal, lightNormal), 0.0);
                        float attenuation = 1.0 / (1.0 + light.attenuation * (distToSurf * distToSurf));
                        vec3 diffuse = light.color * gbColor.rgb * diffuseFactor;
                        finalColor += attenuation * diffuse;
                    }

                    gl_FragColor = vec4(uAmbientLightColor + finalColor, gbColor.a);
                }
            `});
            this.lightPassVBO = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, this.lightPassVBO);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, 7, -1, -1, 7, -1]), gl.STATIC_DRAW);

            this.uMainTextureLoc = this.gBufferShaderPass.getUniformLocation('uMainTexture');
            this.uNormTextureLoc = this.gBufferShaderPass.getUniformLocation('uNormTexture');

            this.gBufferShaderPass.setConstantInt1(this.uMainTextureLoc, 0);
            this.gBufferShaderPass.setConstantInt1(this.uNormTextureLoc, 1);

            this.ambientLightColorLoc = this.lightPassShader.getUniformLocation('uAmbientLightColor');
            this.uResolutionLoc = this.lightPassShader.getUniformLocation('uResolution');
            this.uGbufferColorLoc = this.lightPassShader.getUniformLocation('uGbufferColor');
            this.uGbufferNormalLoc = this.lightPassShader.getUniformLocation('uGbufferNormal');

            this.lightPassShader.setConstantInt1(this.uGbufferColorLoc, 0);
            this.lightPassShader.setConstantInt1(this.uGbufferNormalLoc, 1);

            this.gBufferShaderPass.bindAttribLocation(0, 'v_tex_coord');
            this.gBufferShaderPass.bindAttribLocation(1, 'v_color');
            this.gBufferShaderPass.bindAttribLocation(2, 'v_alpha');
            this.lightPassShader.bindAttribLocation(0, 'vertexPosition');

            for (var index = 0; index < Const.MAX_LIGHTS; ++index)
            {
                this.lightsLocations[index] = {
                    position: this.lightPassShader.getUniformLocation('uLights[' + index + '].position'),
                    color: this.lightPassShader.getUniformLocation('uLights[' + index + '].color'),
                    attenuation: this.lightPassShader.getUniformLocation('uLights[' + index + '].attenuation')
                };
            }

            /* Setup render targets */
            this.gBufferFbo = gl.createFramebuffer();
            this.gBufferColorTex = gl.createTexture();
            this.gBufferNormalTex = gl.createTexture();

            gl.bindFramebuffer(gl.FRAMEBUFFER, this.gBufferFbo);
            gl.bindTexture(gl.TEXTURE_2D, this.gBufferColorTex);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, scene.game.renderer.width, scene.game.renderer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

            gl.bindTexture(gl.TEXTURE_2D, this.gBufferNormalTex);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, scene.game.renderer.width, scene.game.renderer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

            gl.framebufferTexture2D(gl.FRAMEBUFFER, this.ext.COLOR_ATTACHMENT0_WEBGL, gl.TEXTURE_2D, this.gBufferColorTex, 0);
            gl.framebufferTexture2D(gl.FRAMEBUFFER, this.ext.COLOR_ATTACHMENT1_WEBGL, gl.TEXTURE_2D, this.gBufferNormalTex, 0);

            this.ext.drawBuffersWEBGL([this.ext.COLOR_ATTACHMENT0_WEBGL, this.ext.COLOR_ATTACHMENT1_WEBGL]);

            var complete = gl.checkFramebufferStatus(gl.FRAMEBUFFER);

            if (complete !== gl.FRAMEBUFFER_COMPLETE)
            {
                var errors = {
                    36054: 'Incomplete Attachment',
                    36055: 'Missing Attachment',
                    36057: 'Incomplete Dimensions',
                    36061: 'Framebuffer Unsupported'
                };
                throw new Error('Framebuffer incomplete. Framebuffer status: ' + errors[complete]);
            }

            gl.bindFramebuffer(gl.FRAMEBUFFER, null);
        }

        this.setOrigin(0, 0);
    },

    get z()
    {
        return this._z;
    },

    set z(newZ)
    {
        this._z = newZ;
    },

    setAmbientLightColor: function (r, g, b)
    {
        this.ambientLightColorR = r;
        this.ambientLightColorG = g;
        this.ambientLightColorB = b;
    },

    getMaxLights: function ()
    {
        return Const.MAX_LIGHTS;
    },

    getLightCount: function ()
    {
        return this.lights.length;
    },

    isDeferred: function ()
    {
        return WebGLSupportedExtensions.has('WEBGL_draw_buffers');
    },

    /* This will probably be removed later */
    addSprite: function (sprite, normalTexture)
    {
        var spriteNormalPair;

        if (this.spritePool.length > 0)
        {
            spriteNormalPair = this.spritePool.pop();
            spriteNormalPair.set(sprite, normalTexture);
        }
        else
        {
            spriteNormalPair = new SpriteNormalPair(sprite, normalTexture);
        }
        this.scene.sys.displayList.remove(sprite);
        this.sprites.push(spriteNormalPair);
    },

    removeSprite: function (sprite)
    {
        var length = this.sprites.length;
        for (var index = 0; index < length; ++index)
        {
            if (this.sprites[index].spriteRef === sprite)
            {
                this.spritePool.push(this.sprites[index]);
                this.sprites.splice(index, 1);
                break;
            }
        }
        return sprite;
    },

    addLight: function (x, y, z, r, g, b, attenuation)
    {
        if (this.lights.length < Const.MAX_LIGHTS)
        {
            var light = null;
            if (this.lightPool.length > 0)
            {
                light = this.lightPool.pop();
                light.set(x, y, z, r, g, b, attenuation);
            }
            else
            {
                light = new Light(x, y, z, r, g, b, attenuation);
            }
            this.lights.push(light);
            return light;
        }
        return null;
    },

    removeLight: function (light)
    {
        var index = this.lights.indexOf(light);

        if (index >= 0)
        {
            this.lightPool.push(light);
            this.lights.splice(index, 1);
        }
    },

    updateLights: function(renderer, camera, shader)
    {
        if (this.gl !== null)
        {
            var locations = this.lightsLocations;
            var lights = this.lights;
            var length = lights.length;
            var gl = this.gl;
            var point = {x: 0, y: 0};

            shader.setConstantFloat2(this.uResolutionLoc, renderer.width, renderer.height);
            shader.setConstantFloat3(this.ambientLightColorLoc, this.ambientLightColorR, this.ambientLightColorG, this.ambientLightColorB);

            TempMatrix.applyITRS(camera.x, camera.y, camera.rotation, camera.zoom, camera.zoom);

            for (var index = 0; index < length; ++index)
            {
                var light = lights[index];
                TempMatrix.transformPoint(light.x, light.y, point);
                shader.setConstantFloat3(locations[index].position, point.x - (camera.scrollX * light.scrollFactorX), point.y - (camera.scrollY * light.scrollFactorY), light.z);
                shader.setConstantFloat3(locations[index].color, light.r, light.g, light.b);
                shader.setConstantFloat1(locations[index].attenuation, light.attenuation);
            }
        }
    }

});

module.exports = LightLayer;
<commit_msg>Light layer hardcoded max light count removed<commit_after>
var Class = require('../../utils/Class');
var GameObject = require('../GameObject');
var Components = require('../components');
var Render = require('./LightLayerRender');
var Light = require('./Light');
var SpriteNormalPair = require('./SpriteNormalPair');
var WebGLSupportedExtensions = require('../../renderer/webgl/WebGLSupportedExtensions');
var TexturedAndNormalizedTintedShader = require('../../renderer/webgl/shaders/TexturedAndNormalizedTintedShader');
var Const = require('./Const');
var Matrix = require('../components/TransformMatrix');
var TempMatrix = new Matrix();

// http://cpetry.github.io/NormalMap-Online/

var LightLayer = new Class({

    Extends: GameObject,

    Mixins: [
        Components.Alpha,
        Components.BlendMode,
        Components.Origin,
        Components.RenderTarget,
        Components.ScrollFactor,
        Components.Visible,
        Render
    ],

    initialize:

    function LightLayer (scene)
    {
        GameObject.call(this, scene, 'LightLayer');

        var resourceManager = scene.game.renderer.resourceManager;
        var deferred = WebGLSupportedExtensions.has('WEBGL_draw_buffers');

        this.renderer = scene.game.renderer;
        this.passShader = null;
        this.gl = null;
        this.ambientLightColorR = 0.0;
        this.ambientLightColorG = 0.0;
        this.ambientLightColorB = 0.0;
        this.lightPool = [];
        this.spritePool = [];
        this.lights = [];
        this.sprites = [];
        this.lightsLocations = [];
        this._z = 0;

        if (resourceManager !== undefined && !deferred)
        {
            this.gl = scene.game.renderer.gl;
            this.passShader = resourceManager.createShader('Phong2DShaderForward', {vert: TexturedAndNormalizedTintedShader.vert, frag: `
                precision mediump float;

                struct Light
                {
                    vec3 position;
                    vec3 color;
                    float attenuation;
                };

                uniform vec2 uResolution;
                uniform sampler2D uMainTexture;
                uniform sampler2D uNormTexture;
                uniform vec3 uAmbientLightColor;
                uniform Light uLights[` + Const.MAX_LIGHTS + `];

                varying vec2 v_tex_coord;
                varying vec3 v_color;
                varying float v_alpha;

                void main()
                {
                    vec3 finalColor = vec3(0.0, 0.0, 0.0);
                    vec4 spriteColor = texture2D(uMainTexture, v_tex_coord) * vec4(v_color, v_alpha);
                    vec3 spriteNormal = texture2D(uNormTexture, v_tex_coord).rgb;
                    vec3 normal = normalize(vec3(spriteNormal * 2.0 - 1.0));

                    for (int index = 0; index < ` + Const.MAX_LIGHTS + `; ++index)
                    {
                        Light light = uLights[index];
                        float lightY = uResolution.y - light.position.y;
                        vec3 lightDir = vec3((vec2(light.position.x, lightY) / uResolution) - (gl_FragCoord.xy / uResolution), light.position.z);
                        vec3 lightNormal = normalize(lightDir);
                        float distToSurf = length(lightDir);
                        float diffuseFactor = max(dot(normal, lightNormal), 0.0);
                        float attenuation = 1.0 / (1.0 + light.attenuation * (distToSurf * distToSurf));
                        vec3 diffuse = light.color * spriteColor.rgb * diffuseFactor;
                        finalColor += attenuation * diffuse;
                    }

                    gl_FragColor = vec4(uAmbientLightColor + finalColor, spriteColor.a);
                }
            `});
            this.ambientLightColorLoc = this.passShader.getUniformLocation('uAmbientLightColor');
            this.uMainTextureLoc = this.passShader.getUniformLocation('uMainTexture');
            this.uNormTextureLoc = this.passShader.getUniformLocation('uNormTexture');
            this.uResolutionLoc = this.passShader.getUniformLocation('uResolution');

            this.passShader.setConstantInt1(this.uMainTextureLoc, 0);
            this.passShader.setConstantInt1(this.uNormTextureLoc, 1);

            for (var index = 0; index < Const.MAX_LIGHTS; ++index)
            {
                this.lightsLocations[index] = {
                    position: this.passShader.getUniformLocation('uLights[' + index + '].position'),
                    color: this.passShader.getUniformLocation('uLights[' + index + '].color'),
                    attenuation: this.passShader.getUniformLocation('uLights[' + index + '].attenuation')
                };
            }
        }
        else
        {
            var gl = this.gl = scene.game.renderer.gl;
            this.ext = scene.game.renderer.getExtension('WEBGL_draw_buffers');
            this.gBufferShaderPass = resourceManager.createShader('GBufferShader', {vert: TexturedAndNormalizedTintedShader.vert, frag: `
                #extension GL_EXT_draw_buffers : require

                precision mediump float;

                uniform vec2 uResolution;
                uniform sampler2D uMainTexture;
                uniform sampler2D uNormTexture;

                varying vec2 v_tex_coord;
                varying vec3 v_color;
                varying float v_alpha;

                void main()
                {
                    vec4 spriteColor = texture2D(uMainTexture, v_tex_coord) * vec4(v_color, v_alpha);
                    vec3 spriteNormal = texture2D(uNormTexture, v_tex_coord).rgb;

                    gl_FragData[0] = spriteColor;
                    gl_FragData[1] = vec4(spriteNormal, spriteColor.a);
                }
            `});
            this.lightPassShader = resourceManager.createShader('Phong2DShaderDeferred', {
                vert: `
                precision mediump float;
                attribute vec2 vertexPosition;
                void main()
                {
                    gl_Position = vec4(vertexPosition, 0.0, 1.0);
                }
                `,
                frag: `
                precision mediump float;

                struct Light
                {
                    vec3 position;
                    vec3 color;
                    float attenuation;
                };

                uniform vec2 uResolution;
                uniform sampler2D uGbufferColor;
                uniform sampler2D uGbufferNormal;
                uniform vec3 uAmbientLightColor;
                uniform Light uLights[` + Const.MAX_LIGHTS + `];

                void main()
                {
                    vec2 uv = vec2(gl_FragCoord.xy / uResolution);
                    vec3 finalColor = vec3(0.0, 0.0, 0.0);
                    vec4 gbColor = texture2D(uGbufferColor, uv);
                    vec3 gbNormal = texture2D(uGbufferNormal, uv).rgb;
                    vec3 normal = normalize(vec3(gbNormal * 2.0 - 1.0));

                    for (int index = 0; index < ` + Const.MAX_LIGHTS + `; ++index)
                    {
                        Light light = uLights[index];
                        float lightY = uResolution.y - light.position.y;
                        vec3 lightDir = vec3((vec2(light.position.x, lightY) / uResolution) - uv, light.position.z);
                        vec3 lightNormal = normalize(lightDir);
                        float distToSurf = length(lightDir);
                        float diffuseFactor = max(dot(normal, lightNormal), 0.0);
                        float attenuation = 1.0 / (1.0 + light.attenuation * (distToSurf * distToSurf));
                        vec3 diffuse = light.color * gbColor.rgb * diffuseFactor;
                        finalColor += attenuation * diffuse;
                    }

                    gl_FragColor = vec4(uAmbientLightColor + finalColor, gbColor.a);
                }
            `});
            this.lightPassVBO = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, this.lightPassVBO);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, 7, -1, -1, 7, -1]), gl.STATIC_DRAW);

            this.uMainTextureLoc = this.gBufferShaderPass.getUniformLocation('uMainTexture');
            this.uNormTextureLoc = this.gBufferShaderPass.getUniformLocation('uNormTexture');

            this.gBufferShaderPass.setConstantInt1(this.uMainTextureLoc, 0);
            this.gBufferShaderPass.setConstantInt1(this.uNormTextureLoc, 1);

            this.ambientLightColorLoc = this.lightPassShader.getUniformLocation('uAmbientLightColor');
            this.uResolutionLoc = this.lightPassShader.getUniformLocation('uResolution');
            this.uGbufferColorLoc = this.lightPassShader.getUniformLocation('uGbufferColor');
            this.uGbufferNormalLoc = this.lightPassShader.getUniformLocation('uGbufferNormal');

            this.lightPassShader.setConstantInt1(this.uGbufferColorLoc, 0);
            this.lightPassShader.setConstantInt1(this.uGbufferNormalLoc, 1);

            this.gBufferShaderPass.bindAttribLocation(0, 'v_tex_coord');
            this.gBufferShaderPass.bindAttribLocation(1, 'v_color');
            this.gBufferShaderPass.bindAttribLocation(2, 'v_alpha');
            this.lightPassShader.bindAttribLocation(0, 'vertexPosition');

            for (var index = 0; index < Const.MAX_LIGHTS; ++index)
            {
                this.lightsLocations[index] = {
                    position: this.lightPassShader.getUniformLocation('uLights[' + index + '].position'),
                    color: this.lightPassShader.getUniformLocation('uLights[' + index + '].color'),
                    attenuation: this.lightPassShader.getUniformLocation('uLights[' + index + '].attenuation')
                };
            }

            /* Setup render targets */
            this.gBufferFbo = gl.createFramebuffer();
            this.gBufferColorTex = gl.createTexture();
            this.gBufferNormalTex = gl.createTexture();

            gl.bindFramebuffer(gl.FRAMEBUFFER, this.gBufferFbo);
            gl.bindTexture(gl.TEXTURE_2D, this.gBufferColorTex);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, scene.game.renderer.width, scene.game.renderer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

            gl.bindTexture(gl.TEXTURE_2D, this.gBufferNormalTex);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, scene.game.renderer.width, scene.game.renderer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

            gl.framebufferTexture2D(gl.FRAMEBUFFER, this.ext.COLOR_ATTACHMENT0_WEBGL, gl.TEXTURE_2D, this.gBufferColorTex, 0);
            gl.framebufferTexture2D(gl.FRAMEBUFFER, this.ext.COLOR_ATTACHMENT1_WEBGL, gl.TEXTURE_2D, this.gBufferNormalTex, 0);

            this.ext.drawBuffersWEBGL([this.ext.COLOR_ATTACHMENT0_WEBGL, this.ext.COLOR_ATTACHMENT1_WEBGL]);

            var complete = gl.checkFramebufferStatus(gl.FRAMEBUFFER);

            if (complete !== gl.FRAMEBUFFER_COMPLETE)
            {
                var errors = {
                    36054: 'Incomplete Attachment',
                    36055: 'Missing Attachment',
                    36057: 'Incomplete Dimensions',
                    36061: 'Framebuffer Unsupported'
                };
                throw new Error('Framebuffer incomplete. Framebuffer status: ' + errors[complete]);
            }

            gl.bindFramebuffer(gl.FRAMEBUFFER, null);
        }

        this.setOrigin(0, 0);
    },

    get z()
    {
        return this._z;
    },

    set z(newZ)
    {
        this._z = newZ;
    },

    setAmbientLightColor: function (r, g, b)
    {
        this.ambientLightColorR = r;
        this.ambientLightColorG = g;
        this.ambientLightColorB = b;
    },

    getMaxLights: function ()
    {
        return Const.MAX_LIGHTS;
    },

    getLightCount: function ()
    {
        return this.lights.length;
    },

    isDeferred: function ()
    {
        return WebGLSupportedExtensions.has('WEBGL_draw_buffers');
    },

    /* This will probably be removed later */
    addSprite: function (sprite, normalTexture)
    {
        var spriteNormalPair;

        if (this.spritePool.length > 0)
        {
            spriteNormalPair = this.spritePool.pop();
            spriteNormalPair.set(sprite, normalTexture);
        }
        else
        {
            spriteNormalPair = new SpriteNormalPair(sprite, normalTexture);
        }
        this.scene.sys.displayList.remove(sprite);
        this.sprites.push(spriteNormalPair);
    },

    removeSprite: function (sprite)
    {
        var length = this.sprites.length;
        for (var index = 0; index < length; ++index)
        {
            if (this.sprites[index].spriteRef === sprite)
            {
                this.spritePool.push(this.sprites[index]);
                this.sprites.splice(index, 1);
                break;
            }
        }
        return sprite;
    },

    addLight: function (x, y, z, r, g, b, attenuation)
    {
        if (this.lights.length < Const.MAX_LIGHTS)
        {
            var light = null;
            if (this.lightPool.length > 0)
            {
                light = this.lightPool.pop();
                light.set(x, y, z, r, g, b, attenuation);
            }
            else
            {
                light = new Light(x, y, z, r, g, b, attenuation);
            }
            this.lights.push(light);
            return light;
        }
        return null;
    },

    removeLight: function (light)
    {
        var index = this.lights.indexOf(light);

        if (index >= 0)
        {
            this.lightPool.push(light);
            this.lights.splice(index, 1);
        }
    },

    updateLights: function(renderer, camera, shader)
    {
        if (this.gl !== null)
        {
            var locations = this.lightsLocations;
            var lights = this.lights;
            var length = lights.length;
            var gl = this.gl;
            var point = {x: 0, y: 0};

            shader.setConstantFloat2(this.uResolutionLoc, renderer.width, renderer.height);
            shader.setConstantFloat3(this.ambientLightColorLoc, this.ambientLightColorR, this.ambientLightColorG, this.ambientLightColorB);

            TempMatrix.applyITRS(camera.x, camera.y, camera.rotation, camera.zoom, camera.zoom);

            for (var index = 0; index < length; ++index)
            {
                var light = lights[index];
                TempMatrix.transformPoint(light.x, light.y, point);
                shader.setConstantFloat3(locations[index].position, point.x - (camera.scrollX * light.scrollFactorX), point.y - (camera.scrollY * light.scrollFactorY), light.z);
                shader.setConstantFloat3(locations[index].color, light.r, light.g, light.b);
                shader.setConstantFloat1(locations[index].attenuation, light.attenuation);
            }
        }
    }

});

module.exports = LightLayer;
<|endoftext|>


<commit_before>/* initialise javascript extensions */

if (! String.format) {
    String.format = function( text )
    {
        //check if there are two arguments in the arguments list
        if ( arguments.length <= 1 )
        {
            //if there are not 2 or more arguments there's nothing to replace
            //just return the original text
            return text;
        }
        //decrement to move to the second argument in the array
        var tokenCount = arguments.length - 2;
        for( var token = 0; token <= tokenCount; token++ )
        {
            //iterate through the tokens and replace their placeholders from the original text in order
            text = text.replace( new RegExp( "\\{" + token + "\\}", "gi" ),
                                                    arguments[ token + 1 ] );
        }
        return text;
    };
} // if

String.prototype.containsWord = function(word) {
    var testString = "";

    // iterate through the string and test escape special characters
    for (var ii = 0; ii < word.length; ii++) {
        testString += (! (/\w/).test(word[ii])) ? "\\" + word[ii] : word[ii];
    } // for

    var regex = new RegExp("(^|\s)" + testString + "(\w|$)", "i");

    return regex.test(this);
};

Number.prototype.toRad = function() {  // convert degrees to radians
  return this * Math.PI / 180;
}; //

// include the secant method for Number
// code from the excellent number extensions library:
// http://safalra.com/web-design/javascript/number-object-extensions/
Number.prototype.sec = function() {
  return 1 / Math.cos(this);
};

<commit_msg>Added comma as an acceptable delimiter<commit_after>/* initialise javascript extensions */

if (! String.format) {
    String.format = function( text )
    {
        //check if there are two arguments in the arguments list
        if ( arguments.length <= 1 )
        {
            //if there are not 2 or more arguments there's nothing to replace
            //just return the original text
            return text;
        }
        //decrement to move to the second argument in the array
        var tokenCount = arguments.length - 2;
        for( var token = 0; token <= tokenCount; token++ )
        {
            //iterate through the tokens and replace their placeholders from the original text in order
            text = text.replace( new RegExp( "\\{" + token + "\\}", "gi" ),
                                                    arguments[ token + 1 ] );
        }
        return text;
    };
} // if

String.prototype.containsWord = function(word) {
    var testString = "";

    // iterate through the string and test escape special characters
    for (var ii = 0; ii < word.length; ii++) {
        testString += (! (/\w/).test(word[ii])) ? "\\" + word[ii] : word[ii];
    } // for

    var regex = new RegExp("(^|\\s|\\,)" + testString + "(\\,|\\s|$)", "i");

    return regex.test(this);
};

Number.prototype.toRad = function() {  // convert degrees to radians
  return this * Math.PI / 180;
}; //

// include the secant method for Number
// code from the excellent number extensions library:
// http://safalra.com/web-design/javascript/number-object-extensions/
Number.prototype.sec = function() {
  return 1 / Math.cos(this);
};

<|endoftext|>


<commit_before>var Parse = require('parse').Parse;
var appConstants = require('../constants/appConstants');
var sessionUtils = require('./sessionUtils');
var https = require('https');

var parseUtils = {
  // function for server side code
  // to call to check if a user exists
  serverLogin: function(githubData, serverResponse) {
    var _this = this;

    // Initialize Parse for Server Side queries
    Parse.initialize(appConstants.PARSE_APP_ID, appConstants.PARSE_JS_KEY, appConstants.PARSE_MASTER_KEY);
    // Enables us to login the user from the
    // server side (remove if we find another way
    // to get the session token)

    Parse.User.enableUnsafeCurrentUser();

    // store github data
    this.githubData = githubData;
    this.serverResponse = serverResponse;
    this.sessionUtils = sessionUtils;

    var path = '/1/login?username=';
    path += encodeURIComponent(githubData.login);
    path += '&password=';
    path += encodeURIComponent(String(githubData.id));

    https.get({
      host: 'api.parse.com',
      path: path,
      headers: {
        "X-Parse-Application-Id":appConstants.PARSE_APP_ID,
        "X-Parse-REST-API-Key":appConstants.REST_API_KEY,
      }
    }, function(response) {
      // Continuously update stream with data
      var body = '';
      response.on('data', function(d) {
        body += d;
      });
      response.on('end', function() {
        // Data reception is done, do whatever with it!
        var jsonResponse = JSON.parse(body);
        if(jsonResponse.error){
          process.stdout.write("Error reading from parse API: ");
          process.stdout.write(jsonResponse.error);
        }
        if(jsonResponse.sessionToken) {
          this.sessionUtils.createNewSession(jsonResponse.sessionToken, this.serverResponse);
        } else {
          this.serverSignUp();
        }
      }.bind(this));
    }.bind(this));
  },

  serverSignUp: function() {

    var user = new Parse.User();
    user.set("username", this.githubData.login);
    user.set("password", String(this.githubData.id));
    user.set("email", this.githubData.email);
    user.set("avatar_url", this.githubData.avatar_url);
    user.set("name", this.githubData.name);
    user.set("location", this.githubData.location);

    user.signUp(null, {
      success: function(user) {
        // Hooray! User signed up
        sessionUtils.createNewSession(user._sessionToken, this.serverResponse);
      }.bind(this),
      error: function(user, error) {
        console.log("Error: " + error.code + " " + error.message);
        process.stdout.write("ERROR SIGNING UP: ");
        process.stdout.write("Error signing up user: ");
        process.stdout.write(error.code + " " + error.message);
      }
    });
  },

  login: function(githubData) {

  },

  logout: function() {
    Parse.User.logOut();
  }
};

module.exports = parseUtils;
<commit_msg>Wrap parse variables in if condition.<commit_after>var Parse = require('parse').Parse;
var appConstants = require('../constants/appConstants');
var sessionUtils = require('./sessionUtils');
var https = require('https');

var parseUtils = {
  // function for server side code
  // to call to check if a user exists
  serverLogin: function(githubData, serverResponse) {
    var _this = this;

    // Initialize Parse for Server Side queries
    Parse.initialize(appConstants.PARSE_APP_ID, appConstants.PARSE_JS_KEY, appConstants.PARSE_MASTER_KEY);
    // Enables us to login the user from the
    // server side (remove if we find another way
    // to get the session token)

    Parse.User.enableUnsafeCurrentUser();

    // store github data
    this.githubData = githubData;
    this.serverResponse = serverResponse;
    this.sessionUtils = sessionUtils;

    var path = '/1/login?username=';
    path += encodeURIComponent(githubData.login);
    path += '&password=';
    path += encodeURIComponent(String(githubData.id));

    https.get({
      host: 'api.parse.com',
      path: path,
      headers: {
        "X-Parse-Application-Id":appConstants.PARSE_APP_ID,
        "X-Parse-REST-API-Key":appConstants.REST_API_KEY,
      }
    }, function(response) {
      // Continuously update stream with data
      var body = '';
      response.on('data', function(d) {
        body += d;
      });
      response.on('end', function() {
        // Data reception is done, do whatever with it!
        var jsonResponse = JSON.parse(body);
        if(jsonResponse.error){
          process.stdout.write("Error reading from parse API: ");
          process.stdout.write(jsonResponse.error);
        }
        if(jsonResponse.sessionToken) {
          this.sessionUtils.createNewSession(jsonResponse.sessionToken, this.serverResponse);
        } else {
          this.serverSignUp();
        }
      }.bind(this));
    }.bind(this));
  },

  serverSignUp: function() {

    var user = new Parse.User();
    var data = this.githubData;
    user.set("username", data.login);
    user.set("password", String(data.id));
    if(data.email && data.email.length) {
      user.set("email", data.email);
    };
    if(data.avatar_url && data.avatar_url.length) {
      user.set("avatar_url", this.githubData.avatar_url);
    }
    if(data.name && data.name.length) {
      user.set("name", this.githubData.name);
    }
    if(data.location && data.location.length) {
      user.set("location", this.githubData.location);
    }

    user.signUp(null, {
      success: function(user) {
        // Hooray! User signed up
        sessionUtils.createNewSession(user._sessionToken, this.serverResponse);
      }.bind(this),
      error: function(user, error) {
        console.log("Error: " + error.code + " " + error.message);
        process.stdout.write("ERROR SIGNING UP: ");
        process.stdout.write("Error signing up user: ");
        process.stdout.write(error.code + " " + error.message);
      }
    });
  },

  login: function(githubData) {

  },

  logout: function() {
    Parse.User.logOut();
  }
};

module.exports = parseUtils;
<|endoftext|>


<commit_before>'use strict';

describe('myApp.view1 module', function() {

  beforeEach(module('myApp.view1'));

  describe('view1 controller', function(){

    it('should ....', inject(function($controller) {
      //spec body
      var view1Ctrl = $controller('View1Ctrl');
      expect(view1Ctrl).toBeDefined();
    }));

  });
});<commit_msg>Initial project files.<commit_after>'use strict';

describe('myApp.view1 module', function() {

  beforeEach(module('myApp.view1'));

  describe('view1 controller', function(){

    it('should ....', inject(function($controller) {
      //spec body
      var view1Ctrl = $controller('View1Ctrl');
      expect(view1Ctrl).toBeDefined();
    }));

  });
});

// Testing git here...<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var jwt = require('express-jwt');
var auth = jwt({
  secret: 'MY_SECRET',
  userProperty: 'payload'
});

var ctrlProfile = require('../controllers/profile');
var ctrlAuth = require('../controllers/authentication');
var ctrlProject = require('../controllers/project');

// profile
router.get('/profile', auth, ctrlProfile.profileRead);
router.post('/profileUpdate', auth, ctrlProfile.profileUpdate);
router.post('/profileDelete', auth, ctrlProfile.profileDelete);

// project
router.get('/project', ctrlProject.porjectRead);
router.post('/projectUpdate', auth, ctrlProject.projectUpdate);
router.post('/projectDelete', auth, ctrlProject.projectDelete);

// authentication
router.post('/register', ctrlAuth.register);
router.post('/login', ctrlAuth.login);

module.exports = router;<commit_msg>fixed typo in method call<commit_after>var express = require('express');
var router = express.Router();
var jwt = require('express-jwt');
var auth = jwt({
  secret: 'MY_SECRET',
  userProperty: 'payload'
});

var ctrlProfile = require('../controllers/profile');
var ctrlAuth = require('../controllers/authentication');
var ctrlProject = require('../controllers/project');

// profile
router.get('/profile', auth, ctrlProfile.profileRead);
router.post('/profileUpdate', auth, ctrlProfile.profileUpdate);
router.post('/profileDelete', auth, ctrlProfile.profileDelete);

// project
router.get('/project', ctrlProject.projectRead);
router.post('/projectUpdate', auth, ctrlProject.projectUpdate);
router.post('/projectDelete', auth, ctrlProject.projectDelete);

// authentication
router.post('/register', ctrlAuth.register);
router.post('/login', ctrlAuth.login);

module.exports = router;<|endoftext|>


<commit_before>module.exports = function( app ) {
  const
    Model = app.models.user,
    user = require( '../lib/mongoose')( Model );

  function createUser( req, res ) {
    let doc = req.body;

    user.save( doc )
      .then( status => res.json( status ) )
      .catch( error => res.status( 500 ).json( error ) );
  }

  return {
    createUser
  };
};
<commit_msg>[UPDATE]: Adicionado validação dos parametros da requisição<commit_after>module.exports = function( app ) {
  const
    Model = app.models.user,
    user = require( '../lib/mongoose')( Model );

  function createUser( req, res ) {
    let doc = req.body;

    Promise.resolve( doc )
      .then( validateName )
      .then( validateGroup )
      .then( validatePassword )
      .then( validateEmail )
      .then( save )
      .then( resolveResponse )
      .catch( rejectResponse );

    function validateName( _doc ) {
      if ( !( _doc.firstName || _doc.lastName ) ) {
        throw new Error( 'O nome do usuário deve ser informado.' );
      }
      return _doc;
    }

    function validateGroup( _doc ) {
      const
        groups = [ 'admin', 'user' ],
        validGroup = group => _doc.group === group,
        isValid = groups.some( validGroup );

      if( !isValid ) {
        throw new Error( 'O grupo informado não é válido.' );
      }

      return _doc;
    }

    function validateEmail( _doc ) {
      return new Promise( ( resolve, reject ) => {
        user.get( { email: _doc.email } )
        .then( userDoc => {
          if ( userDoc ) {
            return reject( new Error( 'O email informada já está sendo usado por outro usuário' ) );
          }

          resolve( _doc );
        });
      });
    }

    function validatePassword( _doc ) {
      if ( !_doc.password || _doc.password.length < 8 ) {
        throw new Error( 'A senha não pode está vazia ou ser menor que 8 caracteres' );
      }
      return _doc;
    }

    function save( _doc ) {
      return new Promise( ( resolve, reject ) => {
        user.save( _doc )
          .then( _user => resolve( _user ) )
          .catch( error => reject( error ) );
      });
    }

    function resolveResponse( _user ) {
      res.status( 200 ).json( _user );
    }

    function rejectResponse( error ) {
      console.log( error );
      res.status( 500 ).json( error );
    }
  }

  return {
    createUser
  };
};
<|endoftext|>


<commit_before>(function() {
  // This is "window" in browsers and "global" in nodejs.
  // See https://github.com/google/shaka-player/issues/1445
  var innerGlobal = typeof window != 'undefined' ? window : global;

  // This is where our library exports things to.  It is "this" in the wrapped
  // code.  With this, we can decide later what module loader we are in, if any,
  // and put these exports in the appropriate place for that loader.
  var exportTo = {};

  // According to the Closure team, their polyfills will be written to
  // $jscomp.global, which will be "window", or "global", or "this", depending
  // on circumstances.
  // See https://github.com/google/closure-compiler/issues/2957 and
  // https://github.com/google/shaka-player/issues/1455#issuecomment-393250035

  // We provide "global" for use by Closure, and "window" for use by the Shaka
  // library itself.  Both point to "innerGlobal" above.
  (function(window, global) {

%output%

  }).call(exportTo, innerGlobal, innerGlobal);

  if (typeof exports != 'undefined') {
    // CommonJS module loader.  Use "exports" instead of "module.exports" to
    // avoid triggering inappropriately in Electron.
    for (var k in exportTo.shaka) {
      exports[k] = exportTo.shaka[k];
    }
  } else if (typeof define != 'undefined' && define.amd) {
    // AMD module loader.
    define(function(){
      return exportTo.shaka;
    });
  } else {
    // Loaded as an ES module or directly in a <script> tag.
    // Export directly to the global scope.
    innerGlobal.shaka = exportTo.shaka;
  }
})();
<commit_msg>Fix module wrapper to prevent conflicting exports<commit_after>(function() {
  // This is "window" in browsers and "global" in nodejs.
  // See https://github.com/google/shaka-player/issues/1445
  var innerGlobal = typeof window != 'undefined' ? window : global;

  // This is where our library exports things to.  It is "this" in the wrapped
  // code.  With this, we can decide later what module loader we are in, if any,
  // and put these exports in the appropriate place for that loader.
  var exportTo = {};

  // According to the Closure team, their polyfills will be written to
  // $jscomp.global, which will be "window", or "global", or "this", depending
  // on circumstances.
  // See https://github.com/google/closure-compiler/issues/2957 and
  // https://github.com/google/shaka-player/issues/1455#issuecomment-393250035

  // We provide "global" for use by Closure, and "window" for use by the Shaka
  // library itself.  Both point to "innerGlobal" above.
  // We also provide "module", which is always undefined, to prevent compiled-in
  // code from doing its own exports that conflict with ours.
  (function(window, global, module) {

%output%

  }).call(/* this= */ exportTo,
          /* window= */ innerGlobal,
          /* global= */ innerGlobal,
          /* module= */ undefined);

  if (typeof exports != 'undefined') {
    // CommonJS module loader.  Use "exports" instead of "module.exports" to
    // avoid triggering inappropriately in Electron.
    for (var k in exportTo.shaka) {
      exports[k] = exportTo.shaka[k];
    }
  } else if (typeof define != 'undefined' && define.amd) {
    // AMD module loader.
    define(function(){
      return exportTo.shaka;
    });
  } else {
    // Loaded as an ES module or directly in a <script> tag.
    // Export directly to the global scope.
    innerGlobal.shaka = exportTo.shaka;
  }
})();
<|endoftext|>


<commit_before>var PlayList={
	urlBase:OC.linkTo('media','ajax/api.php')+'?action=play&path=',
	current:-1,
	items:[],
	player:null,
	volume:0.8,
	active:false,
	next:function(){
		var items=PlayList.items;
		var next=PlayList.current+1;
		if(next>=items.length){
			next=0;
		}
		PlayList.play(next);
		PlayList.render();
	},
	previous:function(){
		var items=PlayList.items;
		var next=PlayList.current-1;
		if(next<0){
			next=items.length-1;
		}
		PlayList.play(next);
		PlayList.render();
	},
	play:function(index,time,ready){
		var items=PlayList.items;
		if(index==null){
			index=PlayList.current;
		}
		PlayList.save();
		if(index>-1 && index<items.length){
			PlayList.current=index;
			if(PlayList.player){
				if(PlayList.player.data('jPlayer').options.supplied!=items[index].type){//the the audio type changes we need to reinitialize jplayer
					PlayList.player.jPlayer("play",time);
					localStorage.setItem(oc_current_user+'oc_playlist_time',time);
					PlayList.player.jPlayer("destroy");
// 					PlayList.save(); // so that the init don't lose the playlist
					PlayList.init(items[index].type,null); // init calls load that calls play
				}else{
					PlayList.player.jPlayer("setMedia", items[PlayList.current]);
					$(".jp-current-song").text(items[PlayList.current].name);
					items[index].playcount++;
					PlayList.player.jPlayer("play",time);
					if(index>0){
						var previous=index-1;
					}else{
						var previous=items.length-1;
					}
					if(index+1<items.length){
						var next=index+1;
					}else{
						var next=0;
					}
					$('.jp-next').attr('title',items[next].name);
					$('.jp-previous').attr('title',items[previous].name);
					if (typeof Collection !== 'undefined') {
						Collection.registerPlay();
					}
					PlayList.render();
					if(ready){
						ready();
					}
				}
			}else{
				localStorage.setItem(oc_current_user+'oc_playlist_time',time);
				localStorage.setItem(oc_current_user+'oc_playlist_playing','true');
//                 PlayList.save(); // so that the init don't lose the playlist
				PlayList.init(items[index].type,null); // init calls load that calls play
			}
		}
		$(".song").removeClass("collection_playing");
		$(".jp-playlist-" + index).addClass("collection_playing");
	},
	init:function(type,ready){
		if(!PlayList.player){
			$(".jp-previous").click(function() {
				PlayList.previous();
				$(this).blur();
				PlayList.render();
				return false;
			});
			$(".jp-next").click(function() {
				PlayList.next();
				$(this).blur();
				PlayList.render();
				return false;
			});
			PlayList.player=$('#jp-player');
		}
		$(PlayList.player).jPlayer({
			ended:PlayList.next,
			pause:function(){
				localStorage.setItem(oc_current_user+'oc_playlist_playing','false');
			},
			play:function(){
				localStorage.setItem(oc_current_user+'oc_playlist_playing','true');
			},
			supplied:type,
			ready:function(){
				PlayList.load();
				if(ready){
					ready();
				}
			},
			volume:PlayList.volume,
			cssSelectorAncestor:'.player-controls',
			swfPath:OC.linkTo('media','js'),
		});
	},
	add:function(song,dontReset){
		if(!dontReset){
			PlayList.items=[];//clear the playlist
		}
		if(!song){
			return;
		}
		if(song.substr){//we are passed a string, asume it's a url to a song
			PlayList.addFile(song,true);
		}
		if(song.albums){//a artist object was passed, add all albums inside it
			$.each(song.albums,function(index,album){
				PlayList.add(album,true);
			});
		} else if(song.songs){//a album object was passed, add all songs inside it
			$.each(song.songs,function(index,song){
				PlayList.add(song,true);
			});
		}
		if(song.path){
			var type=musicTypeFromFile(song.path);
			var item={name:song.name,type:type,artist:song.artist,album:song.album,length:song.length,playcount:song.playCount};
			item[type]=PlayList.urlBase+encodeURIComponent(song.path);
			PlayList.items.push(item);
		}
	},
	addFile:function(path){
		var type=musicTypeFromFile(path);
		var item={name:'unknown',artist:'unknown',album:'unknwon',type:type};
		$.getJSON(OC.filePath('media','ajax','api.php')+'?action=get_path_info&path='+encodeURIComponent(path),function(song){
			item.name=song.song_name;
			item.artist=song.artist;
			item.album=song.album;
		});
		item[type]=PlayList.urlBase+encodeURIComponent(path);
		PlayList.items.push(item);
	},
	remove:function(index){
		PlayList.items.splice(index,1);
		PlayList.render();
	},
	render:function(){},
	playing:function(){
		if(!PlayList.player){
			return false;
		}else{
			return !PlayList.player.data("jPlayer").status.paused;
		}
	},
	save:function(){
		if(typeof localStorage !== 'undefined' && localStorage){
			localStorage.setItem(oc_current_user+'oc_playlist_items',JSON.stringify(PlayList.items));
			localStorage.setItem(oc_current_user+'oc_playlist_current',PlayList.current);
			if(PlayList.player) {
				if(PlayList.player.data('jPlayer')) {
					var time=Math.round(PlayList.player.data('jPlayer').status.currentTime);
					localStorage.setItem(oc_current_user+'oc_playlist_time',time);
					var volume=PlayList.player.data('jPlayer').options.volume*100;
					localStorage.setItem(oc_current_user+'oc_playlist_volume',volume);
				}
			}
			if(PlayList.active){
				localStorage.setItem(oc_current_user+'oc_playlist_active','false');
			}
		}
	},
	load:function(){
		if(typeof localStorage !== 'undefined' && localStorage){
			PlayList.active=true;
			localStorage.setItem(oc_current_user+'oc_playlist_active','true');
			if(localStorage.hasOwnProperty(oc_current_user+'oc_playlist_items')){
				PlayList.items=JSON.parse(localStorage.getItem(oc_current_user+'oc_playlist_items'));
				if(PlayList.items.length>0){
					PlayList.current=parseInt(localStorage.getItem(oc_current_user+'oc_playlist_current'));
					var time=parseInt(localStorage.getItem(oc_current_user+'oc_playlist_time'));
					if(localStorage.hasOwnProperty(oc_current_user+'oc_playlist_volume')){
						var volume=localStorage.getItem(oc_current_user+'oc_playlist_volume');
						PlayList.volume=volume/100;
						$('.jp-volume-bar-value').css('width',volume+'%');
						if(PlayList.player.data('jPlayer')){
							PlayList.player.jPlayer("option",'volume',volume/100);
						}
					}
					if(JSON.parse(localStorage.getItem(oc_current_user+'oc_playlist_playing'))){
						PlayList.play(null,time);
					}else{
						PlayList.play(null,time,function(){
							PlayList.player.jPlayer("pause");
						});
					}
					PlayList.render();
				}
			}
		}
	}
}

$(document).ready(function(){
	$(window).bind('beforeunload', function (){
		PlayList.save();
	});

	$('jp-previous').tipsy({gravity:'n', fade:true, live:true});
	$('jp-next').tipsy({gravity:'n', fade:true, live:true});
})
<commit_msg>only play the music once<commit_after>var PlayList={
	urlBase:OC.linkTo('media','ajax/api.php')+'?action=play&path=',
	current:-1,
	items:[],
	player:null,
	volume:0.8,
	active:false,
	next:function(){
		var items=PlayList.items;
		var next=PlayList.current+1;
		if(next>=items.length){
			next=0;
		}
		PlayList.play(next);
		PlayList.render();
	},
	previous:function(){
		var items=PlayList.items;
		var next=PlayList.current-1;
		if(next<0){
			next=items.length-1;
		}
		PlayList.play(next);
		PlayList.render();
	},
	play:function(index,time,ready){
		var items=PlayList.items;
		if(index==null){
			index=PlayList.current;
		}
		PlayList.save();
		if(index>-1 && index<items.length){
			PlayList.current=index;
			if(PlayList.player){
				if(PlayList.player.data('jPlayer').options.supplied!=items[index].type){//the the audio type changes we need to reinitialize jplayer
					PlayList.player.jPlayer("play",time);
					localStorage.setItem(oc_current_user+'oc_playlist_time',time);
					PlayList.player.jPlayer("destroy");
// 					PlayList.save(); // so that the init don't lose the playlist
					PlayList.init(items[index].type,null); // init calls load that calls play
				}else{
					PlayList.player.jPlayer("setMedia", items[PlayList.current]);
					$(".jp-current-song").text(items[PlayList.current].name);
					items[index].playcount++;
					PlayList.player.jPlayer("play",time);
					if(index>0){
						var previous=index-1;
					}else{
						var previous=items.length-1;
					}
					if(index+1<items.length){
						var next=index+1;
					}else{
						var next=0;
					}
					$('.jp-next').attr('title',items[next].name);
					$('.jp-previous').attr('title',items[previous].name);
					if (typeof Collection !== 'undefined') {
						Collection.registerPlay();
					}
					PlayList.render();
					if(ready){
						ready();
					}
				}
			}else{
				localStorage.setItem(oc_current_user+'oc_playlist_time',time);
				localStorage.setItem(oc_current_user+'oc_playlist_playing','true');
//                 PlayList.save(); // so that the init don't lose the playlist
				PlayList.init(items[index].type,null); // init calls load that calls play
			}
		}
		$(".song").removeClass("collection_playing");
		$(".jp-playlist-" + index).addClass("collection_playing");
	},
	init:function(type,ready){
		if(!PlayList.player){
			$(".jp-previous").click(function() {
				PlayList.previous();
				$(this).blur();
				PlayList.render();
				return false;
			});
			$(".jp-next").click(function() {
				PlayList.next();
				$(this).blur();
				PlayList.render();
				return false;
			});
			PlayList.player=$('#jp-player');
		}
		$(PlayList.player).jPlayer({
			ended:PlayList.next,
			pause:function(){
				localStorage.setItem(oc_current_user+'oc_playlist_playing','false');
			},
			play:function(){
				localStorage.setItem(oc_current_user+'oc_playlist_playing','true');
			},
			supplied:type,
			ready:function(){
				PlayList.load();
				if(ready){
					ready();
				}
			},
			volume:PlayList.volume,
			cssSelectorAncestor:'.player-controls',
			swfPath:OC.linkTo('media','js'),
		});
	},
	add:function(song,dontReset){
		if(!dontReset){
			PlayList.items=[];//clear the playlist
		}
		if(!song){
			return;
		}
		if(song.substr){//we are passed a string, asume it's a url to a song
			PlayList.addFile(song,true);
		}
		if(song.albums){//a artist object was passed, add all albums inside it
			$.each(song.albums,function(index,album){
				PlayList.add(album,true);
			});
		} else if(song.songs){//a album object was passed, add all songs inside it
			$.each(song.songs,function(index,song){
				PlayList.add(song,true);
			});
		}
		if(song.path){
			var type=musicTypeFromFile(song.path);
			var item={name:song.name,type:type,artist:song.artist,album:song.album,length:song.length,playcount:song.playCount};
			item[type]=PlayList.urlBase+encodeURIComponent(song.path);
			PlayList.items.push(item);
		}
	},
	addFile:function(path){
		var type=musicTypeFromFile(path);
		var item={name:'unknown',artist:'unknown',album:'unknwon',type:type};
		$.getJSON(OC.filePath('media','ajax','api.php')+'?action=get_path_info&path='+encodeURIComponent(path),function(song){
			item.name=song.song_name;
			item.artist=song.artist;
			item.album=song.album;
		});
		item[type]=PlayList.urlBase+encodeURIComponent(path);
		PlayList.items.push(item);
	},
	remove:function(index){
		PlayList.items.splice(index,1);
		PlayList.render();
	},
	render:function(){},
	playing:function(){
		if(!PlayList.player){
			return false;
		}else{
			return !PlayList.player.data("jPlayer").status.paused;
		}
	},
	save:function(){
		if(typeof localStorage !== 'undefined' && localStorage){
			localStorage.setItem(oc_current_user+'oc_playlist_items',JSON.stringify(PlayList.items));
			localStorage.setItem(oc_current_user+'oc_playlist_current',PlayList.current);
			if(PlayList.player) {
				if(PlayList.player.data('jPlayer')) {
					var time=Math.round(PlayList.player.data('jPlayer').status.currentTime);
					localStorage.setItem(oc_current_user+'oc_playlist_time',time);
					var volume=PlayList.player.data('jPlayer').options.volume*100;
					localStorage.setItem(oc_current_user+'oc_playlist_volume',volume);
				}
			}
			localStorage.setItem(oc_current_user+'oc_playlist_active','true');
		}
	},
	load:function(){
		if(typeof localStorage !== 'undefined' && localStorage){
			PlayList.active=true;
			localStorage.setItem(oc_current_user+'oc_playlist_active','true');
			if(localStorage.hasOwnProperty(oc_current_user+'oc_playlist_items')){
				PlayList.items=JSON.parse(localStorage.getItem(oc_current_user+'oc_playlist_items'));
				if(PlayList.items.length>0){
					PlayList.current=parseInt(localStorage.getItem(oc_current_user+'oc_playlist_current'));
					var time=parseInt(localStorage.getItem(oc_current_user+'oc_playlist_time'));
					if(localStorage.hasOwnProperty(oc_current_user+'oc_playlist_volume')){
						var volume=localStorage.getItem(oc_current_user+'oc_playlist_volume');
						PlayList.volume=volume/100;
						$('.jp-volume-bar-value').css('width',volume+'%');
						if(PlayList.player.data('jPlayer')){
							PlayList.player.jPlayer("option",'volume',volume/100);
						}
					}
					if(JSON.parse(localStorage.getItem(oc_current_user+'oc_playlist_playing'))){
						PlayList.play(null,time);
					}else{
						PlayList.play(null,time,function(){
							PlayList.player.jPlayer("pause");
						});
					}
					PlayList.render();
				}
			}
		}
	}
}

$(document).ready(function(){
	$(window).bind('beforeunload', function (){
		PlayList.save();
		if(PlayList.active){
			localStorage.setItem(oc_current_user+'oc_playlist_active','false');
		}
	});

	$('jp-previous').tipsy({gravity:'n', fade:true, live:true});
	$('jp-next').tipsy({gravity:'n', fade:true, live:true});
})
<|endoftext|>


<commit_before>'use strict'
var asArray = require('./util').asArray
var catchesError = require('./util').catchesError
var INTERNAL = require('./util').INTERNAL
var LST = require('./long-stack-traces') // @[/development]

function Promise(fn) {
	if (typeof this !== 'object') {
		throw new TypeError('Promises must be constructed via the "new" keyword.')
	}
	if (typeof fn !== 'function') {
		throw new TypeError('Promises must be constructed with a function argument.')
	}
	this._state = $NO_STATE
	this._value = null
	this._deferreds = null
	if (fn !== INTERNAL) {
		this._resolveFromHandler(fn)
	}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
	return this._then(onFulfilled, onRejected)
}
Promise.prototype.catch = function (onRejected) {
	if (arguments.length > 1) {
		var len = arguments.length - 1
		var args = new Array(len)
		for (var i=0; i<len; i++) {
			args[i] = arguments[i]
		}
		onRejected = arguments[i]
		var self = this // @[/development]
		return this._then(null, function (reason) {
			for (var i=0; i<len; i++) {
				if (catchesError(args[i], reason)) {
					return onRejected(reason)
				}
			}
			LST.setRejectionStack(self._getStack()) // @[/development]
			throw reason
		})
	}
	return this._then(null, onRejected)
}
Promise.prototype.catchLater = function () {
	this._state |= $SUPPRESS_UNHANDLED_REJECTIONS
	return this
}
module.exports = Promise
Promise.resolve = function (value) {
	if (value instanceof Promise) {
		return value
	}
	var promise = new Promise(INTERNAL)
	promise._addStackTrace(1) // @[/development]
	promise._resolve(value)
	return promise
}
Promise.reject = function (reason) {
	var promise = new Promise(INTERNAL)
	promise._addStackTrace(1) // @[/development]
	promise._reject(reason)
	return promise
}
Promise.race = function (iterable) {
	return new Promise(INTERNAL)._resolveFromHandler(function (res, rej) {
		var input = asArray(iterable)
		rej = LST.upgradeRejector(rej) // @[/development]
		for (var i=0, len=input.length; i<len; i++) {
			Promise.resolve(input[i])._then(res, rej)
		}
	})
}
Promise.all = function (iterable) {
	return new Promise(INTERNAL)._resolveFromHandler(function (res, rej) {
		var input = asArray(iterable)
		var pendings = input.length
		var result = new Array(pendings)
		if (pendings === 0) {
			return res(result)
		}
		rej = LST.upgradeRejector(rej) // @[/development]
		var resolveItem = function (i) {
			return function (value) {
				result[i] = value
				if (--pendings === 0) {res(result)}
			}
		}
		for (var i=0; i<pendings; i++) {
			Promise.resolve(input[i])._then(resolveItem(i), rej)
		}
	})
}
<commit_msg>strengthened new keyword check<commit_after>'use strict'
var asArray = require('./util').asArray
var catchesError = require('./util').catchesError
var INTERNAL = require('./util').INTERNAL
var LST = require('./long-stack-traces') // @[/development]

function Promise(fn) {
	if (!(this instanceof Promise) || this._state !== undefined) {
		throw new TypeError('Promises must be constructed via the "new" keyword.')
	}
	if (typeof fn !== 'function') {
		throw new TypeError('Promises must be constructed with a function argument.')
	}
	this._state = $NO_STATE
	this._value = null
	this._deferreds = null
	if (fn !== INTERNAL) {
		this._resolveFromHandler(fn)
	}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
	return this._then(onFulfilled, onRejected)
}
Promise.prototype.catch = function (onRejected) {
	if (arguments.length > 1) {
		var len = arguments.length - 1
		var args = new Array(len)
		for (var i=0; i<len; i++) {
			args[i] = arguments[i]
		}
		onRejected = arguments[i]
		var self = this // @[/development]
		return this._then(null, function (reason) {
			for (var i=0; i<len; i++) {
				if (catchesError(args[i], reason)) {
					return onRejected(reason)
				}
			}
			LST.setRejectionStack(self._getStack()) // @[/development]
			throw reason
		})
	}
	return this._then(null, onRejected)
}
Promise.prototype.catchLater = function () {
	this._state |= $SUPPRESS_UNHANDLED_REJECTIONS
	return this
}
module.exports = Promise
Promise.resolve = function (value) {
	if (value instanceof Promise) {
		return value
	}
	var promise = new Promise(INTERNAL)
	promise._addStackTrace(1) // @[/development]
	promise._resolve(value)
	return promise
}
Promise.reject = function (reason) {
	var promise = new Promise(INTERNAL)
	promise._addStackTrace(1) // @[/development]
	promise._reject(reason)
	return promise
}
Promise.race = function (iterable) {
	return new Promise(INTERNAL)._resolveFromHandler(function (res, rej) {
		var input = asArray(iterable)
		rej = LST.upgradeRejector(rej) // @[/development]
		for (var i=0, len=input.length; i<len; i++) {
			Promise.resolve(input[i])._then(res, rej)
		}
	})
}
Promise.all = function (iterable) {
	return new Promise(INTERNAL)._resolveFromHandler(function (res, rej) {
		var input = asArray(iterable)
		var pendings = input.length
		var result = new Array(pendings)
		if (pendings === 0) {
			return res(result)
		}
		rej = LST.upgradeRejector(rej) // @[/development]
		var resolveItem = function (i) {
			return function (value) {
				result[i] = value
				if (--pendings === 0) {res(result)}
			}
		}
		for (var i=0; i<pendings; i++) {
			Promise.resolve(input[i])._then(resolveItem(i), rej)
		}
	})
}
<|endoftext|>


<commit_before>/* globals __webpack_require__ */
module.exports = function() {
	return __webpack_require__;
};
<commit_msg>remove buildin/return-require as it has no user (apparently)<commit_after><|endoftext|>


<commit_before>//DOM change listener, taken from https://stackoverflow.com/questions/3219758/detect-changes-in-the-dom
var observeDOM = (function(){
  var MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
      eventListenerSupported = window.addEventListener;

  return function(obj, callback){
      if( MutationObserver ){
          // define a new observer
          var obs = new MutationObserver(function(mutations, observer){
              if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
                  callback();
          });
          // have the observer observe foo for changes in children
          obs.observe( obj, { childList:true, subtree:true });
      }
      else if( eventListenerSupported ){
          obj.addEventListener('DOMNodeInserted', callback, false);
          obj.addEventListener('DOMNodeRemoved', callback, false);
      }
  }
})();
var changeFlag = false
// On change inside box scores, recalculate Fantasy Points
observeDOM( document.getElementById('nbaGIboxscore') , updateFantasyScores);
updateFantasyScores()

function updateFantasyScores(){
  if (changeFlag){
    //it was our own DOM update, so no infinite loops, please=)
    changeFlag = false
    return
  }
  changeFlag = true
  //find two team's stat tables
  var tables = document.querySelectorAll("#nbaGITeamStats")
  if (tables.length == 2){
    console.log("found")
    //let's get a score of match
    var home = +document.getElementsByClassName("teamHome")[0].innerHTML
    var away = +document.getElementsByClassName("teamAway")[0].innerHTML
    for (var i = 0; i < 2; ++i){
      //calculate win-loss modifier
      //first table for away, second for home team
      var winLossMod
      if (i == 0){
        winLossMod = away > home ? 3 : -2
      }else{
        winLossMod = home > away ? 2 : -3
      }
      //get rows
      var table = tables.item(i)
      var rows = table.getElementsByTagName("tr")
      if (rows.length > 2){
        //insert column header
        var td = document.createElement("td")
        td.innerHTML = "ФО"
        rows[2].appendChild(td)
        //for every player's stats row
        for (var j = 3; j < rows.length-2; ++j){
          var row = rows[j]
          var columns = row.children
          if (columns.length < 10){
            //something wrong - columns is not set properly
            continue
          }
          //fantasy points, rules from http://www.sports.ru/fantasy/basketball/tournament/rules/150.html
          var FO = winLossMod
          var splitCol = function(col, splitChar){
            return columns[col].innerHTML.split(splitChar).map(function(elm){
              return +elm
            })
          }
          //time points
          var stat = splitCol(2, ":")
          if (stat[0] > 0 || stat[1] > 0){
            FO += 1
            if (stat[0] >= 10){
              FO += 1
            }
          }
          //two-pointers
          stat = splitCol(3, "-")
          FO += (stat[0] - stat[1])
          //three-pointers
          stat = splitCol(4, "-")
          FO += (stat[0] - stat[1])
          //free-throws
          stat = splitCol(5, "-")
          FO += (stat[0] - stat[1])
          //rebounds
          FO += +columns[9].innerHTML
          //assists
          FO += +columns[10].innerHTML
          //fouls
          FO -= +columns[11].innerHTML
          //steals
          FO += +columns[12].innerHTML
          //turnovers
          FO -= 2*(+columns[13].innerHTML)
          //blockshots
          FO += +columns[14].innerHTML
          //scored points
          FO += +columns[16].innerHTML

          //insert a column with fantasy points
          if (FO == FO){//not NaN
            var td = document.createElement("td")
            td.innerHTML = FO
            row.appendChild(td)
          }
        }
      }
    }
  }
}
<commit_msg>Remove redundant log line<commit_after>//DOM change listener, taken from https://stackoverflow.com/questions/3219758/detect-changes-in-the-dom
var observeDOM = (function(){
  var MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
      eventListenerSupported = window.addEventListener;

  return function(obj, callback){
      if( MutationObserver ){
          // define a new observer
          var obs = new MutationObserver(function(mutations, observer){
              if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
                  callback();
          });
          // have the observer observe foo for changes in children
          obs.observe( obj, { childList:true, subtree:true });
      }
      else if( eventListenerSupported ){
          obj.addEventListener('DOMNodeInserted', callback, false);
          obj.addEventListener('DOMNodeRemoved', callback, false);
      }
  }
})();
var changeFlag = false
// On change inside box scores, recalculate Fantasy Points
observeDOM( document.getElementById('nbaGIboxscore') , updateFantasyScores);
updateFantasyScores()

function updateFantasyScores(){
  if (changeFlag){
    //it was our own DOM update, so no infinite loops, please=)
    changeFlag = false
    return
  }
  changeFlag = true
  //find two team's stat tables
  var tables = document.querySelectorAll("#nbaGITeamStats")
  if (tables.length == 2){
    //let's get a score of match
    var home = +document.getElementsByClassName("teamHome")[0].innerHTML
    var away = +document.getElementsByClassName("teamAway")[0].innerHTML
    for (var i = 0; i < 2; ++i){
      //calculate win-loss modifier
      //first table for away, second for home team
      var winLossMod
      if (i == 0){
        winLossMod = away > home ? 3 : -2
      }else{
        winLossMod = home > away ? 2 : -3
      }
      //get rows
      var table = tables.item(i)
      var rows = table.getElementsByTagName("tr")
      if (rows.length > 2){
        //insert column header
        var td = document.createElement("td")
        td.innerHTML = "ФО"
        rows[2].appendChild(td)
        //for every player's stats row
        for (var j = 3; j < rows.length-2; ++j){
          var row = rows[j]
          var columns = row.children
          if (columns.length < 10){
            //something wrong - columns is not set properly
            continue
          }
          //fantasy points, rules from http://www.sports.ru/fantasy/basketball/tournament/rules/150.html
          var FO = winLossMod
          var splitCol = function(col, splitChar){
            return columns[col].innerHTML.split(splitChar).map(function(elm){
              return +elm
            })
          }
          //time points
          var stat = splitCol(2, ":")
          if (stat[0] > 0 || stat[1] > 0){
            FO += 1
            if (stat[0] >= 10){
              FO += 1
            }
          }
          //two-pointers
          stat = splitCol(3, "-")
          FO += (stat[0] - stat[1])
          //three-pointers
          stat = splitCol(4, "-")
          FO += (stat[0] - stat[1])
          //free-throws
          stat = splitCol(5, "-")
          FO += (stat[0] - stat[1])
          //rebounds
          FO += +columns[9].innerHTML
          //assists
          FO += +columns[10].innerHTML
          //fouls
          FO -= +columns[11].innerHTML
          //steals
          FO += +columns[12].innerHTML
          //turnovers
          FO -= 2*(+columns[13].innerHTML)
          //blockshots
          FO += +columns[14].innerHTML
          //scored points
          FO += +columns[16].innerHTML

          //insert a column with fantasy points
          if (FO == FO){//not NaN
            var td = document.createElement("td")
            td.innerHTML = FO
            row.appendChild(td)
          }
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>/**
 * @typedef {function} testTimer
 * @return {number[]}
 */

/**
 * Create a simple timer for tests. Timer will return next number on every call.
 *
 * @return {testTimer} timer
 *
 * @example
 * let timer = createTestTimer()
 * timer() //=> [1]
 * timer() //=> [2]
 * timer() //=> [3]
 */
function createTestTimer () {
  var last = 0
  return function () {
    last += 1
    return [last]
  }
}

module.exports = createTestTimer
<commit_msg>Update JSDoc<commit_after>/**
 * Create a simple timer for tests. Timer will return next number on every call.
 *
 * @return {Timer} test timer
 *
 * @example
 * import createTestTimer from 'logux-core/create-test-timer'
 *
 * const timer = createTestTimer()
 * timer() //=> [1]
 * timer() //=> [2]
 * timer() //=> [3]
 */
function createTestTimer () {
  var last = 0
  return function () {
    last += 1
    return [last]
  }
}

module.exports = createTestTimer
<|endoftext|>