<commit_before>#!/usr/bin/env node
/**
 * @license
 * Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
'use strict';
var commander = require('commander');
var concat = require('gulp-concat');
var debug = require('gulp-debug');
var del = require('del');
var fs = require('fs');
var gulp = require('gulp');
var filter = require('gulp-filter');
var mainBowerFiles = require('main-bower-files');
var path = require('path');
var polyclean = require('polyclean');
var replace = require('gulp-replace');
var shell = require('gulp-shell');

var mainImport = require('../lib/main-import');
var gulpsettings = require('../lib/gulpsettings');

commander
  .usage('[options] <components...>')
  .option('-d, --workdir [dir]', 'sets directory used for polymerization. Defaults to polymers/')
  .option('-m, --mainfile [file]', 'Sets debug main file. Defaults to main.html')
  .option('-p, --outfile [file]', 'Sets the output file. Defaults to polymers.html')
  .parse(process.argv)

var workdir = commander.workdir;
if (!workdir) {
  workdir = "polymers";
}
var outfile = commander.outfile;
if (!outfile) {
  outfile = "polymers.html";
}
console.log(workdir);
console.log(outfile);
console.log(commander.args);

function vulcanize(filename, outfile, root) {
  var cmd =  'node_modules/vulcanize/bin/vulcanize';
  cmd = cmd + ' ' + filename + ' > ' + outfile;
  console.log(cmd);
  return cmd
}

function bower(args) {
  var cmd = '../node_modules/bower/bin/bower ';
  return cmd + args
}

function bower_install(components) {
  return bower(' --save install ' + components.join(' '))
}

function bower_init() {
  return bower(' init')
}

gulp.task('clean', function(cb) {
  del([workdir], cb);
});

gulp.task('mkdir', ['clean'], function(cb) {
  fs.mkdir(workdir, null, cb);
});

gulp.task('bower-init', ['mkdir'], function(cb) {
  fs.writeFile(path.join(workdir, 'bower.json'), JSON.stringify(gulpsettings()), cb)
})

gulp.task('bower', ['bower-init'], shell.task(bower_install(commander.args), {cwd: workdir}));

var bowerDir = path.join(workdir, 'bower_components');

gulp.task('component-main', ['bower'], function() {
  return gulp.src(mainBowerFiles({
    paths: {
      bowerJson: path.join(workdir, 'bower.json'),
      bowerDirectory: bowerDir
    }
  }))
  .pipe(filter('**/*.html'))
  .pipe(mainImport())
  .pipe(concat("main.html"))
  .pipe(gulp.dest(process.cwd()));
});

gulp.task('vulcanize',
          ['component-main'],
          shell.task(vulcanize("main.html", outfile)));

gulp.task('polish', ['vulcanize'], function() {
  return gulp.src(outfile)
    .pipe(polyclean.cleanJsComments())
    // Get rid of erroneous html comments
    .pipe(replace(/<!--((?!@license)[^])*?-->/g, ''))
    // Reduce script tags
    .pipe(replace(/<\/script>\s*<script>/g, '\n'))
    // Collapse newlines
    .pipe(replace(/\n\s*\n/g, '\n'))
    // Collapse leading spaces+tabs.
    .pipe(replace(/^[ \t]+/gm, ''))
    .pipe(gulp.dest(process.cwd()));
});

gulp.start('polish');
<commit_msg>remove debug<commit_after>#!/usr/bin/env node
/**
 * @license
 * Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
'use strict';
var commander = require('commander');
var concat = require('gulp-concat');
var del = require('del');
var fs = require('fs');
var gulp = require('gulp');
var filter = require('gulp-filter');
var mainBowerFiles = require('main-bower-files');
var path = require('path');
var polyclean = require('polyclean');
var replace = require('gulp-replace');
var shell = require('gulp-shell');

var mainImport = require('../lib/main-import');
var gulpsettings = require('../lib/gulpsettings');

commander
  .usage('[options] <components...>')
  .option('-d, --workdir [dir]', 'sets directory used for polymerization. Defaults to polymers/')
  .option('-m, --mainfile [file]', 'Sets debug main file. Defaults to main.html')
  .option('-p, --outfile [file]', 'Sets the output file. Defaults to polymers.html')
  .parse(process.argv)

var workdir = commander.workdir;
if (!workdir) {
  workdir = "polymers";
}
var outfile = commander.outfile;
if (!outfile) {
  outfile = "polymers.html";
}
console.log(workdir);
console.log(outfile);
console.log(commander.args);

function vulcanize(filename, outfile, root) {
  var cmd =  'node_modules/vulcanize/bin/vulcanize';
  cmd = cmd + ' ' + filename + ' > ' + outfile;
  console.log(cmd);
  return cmd
}

function bower(args) {
  var cmd = '../node_modules/bower/bin/bower ';
  return cmd + args
}

function bower_install(components) {
  return bower(' --save install ' + components.join(' '))
}

function bower_init() {
  return bower(' init')
}

gulp.task('clean', function(cb) {
  del([workdir], cb);
});

gulp.task('mkdir', ['clean'], function(cb) {
  fs.mkdir(workdir, null, cb);
});

gulp.task('bower-init', ['mkdir'], function(cb) {
  fs.writeFile(path.join(workdir, 'bower.json'), JSON.stringify(gulpsettings()), cb)
})

gulp.task('bower', ['bower-init'], shell.task(bower_install(commander.args), {cwd: workdir}));

var bowerDir = path.join(workdir, 'bower_components');

gulp.task('component-main', ['bower'], function() {
  return gulp.src(mainBowerFiles({
    paths: {
      bowerJson: path.join(workdir, 'bower.json'),
      bowerDirectory: bowerDir
    }
  }))
  .pipe(filter('**/*.html'))
  .pipe(mainImport())
  .pipe(concat("main.html"))
  .pipe(gulp.dest(process.cwd()));
});

gulp.task('vulcanize',
          ['component-main'],
          shell.task(vulcanize("main.html", outfile)));

gulp.task('polish', ['vulcanize'], function() {
  return gulp.src(outfile)
    .pipe(polyclean.cleanJsComments())
    // Get rid of erroneous html comments
    .pipe(replace(/<!--((?!@license)[^])*?-->/g, ''))
    // Reduce script tags
    .pipe(replace(/<\/script>\s*<script>/g, '\n'))
    // Collapse newlines
    .pipe(replace(/\n\s*\n/g, '\n'))
    // Collapse leading spaces+tabs.
    .pipe(replace(/^[ \t]+/gm, ''))
    .pipe(gulp.dest(process.cwd()));
});

gulp.start('polish');
<|endoftext|>


<commit_before>//#!/usr/bin/env node

global.Snakeskin = require('../snakeskin');

var program = require('commander'),
	beautify = require('js-beautify'),
	monocle = require('monocle')();

var path = require('path');
var fs = require('fs'),
	exists = fs.existsSync || path.existsSync;

program
	.version(Snakeskin.VERSION.join('.'))

	.usage('[options] [dir|file ...]')
	.option('-p, --params [src]', 'path to the options file or JS options object')

	.option('-s, --source [src]', 'path to the template file or directory')
	.option('-f, --file [src]', 'path to the template file (meta-information)')
	.option('-m, --mask [mask]', 'mask for a template files (RegExp)')
	.option('-w, --watch', 'watch files for changes and automatically re-render')

	.option('-o, --output [src]', 'path to the file to save')
	.option('--extname [ext]', 'file extension for saving (if "output" is a directory)')
	.option('-n, --common-js', 'common.js export (for node.js)')

	.option('-e, --exec', 'execute compiled template')
	.option('-d, --data [src]', 'path to the data file or JS data object')
	.option('-t, --tpl [name]', 'name of the main template')

	.option('--disable-localization', 'disable support for localization')
	.option('--i18n-fn', 'i18n function name')
	.option('--language [src]', 'path to the localization file or localization object')
	.option('--words [src]', 'path to the localization file to save')

	.option('--ignore', 'regular expression to ignore the empty space')
	.option('--auto-replace', 'enable macros support')
	.option('--macros [src]', 'path to the macros file or JS macros object')

	.option('--disable-xml', 'disable default xml validation')
	.option('--inline-iterators', 'inline forEach and forIn')
	.option('--disable-escape-output', 'disable default "html" filter')

	.option('--render-as [mode]', 'render all templates as "interface" or "placeholder"')
	.option('--render-mode [mode]', 'render all templates in "stringConcat", "stringBuffer" or "dom"')

	.option('--pretty-print', 'formatting output')
	.parse(process.argv);

var params = Snakeskin.toObj(program['params']) || {};

if (params instanceof Object === false) {
	params = {};
}

params.xml = 'disableXml' in program ?
	!program['disableXml'] : params.xml;

params.commonJS = 'commonJs' in program ?
	program['commonJs'] : params.commonJS;

params.localization = 'disableLocalization' in program ?
	!program['disableLocalization'] : params.localization;

params.i18nFn = 'i18nFn' in program ?
	program['i18nFn'] : params.i18nFn;

params.language = 'language' in program ?
	program['language'] : params.language;

params.words = 'words' in program ?
	program['words'] : params.words;

params.renderAs = 'renderAs' in program ?
	program['renderAs'] : params.renderAs;

params.renderMode = 'renderMode' in program ?
	program['renderMode'] : params.renderMode;

params.inlineIterators = 'inlineIterators' in program ?
	program['inlineIterators'] : params.inlineIterators;

params.escapeOutput = 'disableEscapeOutput' in program ?
	!program['disableEscapeOutput'] : params.escapeOutput;

params.prettyPrint = 'prettyPrint' in program ?
	program['prettyPrint'] : params.prettyPrint;

params.ignore = 'ignore' in program ?
	program['ignore'] : params.ignore;

params.autoReplace = 'autoReplace' in program ?
	program['autoReplace'] : params.autoReplace;

params.macros = 'macros' in program ?
	program['macros'] : params.macros;

params.debug = {};
params.cache = false;

var include = {},
	fMap = {},
	watch = program['watch'];

var prettyPrint = params.prettyPrint,
	language = params.language,
	macros = params.macros;

var exec = program['exec'],
	tplData = program['data'],
	mainTpl = program['tpl'];

var words = params.words;

if (words) {
	params.words = {};
}

var args = program['args'],
	input;

var file = program['source'],
	out = program['output'];

if (!file && args.length) {
	input = args.join(' ');

	if (exists(input)) {
		file = input;
		input = false;
	}
}

var calls = {};

function action(data, file) {
	console.time('Time');

	file = file || program['file'] || '';
	var tpls = {},
		fileName = '';

	if (file) {
		fileName = path.basename(file, path.extname(file));
	}

	if (tplData || mainTpl || exec) {
		params.commonJS = true;
		params.context = tpls;
		params.prettyPrint = false;
	}

	function pathTpl(src) {
		return path.normalize(
			src
				.replace(/%fileDir%/g, path.dirname(file))
				.replace(/%fileName%/g, fileName)
				.replace(/%file%/g, path.basename(file))
				.replace(/%filePath%/g, file)
		);
	}

	function load(val) {
		val = pathTpl(val);

		var tmp = val;
		val = path.resolve(val);

		if (exists(val) && fileName && fs.statSync(val).isDirectory()) {
			tmp = path.join(val, fileName) + '.js';

			if (!exists(tmp)) {
				tmp += 'on';
			}
		}

		return Snakeskin.toObj(tmp, null, (src) => {
			if (file) {
				include[src] = include[src] || {};
				include[src][file] = true;
			}
		});
	}

	if (language) {
		params.language = load(language);
	}

	if (macros) {
		params.macros = load(macros);
	}

	function line() {
		console.log(new Array(80).join('~'));
	}

	function success() {
		line();
		console.log(`File "${path.relative(__dirname, file)}" has been successfully compiled "${path.relative(__dirname, outFile)}".`);
		console.timeEnd('Time');
		line();
	}

	var outFile = out,
		execTpl = tplData || mainTpl || exec;

	if (outFile) {
		outFile = pathTpl(outFile);

		let tmp = outFile;
		outFile = path.resolve(outFile);

		if (exists(outFile) && fs.statSync(outFile).isDirectory()) {
			tmp = path.join(tmp, path.basename(file)) + (program['extname'] || (execTpl ? '.html' : '.js'));
		}

		outFile = tmp;
		path.dirname(outFile).split(path.sep).forEach((el, i, data) => {
			var src = data.slice(0, i + 1).join(path.sep);

			if (!exists(src)) {
				fs.mkdirSync(src);
			}
		});

		if (file && (!words || exists(words)) && params.cache !== false) {
			let includes = Snakeskin.check(file, outFile, Snakeskin.compile(null, params, null, {cacheKey: true}), true);

			if (includes) {
				success();

				include[file] = include[file] || {};
				include[file][file] = true;

				includes.forEach((key) => {
					include[key] = include[key] || {};
					include[key][file] = true;
				});

				return;
			}
		}
	}

	var res = Snakeskin.compile(
		String(data),
		params,
		{file}
	);

	var toConsole = input && !program['output'] ||
		!outFile;

	if (res !== false) {
		if (execTpl) {
			let tpl;

			if (mainTpl && mainTpl !== true) {
				tpl = tpls[mainTpl];

			} else {
				if (file) {
					tpl = tpls[fileName] || tpls.main || tpls[Object.keys(tpls)[0]];

				} else {
					tpl = tpls.main || tpls[Object.keys(tpls)[0]];
				}
			}

			if (!tpl) {
				console.error('Template is not defined');

				if (!watch) {
					process.exit(1);
				}

			} else {
				let dataObj;
				if (tplData && tplData !== true) {
					dataObj = load(tplData);
				}

				res = tpl(dataObj);
				if (prettyPrint) {
					if (toConsole) {
						res = beautify['html'](res);

					} else {
						res = (beautify[path.extname(outFile).replace(/^\./, '')] || beautify['html'])(res);
					}
				}
			}
		}

		if (toConsole) {
			console.log(res);

		} else {
			fs.writeFileSync(outFile, res);
			success();

			let tmp = params.debug.files;

			include[file] = include[file] || {};
			include[file][file] = true;

			if (tmp) {
				for (let key in tmp) {
					if (!tmp.hasOwnProperty(key)) {
						continue;
					}

					include[key] = include[key] || {};
					include[key][file] = true;
				}
			}
		}

	} else {
		if (!watch) {
			process.exit(1);
		}
	}
}

function end() {
	if (words) {
		path.dirname(words).split(path.sep).forEach((el, i, data) => {
			var src = data.slice(0, i + 1).join(path.sep);

			if (!exists(src)) {
				fs.mkdirSync(src);
			}
		});

		fs.writeFileSync(words, JSON.stringify(params.words, null, '\t'));
	}
}

if (!file && input == null) {
	let buf = '';
	let stdin = process.stdin,
		stdout = process.stdout;

	stdin.setEncoding('utf8');
	stdin.on('data', (chunk) => {
		buf += chunk;
	});

	stdin.on('end', () => {
		action(buf);
		end();
	}).resume();

	process.on('SIGINT', () => {
		stdout.write('\n');
		stdin.emit('end');
		stdout.write('\n');
		process.exit();
	});

} else {
	if (file) {
		file = path.normalize(path.resolve(file));

		let isDir = fs.statSync(file).isDirectory(),
			mask = program['mask'];

		mask = mask &&
			new RegExp(mask);

		let watchDir = () => {
			monocle.watchDirectory({
				root: file,
				listener: (f) => {
					var src = f.fullPath;
					if (!fMap[src] && !f.stat.isDirectory() && (mask ? mask.test(src) : path.extname(src) === '.ss')) {
						monocle.unwatchAll();
						action(fs.readFileSync(src), src);
						wacthFiles();
					}
				}
			});
		};

		let wacthFiles = () => {
			let files = [];
			for (let key in include) {
				if (!include.hasOwnProperty(key)) {
					continue;
				}

				fMap[key] = true;
				files.push(key);
			}

			monocle.watchFiles({
				files: files,
				listener: (f) => {
					var src = f.fullPath,
						files = include[src];

					if (files && !calls[src]) {
						calls[src] = setTimeout(() => {
							monocle.unwatchAll();

							for (let key in files) {
								if (!files.hasOwnProperty(key)) {
									continue;
								}

								if ((!mask || mask.test(key))) {
									if (exists(key)) {
										action(fs.readFileSync(key), key);

									} else {
										delete fMap[key];
									}
								}
							}

							delete calls[src];
							wacthFiles();
						}, 60);
					}

					end();
				}
			});

			if (isDir) {
				watchDir();
			}
		};

		if (fs.statSync(file).isDirectory()) {
			var renderDir = (dir) => {
				fs.readdirSync(dir).forEach((el) => {
					var src = path.join(dir, el);

					if (fs.statSync(src).isDirectory()) {
						renderDir(src);

					} else if (mask ? mask.test(src) : path.extname(el) === '.ss') {
						action(fs.readFileSync(src), src);
					}
				});
			};

			renderDir(file);

		} else if (!mask || mask.test(file)) {
			action(fs.readFileSync(file), file);
		}

		if (watch) {
			wacthFiles();
		}

	} else {
		action(input);
	}

	end();
}
<commit_msg>Добавлен флаг --tolerate-whitespace<commit_after>//#!/usr/bin/env node

global.Snakeskin = require('../snakeskin');

var program = require('commander'),
	beautify = require('js-beautify'),
	monocle = require('monocle')();

var path = require('path');
var fs = require('fs'),
	exists = fs.existsSync || path.existsSync;

program
	.version(Snakeskin.VERSION.join('.'))

	.usage('[options] [dir|file ...]')
	.option('-p, --params [src]', 'path to the options file or JS options object')

	.option('-s, --source [src]', 'path to the template file or directory')
	.option('-f, --file [src]', 'path to the template file (meta-information)')
	.option('-m, --mask [mask]', 'mask for a template files (RegExp)')
	.option('-w, --watch', 'watch files for changes and automatically re-render')

	.option('-o, --output [src]', 'path to the file to save')
	.option('--extname [ext]', 'file extension for saving (if "output" is a directory)')
	.option('-n, --common-js', 'common.js export (for node.js)')

	.option('-e, --exec', 'execute compiled template')
	.option('-d, --data [src]', 'path to the data file or JS data object')
	.option('-t, --tpl [name]', 'name of the main template')

	.option('--disable-localization', 'disable support for localization')
	.option('--i18n-fn', 'i18n function name')
	.option('--language [src]', 'path to the localization file or localization object')
	.option('--words [src]', 'path to the localization file to save')

	.option('--tolerate-whitespace', 'tolerate whitespace characters in the template')
	.option('--ignore', 'regular expression to ignore the empty space')
	.option('--auto-replace', 'enable macros support')
	.option('--macros [src]', 'path to the macros file or JS macros object')

	.option('--disable-xml', 'disable default xml validation')
	.option('--inline-iterators', 'inline forEach and forIn')
	.option('--disable-escape-output', 'disable default "html" filter')

	.option('--render-as [mode]', 'render all templates as "interface" or "placeholder"')
	.option('--render-mode [mode]', 'render all templates in "stringConcat", "stringBuffer" or "dom"')

	.option('--pretty-print', 'formatting output')
	.parse(process.argv);

var params = Snakeskin.toObj(program['params']) || {};

if (params instanceof Object === false) {
	params = {};
}

params.xml = 'disableXml' in program ?
	!program['disableXml'] : params.xml;

params.commonJS = 'commonJs' in program ?
	program['commonJs'] : params.commonJS;

params.localization = 'disableLocalization' in program ?
	!program['disableLocalization'] : params.localization;

params.i18nFn = 'i18nFn' in program ?
	program['i18nFn'] : params.i18nFn;

params.language = 'language' in program ?
	program['language'] : params.language;

params.words = 'words' in program ?
	program['words'] : params.words;

params.renderAs = 'renderAs' in program ?
	program['renderAs'] : params.renderAs;

params.renderMode = 'renderMode' in program ?
	program['renderMode'] : params.renderMode;

params.inlineIterators = 'inlineIterators' in program ?
	program['inlineIterators'] : params.inlineIterators;

params.escapeOutput = 'disableEscapeOutput' in program ?
	!program['disableEscapeOutput'] : params.escapeOutput;

params.prettyPrint = 'prettyPrint' in program ?
	program['prettyPrint'] : params.prettyPrint;

params.tolerateWhitespace = 'tolerateWhitespace' in program ?
	program['tolerateWhitespace'] : params.tolerateWhitespace;

params.ignore = 'ignore' in program ?
	program['ignore'] : params.ignore;

params.autoReplace = 'autoReplace' in program ?
	program['autoReplace'] : params.autoReplace;

params.macros = 'macros' in program ?
	program['macros'] : params.macros;

params.debug = {};
params.cache = false;

var include = {},
	fMap = {},
	watch = program['watch'];

var prettyPrint = params.prettyPrint,
	language = params.language,
	macros = params.macros;

var exec = program['exec'],
	tplData = program['data'],
	mainTpl = program['tpl'];

var words = params.words;

if (words) {
	params.words = {};
}

var args = program['args'],
	input;

var file = program['source'],
	out = program['output'];

if (!file && args.length) {
	input = args.join(' ');

	if (exists(input)) {
		file = input;
		input = false;
	}
}

var calls = {};

function action(data, file) {
	console.time('Time');

	file = file || program['file'] || '';
	var tpls = {},
		fileName = '';

	if (file) {
		fileName = path.basename(file, path.extname(file));
	}

	if (tplData || mainTpl || exec) {
		params.commonJS = true;
		params.context = tpls;
		params.prettyPrint = false;
	}

	function pathTpl(src) {
		return path.normalize(
			src
				.replace(/%fileDir%/g, path.dirname(file))
				.replace(/%fileName%/g, fileName)
				.replace(/%file%/g, path.basename(file))
				.replace(/%filePath%/g, file)
		);
	}

	function load(val) {
		val = pathTpl(val);

		var tmp = val;
		val = path.resolve(val);

		if (exists(val) && fileName && fs.statSync(val).isDirectory()) {
			tmp = path.join(val, fileName) + '.js';

			if (!exists(tmp)) {
				tmp += 'on';
			}
		}

		return Snakeskin.toObj(tmp, null, (src) => {
			if (file) {
				include[src] = include[src] || {};
				include[src][file] = true;
			}
		});
	}

	if (language) {
		params.language = load(language);
	}

	if (macros) {
		params.macros = load(macros);
	}

	function line() {
		console.log(new Array(80).join('~'));
	}

	function success() {
		line();
		console.log(`File "${path.relative(__dirname, file)}" has been successfully compiled "${path.relative(__dirname, outFile)}".`);
		console.timeEnd('Time');
		line();
	}

	var outFile = out,
		execTpl = tplData || mainTpl || exec;

	if (outFile) {
		outFile = pathTpl(outFile);

		let tmp = outFile;
		outFile = path.resolve(outFile);

		if (exists(outFile) && fs.statSync(outFile).isDirectory()) {
			tmp = path.join(tmp, path.basename(file)) + (program['extname'] || (execTpl ? '.html' : '.js'));
		}

		outFile = tmp;
		path.dirname(outFile).split(path.sep).forEach((el, i, data) => {
			var src = data.slice(0, i + 1).join(path.sep);

			if (!exists(src)) {
				fs.mkdirSync(src);
			}
		});

		if (file && (!words || exists(words)) && params.cache !== false) {
			let includes = Snakeskin.check(file, outFile, Snakeskin.compile(null, params, null, {cacheKey: true}), true);

			if (includes) {
				success();

				include[file] = include[file] || {};
				include[file][file] = true;

				includes.forEach((key) => {
					include[key] = include[key] || {};
					include[key][file] = true;
				});

				return;
			}
		}
	}

	var res = Snakeskin.compile(
		String(data),
		params,
		{file}
	);

	var toConsole = input && !program['output'] ||
		!outFile;

	if (res !== false) {
		if (execTpl) {
			let tpl;

			if (mainTpl && mainTpl !== true) {
				tpl = tpls[mainTpl];

			} else {
				if (file) {
					tpl = tpls[fileName] || tpls.main || tpls[Object.keys(tpls)[0]];

				} else {
					tpl = tpls.main || tpls[Object.keys(tpls)[0]];
				}
			}

			if (!tpl) {
				console.error('Template is not defined');

				if (!watch) {
					process.exit(1);
				}

			} else {
				let dataObj;
				if (tplData && tplData !== true) {
					dataObj = load(tplData);
				}

				res = tpl(dataObj);
				if (prettyPrint) {
					if (toConsole) {
						res = beautify['html'](res);

					} else {
						res = (beautify[path.extname(outFile).replace(/^\./, '')] || beautify['html'])(res);
					}
				}
			}
		}

		if (toConsole) {
			console.log(res);

		} else {
			fs.writeFileSync(outFile, res);
			success();

			let tmp = params.debug.files;

			include[file] = include[file] || {};
			include[file][file] = true;

			if (tmp) {
				for (let key in tmp) {
					if (!tmp.hasOwnProperty(key)) {
						continue;
					}

					include[key] = include[key] || {};
					include[key][file] = true;
				}
			}
		}

	} else {
		if (!watch) {
			process.exit(1);
		}
	}
}

function end() {
	if (words) {
		path.dirname(words).split(path.sep).forEach((el, i, data) => {
			var src = data.slice(0, i + 1).join(path.sep);

			if (!exists(src)) {
				fs.mkdirSync(src);
			}
		});

		fs.writeFileSync(words, JSON.stringify(params.words, null, '\t'));
	}
}

if (!file && input == null) {
	let buf = '';
	let stdin = process.stdin,
		stdout = process.stdout;

	stdin.setEncoding('utf8');
	stdin.on('data', (chunk) => {
		buf += chunk;
	});

	stdin.on('end', () => {
		action(buf);
		end();
	}).resume();

	process.on('SIGINT', () => {
		stdout.write('\n');
		stdin.emit('end');
		stdout.write('\n');
		process.exit();
	});

} else {
	if (file) {
		file = path.normalize(path.resolve(file));

		let isDir = fs.statSync(file).isDirectory(),
			mask = program['mask'];

		mask = mask &&
			new RegExp(mask);

		let watchDir = () => {
			monocle.watchDirectory({
				root: file,
				listener: (f) => {
					var src = f.fullPath;
					if (!fMap[src] && !f.stat.isDirectory() && (mask ? mask.test(src) : path.extname(src) === '.ss')) {
						monocle.unwatchAll();
						action(fs.readFileSync(src), src);
						wacthFiles();
					}
				}
			});
		};

		let wacthFiles = () => {
			let files = [];
			for (let key in include) {
				if (!include.hasOwnProperty(key)) {
					continue;
				}

				fMap[key] = true;
				files.push(key);
			}

			monocle.watchFiles({
				files: files,
				listener: (f) => {
					var src = f.fullPath,
						files = include[src];

					if (files && !calls[src]) {
						calls[src] = setTimeout(() => {
							monocle.unwatchAll();

							for (let key in files) {
								if (!files.hasOwnProperty(key)) {
									continue;
								}

								if ((!mask || mask.test(key))) {
									if (exists(key)) {
										action(fs.readFileSync(key), key);

									} else {
										delete fMap[key];
									}
								}
							}

							delete calls[src];
							wacthFiles();
						}, 60);
					}

					end();
				}
			});

			if (isDir) {
				watchDir();
			}
		};

		if (fs.statSync(file).isDirectory()) {
			var renderDir = (dir) => {
				fs.readdirSync(dir).forEach((el) => {
					var src = path.join(dir, el);

					if (fs.statSync(src).isDirectory()) {
						renderDir(src);

					} else if (mask ? mask.test(src) : path.extname(el) === '.ss') {
						action(fs.readFileSync(src), src);
					}
				});
			};

			renderDir(file);

		} else if (!mask || mask.test(file)) {
			action(fs.readFileSync(file), file);
		}

		if (watch) {
			wacthFiles();
		}

	} else {
		action(input);
	}

	end();
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict'

process.title = 'styled-svg'

// setup CLI options and usage
const commandLineArgs = require('command-line-args')

const optionsDefinitions = [
  {
    name: 'input',
    alias: 'i',
    description: 'The input files to process.',
    type: String,
    multiple: true,
    defaultOption: true,
    defaultValue: ['**/*.svg'],
    typeLabel: '<files>'
  },
  {
    name: 'clean',
    description: 'Clears the output directory before generating.',
    type: Boolean
  },
  {
    name: 'dry-run',
    description: 'Outputs the changes to console instead of writing them',
    type: Boolean
  },
  {
    name: 'output-dir',
    description: 'The directory to output components to. This defaults to the directory of the svg.',
    type: String
  },
  {
    name: 'test-dir',
    description: 'The directory to output tests to. This is relative to the output directory',
    type: String
  },
  {
    name: 'templates-dir',
    description: 'The directory to use for templates',
    type: String
  },
  {
    name: 'help',
    alias: 'h',
    type: Boolean,
    description: 'Displays this usage guide.'
  }
]

const options = commandLineArgs(optionsDefinitions)

if (options.help || options._unknown) {
  const usage = require('command-line-usage')([
    {
      header: 'styled-svg',
      content: 'Generate styled-components from SVG files.'
    },
    {
      header: 'Options',
      optionList: optionsDefinitions
    }
  ])
  console.log(usage)
} else {
  // shim friendly options
  options.outputDir = options['output-dir']
  options.testDir = options['test-dir']
  options.templatesDir = options['templates-dir']
  options.dryRun = options['dry-run']

  // execute on sources
  const globby = require('globby')
  const convert = require('..')

  globby(options.input)
    .then((files) => {
      convert(files, options)
    })
    .catch((err) => {
      console.log(err.stack)
      process.exit(1)
    })
}
<commit_msg>Add default description<commit_after>#!/usr/bin/env node

'use strict'

process.title = 'styled-svg'

// setup CLI options and usage
const commandLineArgs = require('command-line-args')

const optionsDefinitions = [
  {
    name: 'input',
    alias: 'i',
    description: 'The input files to process.',
    type: String,
    multiple: true,
    defaultOption: true,
    defaultValue: ['**/*.svg'],
    typeLabel: '<files>'
  },
  {
    name: 'clean',
    description: 'Clears the output directory before generating.',
    type: Boolean
  },
  {
    name: 'dry-run',
    description: 'Outputs the changes to console instead of writing them',
    type: Boolean
  },
  {
    name: 'output-dir',
    description: 'The directory to output components to. This defaults to the directory of the svg.',
    type: String
  },
  {
    name: 'test-dir',
    description: 'The directory to output tests to. This is relative to the output directory',
    type: String
  },
  {
    name: 'templates-dir',
    description: 'The directory to use for templates. Defaults to internal templates',
    type: String
  },
  {
    name: 'help',
    alias: 'h',
    type: Boolean,
    description: 'Displays this usage guide.'
  }
]

const options = commandLineArgs(optionsDefinitions)

if (options.help || options._unknown) {
  const usage = require('command-line-usage')([
    {
      header: 'styled-svg',
      content: 'Generate styled-components from SVG files.'
    },
    {
      header: 'Options',
      optionList: optionsDefinitions
    }
  ])
  console.log(usage)
} else {
  // shim friendly options
  options.outputDir = options['output-dir']
  options.testDir = options['test-dir']
  options.templatesDir = options['templates-dir']
  options.dryRun = options['dry-run']

  // execute on sources
  const globby = require('globby')
  const convert = require('..')

  globby(options.input)
    .then((files) => {
      convert(files, options)
    })
    .catch((err) => {
      console.log(err.stack)
      process.exit(1)
    })
}
<|endoftext|>


<commit_before>import GMusic, { GMusicNamespace } from 'gmusic.js';

const fs = require('fs');

// DEV: These constants will be transformed into string constants by browserify
const BASE_CSS = fs.readFileSync(__dirname + '/../build/rework.css', 'utf8'); // eslint-disable-line
const CONSTANTS = require('../lib/_constants');

export default class GMusicMiniPlayerController extends GMusicNamespace {
  constructor(...args) {
    super(...args);

    this.GPM_API = new GMusic(window);
    this.SELECTORS = GMusic.SELECTORS;

    this._initCSS();
    this._initMiniPlayerUI();
    this._initMiniPlayerNowPlayingMonitor();
    this._initMiniPlayerTimingUI();
    this._initMiniPlayerTimingMonitor();
    this._initMiniPlayerRadioMonitor();

    this.miniState = false;
    this.scrollVolume = true;

    this._initGlobalEventHandlers();

    this.addMethods([
      'enable',
      'disable',
      'toggle',
      'enableButton',
      'disableButton',
      'showControlsWhen',
      'setScrollVolume',
      'getScrollVolume',
    ]);
  }

  _initCSS() {
    const styleElement = document.createElement('style');
    styleElement.innerHTML = BASE_CSS;
    document.body.appendChild(styleElement);
  }

  _initMiniPlayerUI() {
    this.miniNowPlayerInfo = document.createElement('div');
    this.miniAlbumArt = document.createElement('img');

    // DEV: Configure mini player elements
    this.miniNowPlayerInfo.id = 'mini-info';
    this.miniNowPlayerInfo.setAttribute('style', 'display: none');
    this.miniNowPlayerInfo.innerHTML = '';

    this.miniAlbumArt.id = 'mini-album';
    // DEV: Placeholder image
    this.miniAlbumArt.src = 'https://www.samuelattard.com/img/gpm_placeholder.jpg';
    this.miniAlbumArt.setAttribute('style', 'display: none');
    // DEV: If the album art load ever fails, use the placeholder
    this.miniAlbumArt.addEventListener('error', (e) => {
      e.target.src = 'https://www.samuelattard.com/img/gpm_placeholder.jpg'; // eslint-disable-line
    });
    // DEV: Prevent dragging of the album image
    this.miniAlbumArt.addEventListener('mousedown', (e) => {
      e.preventDefault();
    });

    document.body.appendChild(this.miniNowPlayerInfo);
    document.body.appendChild(this.miniAlbumArt);
  }

  _initMiniPlayerTimingUI() {
    const player = document.getElementById('player');
    const container = document.createElement('div');
    this.timeSpan_SoFar = document.createElement('span');
    this.timeSpan_Total = document.createElement('span');

    this.timeSpan_SoFar.classList.add('mini-timespan-c');
    this.timeSpan_SoFar.setAttribute('style', 'display: none');
    this.timeSpan_SoFar.innerHTML = '0:00';
    player.appendChild(this.timeSpan_SoFar);

    this.timeSpan_Total.classList.add('mini-timespan-t');
    this.timeSpan_Total.setAttribute('style', 'display: none');
    this.timeSpan_Total.innerHTML = '0:00';
    player.appendChild(this.timeSpan_Total);

    container.innerHTML = `
      <paper-icon-button
        data-id="show-miniplayer-dp"
        icon="open-in-new"
        title="Show mini player"
        aria-label="Show mini player"
        role="button"
        tabindex="0"
        no-focus="">
      </paper-icon-button>`;
    this.miniButtonElement = container.querySelectorAll('[data-id="show-miniplayer-dp"]')[0];
    this.miniButtonElement.addEventListener('click', (e) => {
      this.getControls().toggle();
      e.target.blur();
      this.miniButtonElement.style.display = 'none';
      document.body.removeAttribute('ready');
      setTimeout(() => {
        this.miniButtonElement.style.display = 'block';
      }, 400);
      e.preventDefault();
      return false;
    });
    document.getElementById('player').appendChild(container);
  }

  _initMiniPlayerTimingMonitor() {
    this.GPM_API.on('change:playback-time', (e) => {
      this.timeSpan_SoFar.innerHTML = (e.current ? this._timeFormat(e.current) : '0:00');
      this.timeSpan_Total.innerHTML = (e.total ? this._timeFormat(e.total) : '0:00');
    });
  }

  _initMiniPlayerRadioMonitor() {
    this.GPM_API.on('change:playback', this._radioMonitor.bind(this));
    this.GPM_API.on('change:playback-time', this._radioMonitor.bind(this));
    this.GPM_API.on('change:song', this._radioMonitor.bind(this));
  }

  _radioMonitor() {
    const repeatElement = document.querySelectorAll(this.SELECTORS.controlsSelectors.repeat);
    const player = document.querySelector('#player');
    if (repeatElement && repeatElement[0] && player) {
      if (repeatElement[0].style.display === 'none') {
        if (player.getAttribute('radio') === null) {
          player.setAttribute('radio', 'on');
        }
      } else if (player.getAttribute('radio') !== null) {
        player.removeAttribute('radio');
      }
    }
  }

  _initMiniPlayerNowPlayingMonitor() {
    this.GPM_API.on('change:song', (e) => {
      this.miniAlbumArt.src = e.art.replace('=s90', '=s300');
      const infoSpans = this.miniNowPlayerInfo.getElementsByTagName('span');
      infoSpans[0].innerHTML = e.title;
      infoSpans[1].innerHTML = `${e.artist} - ${e.album}`;
    });
  }

  _initGlobalEventHandlers() {
    // DEV: Scroll to change volume in mini player mode
    window.addEventListener('mousewheel', (e) => {
      if (!this.scrollVolume) return;
      if (this.miniState) {
        if (e.wheelDelta < 0) {
          this.GPM_API.volume.decreaseVolume();
        } else {
          this.GPM_API.volume.increaseVolume();
        }
      }
    });

    // DEV: Handle abstract resizing of the window
    document.body.addEventListener('mousemove', () => {
      if (this.miniState && this.miniButtonElement.style.display !== 'none') {
        document.body.setAttribute('ready', 'ready');
      }
    });

    // DEV: When in mini player mode implementees might want to drag the window
    document.addEventListener('mousedown', (e) => {
      if (this.miniState && e.clientY <= 210) {
        this._fire('dragstart');
        e.preventDefault();
        e.stopPropagation();
        return false;
      }
      return true;
    });
  }

  _timeFormat(milli) {
    const totalSeconds = Math.floor(milli / 1000);
    const minutes = Math.floor(totalSeconds / 60);
    const seconds = totalSeconds % 60;
    return `${minutes}:${(seconds < 10 ? `0${seconds}` : seconds)}`;
  }

  enable() {
    let delay = 0;
    this.miniState = true;
    // close menu
    const closeBtn = document.getElementById('left-nav-close-button');
    if (closeBtn !== null) {
      closeBtn.click();
    }
    // DEV: Allow a syncronous callback to handle the enable event and delay by X milliseconds
    this.emit('mini:enable', (newDelay) => {
      delay = newDelay;
    });
    setTimeout(() => {
      document.querySelector('html').classList.add(CONSTANTS.CLASS_NAMESPACE);
    }, delay);
  }

  disable() {
    let delay = 0;
    this.miniState = false;
    // DEV: Allow a syncronous callback to handle the disable event and delay by X milliseconds
    this.emit('mini:disable', (newDelay) => {
      delay = newDelay;
    });
    setTimeout(() => {
      document.querySelector('html').classList.remove(CONSTANTS.CLASS_NAMESPACE);
    }, delay);
  }

  toggle() {
    if (this.miniState) {
      this.disable();
    } else {
      this.enable();
    }
  }

  enableButton() {
    this.miniButtonElement.style.display = 'block';
  }

  disableButton() {
    this.miniButtonElement.style.display = 'none';
  }

  showControlsWhen(when) {
    if (when === 'hover') {
      document.body.removeAttribute('controls');
    } else {
      document.body.setAttribute('controls', 'controls');
    }
  }

  setScrollVolume(state) {
    this.scrollVolume = state;
  }

  getScrollVolume() {
    return this.scrollVolume;
  }
}
<commit_msg>'getControls' is not a thing<commit_after>import GMusic, { GMusicNamespace } from 'gmusic.js';

const fs = require('fs');

// DEV: These constants will be transformed into string constants by browserify
const BASE_CSS = fs.readFileSync(__dirname + '/../build/rework.css', 'utf8'); // eslint-disable-line
const CONSTANTS = require('../lib/_constants');

export default class GMusicMiniPlayerController extends GMusicNamespace {
  constructor(...args) {
    super(...args);

    this.GPM_API = new GMusic(window);
    this.SELECTORS = GMusic.SELECTORS;

    this._initCSS();
    this._initMiniPlayerUI();
    this._initMiniPlayerNowPlayingMonitor();
    this._initMiniPlayerTimingUI();
    this._initMiniPlayerTimingMonitor();
    this._initMiniPlayerRadioMonitor();

    this.miniState = false;
    this.scrollVolume = true;

    this._initGlobalEventHandlers();

    this.addMethods([
      'enable',
      'disable',
      'toggle',
      'enableButton',
      'disableButton',
      'showControlsWhen',
      'setScrollVolume',
      'getScrollVolume',
    ]);
  }

  _initCSS() {
    const styleElement = document.createElement('style');
    styleElement.innerHTML = BASE_CSS;
    document.body.appendChild(styleElement);
  }

  _initMiniPlayerUI() {
    this.miniNowPlayerInfo = document.createElement('div');
    this.miniAlbumArt = document.createElement('img');

    // DEV: Configure mini player elements
    this.miniNowPlayerInfo.id = 'mini-info';
    this.miniNowPlayerInfo.setAttribute('style', 'display: none');
    this.miniNowPlayerInfo.innerHTML = '';

    this.miniAlbumArt.id = 'mini-album';
    // DEV: Placeholder image
    this.miniAlbumArt.src = 'https://www.samuelattard.com/img/gpm_placeholder.jpg';
    this.miniAlbumArt.setAttribute('style', 'display: none');
    // DEV: If the album art load ever fails, use the placeholder
    this.miniAlbumArt.addEventListener('error', (e) => {
      e.target.src = 'https://www.samuelattard.com/img/gpm_placeholder.jpg'; // eslint-disable-line
    });
    // DEV: Prevent dragging of the album image
    this.miniAlbumArt.addEventListener('mousedown', (e) => {
      e.preventDefault();
    });

    document.body.appendChild(this.miniNowPlayerInfo);
    document.body.appendChild(this.miniAlbumArt);
  }

  _initMiniPlayerTimingUI() {
    const player = document.getElementById('player');
    const container = document.createElement('div');
    this.timeSpan_SoFar = document.createElement('span');
    this.timeSpan_Total = document.createElement('span');

    this.timeSpan_SoFar.classList.add('mini-timespan-c');
    this.timeSpan_SoFar.setAttribute('style', 'display: none');
    this.timeSpan_SoFar.innerHTML = '0:00';
    player.appendChild(this.timeSpan_SoFar);

    this.timeSpan_Total.classList.add('mini-timespan-t');
    this.timeSpan_Total.setAttribute('style', 'display: none');
    this.timeSpan_Total.innerHTML = '0:00';
    player.appendChild(this.timeSpan_Total);

    container.innerHTML = `
      <paper-icon-button
        data-id="show-miniplayer-dp"
        icon="open-in-new"
        title="Show mini player"
        aria-label="Show mini player"
        role="button"
        tabindex="0"
        no-focus="">
      </paper-icon-button>`;
    this.miniButtonElement = container.querySelectorAll('[data-id="show-miniplayer-dp"]')[0];
    this.miniButtonElement.addEventListener('click', (e) => {
      this.toggle();
      e.target.blur();
      this.miniButtonElement.style.display = 'none';
      document.body.removeAttribute('ready');
      setTimeout(() => {
        this.miniButtonElement.style.display = 'block';
      }, 400);
      e.preventDefault();
      return false;
    });
    document.getElementById('player').appendChild(container);
  }

  _initMiniPlayerTimingMonitor() {
    this.GPM_API.on('change:playback-time', (e) => {
      this.timeSpan_SoFar.innerHTML = (e.current ? this._timeFormat(e.current) : '0:00');
      this.timeSpan_Total.innerHTML = (e.total ? this._timeFormat(e.total) : '0:00');
    });
  }

  _initMiniPlayerRadioMonitor() {
    this.GPM_API.on('change:playback', this._radioMonitor.bind(this));
    this.GPM_API.on('change:playback-time', this._radioMonitor.bind(this));
    this.GPM_API.on('change:song', this._radioMonitor.bind(this));
  }

  _radioMonitor() {
    const repeatElement = document.querySelectorAll(this.SELECTORS.controlsSelectors.repeat);
    const player = document.querySelector('#player');
    if (repeatElement && repeatElement[0] && player) {
      if (repeatElement[0].style.display === 'none') {
        if (player.getAttribute('radio') === null) {
          player.setAttribute('radio', 'on');
        }
      } else if (player.getAttribute('radio') !== null) {
        player.removeAttribute('radio');
      }
    }
  }

  _initMiniPlayerNowPlayingMonitor() {
    this.GPM_API.on('change:song', (e) => {
      this.miniAlbumArt.src = e.art.replace('=s90', '=s300');
      const infoSpans = this.miniNowPlayerInfo.getElementsByTagName('span');
      infoSpans[0].innerHTML = e.title;
      infoSpans[1].innerHTML = `${e.artist} - ${e.album}`;
    });
  }

  _initGlobalEventHandlers() {
    // DEV: Scroll to change volume in mini player mode
    window.addEventListener('mousewheel', (e) => {
      if (!this.scrollVolume) return;
      if (this.miniState) {
        if (e.wheelDelta < 0) {
          this.GPM_API.volume.decreaseVolume();
        } else {
          this.GPM_API.volume.increaseVolume();
        }
      }
    });

    // DEV: Handle abstract resizing of the window
    document.body.addEventListener('mousemove', () => {
      if (this.miniState && this.miniButtonElement.style.display !== 'none') {
        document.body.setAttribute('ready', 'ready');
      }
    });

    // DEV: When in mini player mode implementees might want to drag the window
    document.addEventListener('mousedown', (e) => {
      if (this.miniState && e.clientY <= 210) {
        this._fire('dragstart');
        e.preventDefault();
        e.stopPropagation();
        return false;
      }
      return true;
    });
  }

  _timeFormat(milli) {
    const totalSeconds = Math.floor(milli / 1000);
    const minutes = Math.floor(totalSeconds / 60);
    const seconds = totalSeconds % 60;
    return `${minutes}:${(seconds < 10 ? `0${seconds}` : seconds)}`;
  }

  enable() {
    let delay = 0;
    this.miniState = true;
    // close menu
    const closeBtn = document.getElementById('left-nav-close-button');
    if (closeBtn !== null) {
      closeBtn.click();
    }
    // DEV: Allow a syncronous callback to handle the enable event and delay by X milliseconds
    this.emit('mini:enable', (newDelay) => {
      delay = newDelay;
    });
    setTimeout(() => {
      document.querySelector('html').classList.add(CONSTANTS.CLASS_NAMESPACE);
    }, delay);
  }

  disable() {
    let delay = 0;
    this.miniState = false;
    // DEV: Allow a syncronous callback to handle the disable event and delay by X milliseconds
    this.emit('mini:disable', (newDelay) => {
      delay = newDelay;
    });
    setTimeout(() => {
      document.querySelector('html').classList.remove(CONSTANTS.CLASS_NAMESPACE);
    }, delay);
  }

  toggle() {
    if (this.miniState) {
      this.disable();
    } else {
      this.enable();
    }
  }

  enableButton() {
    this.miniButtonElement.style.display = 'block';
  }

  disableButton() {
    this.miniButtonElement.style.display = 'none';
  }

  showControlsWhen(when) {
    if (when === 'hover') {
      document.body.removeAttribute('controls');
    } else {
      document.body.setAttribute('controls', 'controls');
    }
  }

  setScrollVolume(state) {
    this.scrollVolume = state;
  }

  getScrollVolume() {
    return this.scrollVolume;
  }
}
<|endoftext|>


<commit_before>define([
	'goo/math/Vector3',
	'goo/math/Matrix3x3',
	'goo/math/Matrix4x4'
],
/** @lends */
function (
	Vector3,
	Matrix3x3,
	Matrix4x4
) {
	"use strict";

	/**
	 * @class Transform models a transformation in 3d space as: Y = M*X+T, with M being a Matrix3 and T is a Vector3. Generally M will be a rotation
	 *        only matrix in which case it is represented by the matrix and scale fields as R*S, where S is a positive scale vector. For non-uniform
	 *        scales and reflections, use setMatrix, which will consider M as being a general 3x3 matrix and disregard anything set in scale.
	 */
	function Transform() {
		/** Read only, will be updated automatically by {@link Transform.update}
		 * @type {Matrix4x4}
		 */
		this.matrix = new Matrix4x4();
		this.normalMatrix = new Matrix4x4();

		/** @type {Vector3} */
		this.translation = new Vector3();
		/** @type {Matrix3x3} */
		this.rotation = new Matrix3x3();
		/** @type {Vector3} */
		this.scale = new Vector3(1, 1, 1);

		this.tmpVec = new Vector3();
		this.tmpVec2 = new Vector3();
		this.tmpMat1 = new Matrix3x3();
	}

	/**
	 * Combines two transforms into one. This will only work if scaling in the left hand transform is uniform
	 * @param {Transform} lhs left hand side transform
	 * @param {Transform} rhs right hand side transform
	 * @param {Transform} target
	 * @returns {Transform} target
	 */
	Transform.combine = function(lhs, rhs, target) {
		if(lhs.scale.data[0] !== lhs.scale.data[1] || lhs.scale.data[0] !== lhs.scale.data[2]) {
			throw {
				name: 'NonUniformScaleException',
				message: 'Non-uniform scaling in left hand transform, cannot resolve combined transform'
			};
		}
		target = target || new Transform();

		// Translation
		var tmpVec = target.tmpVec;
		tmpVec.setv(rhs.translation);
		// Rotate translation
		lhs.rotation.applyPost(tmpVec);
		// Scale translation
		tmpVec.mulv(lhs.scale);
		// Translate translation
		tmpVec.addv(lhs.translation);

		// Scale
		var tmpVec2 = target.tmpVec2;
		tmpVec2.setv(rhs.scale);
		// Scale scale
		tmpVec2.mulv(lhs.scale);

		// Rotation
		var tmpMat1 = target.tmpMat1;
		// Rotate rotation
		Matrix3x3.combine(lhs.rotation, rhs.rotation, tmpMat1);

		target.rotation.copy(tmpMat1);
		target.scale.setv(tmpVec2);
		target.translation.setv(tmpVec);

		target.update();

		return target;
	};

	/**
	 * Combines new transform into this one. This will only work if scaling in the left hand transform is uniform
	 * @param {Transform} rhs right hand side transform
	 * @returns {Transform} this for chaining
	 */
	Transform.prototype.combine = function(rhs) {
		return Transform.combine(this, rhs, this);
	};

	// TODO: sort this crap out!
	Transform.prototype.multiply = function (a, b) {
		Matrix4x4.combine(a.matrix, b.matrix, this.matrix);

		this.tmpMat1.data.set(a.rotation.data);
		//this.tmpMat1.multiplyDiagonalPost(a.scale, this.tmpMat1);
		this.rotation.data.set(b.rotation.data);
		//this.rotation.multiplyDiagonalPost(b.scale, this.rotation);
		Matrix3x3.combine(this.tmpMat1, this.rotation, this.rotation);
		this.translation.setv(b.translation);
		this.translation.mulv(a.scale);
		this.tmpMat1.applyPost(this.translation).addv(a.translation);
		this.scale.setv(a.scale).mulv(b.scale);
	};

	/**
	 * Set Transform to identity
	 */
	Transform.prototype.setIdentity = function () {
		this.matrix.setIdentity();

		this.translation.setv(Vector3.ZERO);
		this.rotation.setIdentity();
		this.scale.setv(Vector3.ONE);
	};

	/**
	 * Applies this transform to supplied vector as a point
	 * @param {Vector3} point
	 * @param {Vector3} store
	 * @returns {Vector3} store
	 * @example
	 * // Vector3 object, one unit right, two units up, two units back
	 * var v1 = new Vector3(1, 2, 2);
	 * // Vector3 to store the local position
	 * var localPos = new Vector3();
	 * // converts v1 to be in 'world space' based on the entities postion / rotation
	 * entity.transformComponent.transform.applyForward(v1, localPos);
	 */
	Transform.prototype.applyForward = function (point, store) {
		store.setv(point);

		// store.set(store.x * this.scale.x, store.y * this.scale.y, store.z * this.scale.z);
		// this.rotation.applyPost(store);
		// store.add(this.translation);

		this.matrix.applyPostPoint(store);

		return store;
	};

	/**
	 * Applies this transform to supplied vector as a direction-vector (translation will not affect it)
	 * @param {Vector3} vector
	 * @param {Vector3} store
	 * @returns {Vector3} store
	 * @example
	 * // Vector3 pointing in the direction we want
	 * var back = new Vector3(0, 0, 1);
	 * // Vector3 to store the local 'back'
	 * var localBack = new Vector3();
	 * // converts 'back' to a localized direction based on the entities rotation
	 * entity.transformComponent.transform.applyForwardVector(back, localBack);
	 */
	Transform.prototype.applyForwardVector = function (vector, store) {
		store.copy(vector);

		store.set(store.x * this.scale.x, store.y * this.scale.y, store.z * this.scale.z);
		this.rotation.applyPost(store);

		return store;
	};

	/**
	 * Updates the transform according to set scaling, rotation and translation. This is done automatically by the engine
	 */
	Transform.prototype.update = function () {
		var target = this.matrix.data;
		var rotation = this.rotation.data;
		var scale = this.scale.data;
		var translation = this.translation.data;

		target[0] = scale[0] * rotation[0];
		target[1] = scale[0] * rotation[1];
		target[2] = scale[0] * rotation[2];
		target[3] = 0.0;
		target[4] = scale[1] * rotation[3];
		target[5] = scale[1] * rotation[4];
		target[6] = scale[1] * rotation[5];
		target[7] = 0.0;
		target[8] = scale[2] * rotation[6];
		target[9] = scale[2] * rotation[7];
		target[10] = scale[2] * rotation[8];
		target[11] = 0.0;
		target[12] = translation[0];
		target[13] = translation[1];
		target[14] = translation[2];
		target[15] = 1.0;
	};

	/**
	 * Copy supplied transform into this transform
	 * @param {Transform} transform
	 */
	Transform.prototype.copy = function (transform) {
		this.matrix.copy(transform.matrix);

		this.translation.setv(transform.translation);
		this.rotation.copy(transform.rotation);
		this.scale.setv(transform.scale);
	};

	/**
	 * Set this transform's rotation to rotation around X, Y and Z axis.
	 * The rotation is applied in XYZ order.
	 * @param {number} x
	 * @param {number} y
	 * @param {number} z
	 */
	Transform.prototype.setRotationXYZ = function (x, y, z) {
		this.rotation.fromAngles(x, y, z);
	};

	/**
	 * Sets the transform to look in a specific direction.
	 * @param {Vector3} position Target position.
	 * @param {Vector3} [up=(0, 1, 0)] Up vector.
	 */
	Transform.prototype.lookAt = function (position, up) {
		if (!up) {
			up = Vector3.UNIT_Y;
		}

		this.tmpVec.setv(this.translation).subv(position).normalize();
		this.rotation.lookAt(this.tmpVec, up);
	};

	/**
	 * Invert this transform and store it in supplied transform
	 * @param {Transform} store
	 * @returns {Transform} store
	 */
	Transform.prototype.invert = function (store) {
		var result = store;
		if (!result) {
			result = new Transform();
		}

		// if (_identity) {
		// result.setIdentity();
		// return result;
		// }

		result.matrix.copy(this.matrix);
		result.matrix.invert();

		var newRotation = result.rotation.copy(this.rotation);
		// if (_uniformScale) {
		// var sx = this.scale.x;
		// newRotation.transposeLocal();
		// if (sx !== 1.0) {
		// newRotation.multiplyLocal(1.0 / sx);
		// }
		// } else {
		newRotation.multiplyDiagonalPost(this.scale, newRotation).invert();
		// }

		result.translation.copy(this.translation);
		result.rotation.applyPost(result.translation).invert();

		// result.update();

		return result;
	};

	Transform.prototype.toString = function () {
		return '' + this.matrix;
	};

	return Transform;
});<commit_msg>Added a review comment on the wrong behavior of Transform.prototype.lookAt<commit_after>define([
	'goo/math/Vector3',
	'goo/math/Matrix3x3',
	'goo/math/Matrix4x4'
],
/** @lends */
function (
	Vector3,
	Matrix3x3,
	Matrix4x4
) {
	"use strict";

	/**
	 * @class Transform models a transformation in 3d space as: Y = M*X+T, with M being a Matrix3 and T is a Vector3. Generally M will be a rotation
	 *        only matrix in which case it is represented by the matrix and scale fields as R*S, where S is a positive scale vector. For non-uniform
	 *        scales and reflections, use setMatrix, which will consider M as being a general 3x3 matrix and disregard anything set in scale.
	 */
	function Transform() {
		/** Read only, will be updated automatically by {@link Transform.update}
		 * @type {Matrix4x4}
		 */
		this.matrix = new Matrix4x4();
		this.normalMatrix = new Matrix4x4();

		/** @type {Vector3} */
		this.translation = new Vector3();
		/** @type {Matrix3x3} */
		this.rotation = new Matrix3x3();
		/** @type {Vector3} */
		this.scale = new Vector3(1, 1, 1);

		this.tmpVec = new Vector3();
		this.tmpVec2 = new Vector3();
		this.tmpMat1 = new Matrix3x3();
	}

	/**
	 * Combines two transforms into one. This will only work if scaling in the left hand transform is uniform
	 * @param {Transform} lhs left hand side transform
	 * @param {Transform} rhs right hand side transform
	 * @param {Transform} target
	 * @returns {Transform} target
	 */
	Transform.combine = function(lhs, rhs, target) {
		if(lhs.scale.data[0] !== lhs.scale.data[1] || lhs.scale.data[0] !== lhs.scale.data[2]) {
			throw {
				name: 'NonUniformScaleException',
				message: 'Non-uniform scaling in left hand transform, cannot resolve combined transform'
			};
		}
		target = target || new Transform();

		// Translation
		var tmpVec = target.tmpVec;
		tmpVec.setv(rhs.translation);
		// Rotate translation
		lhs.rotation.applyPost(tmpVec);
		// Scale translation
		tmpVec.mulv(lhs.scale);
		// Translate translation
		tmpVec.addv(lhs.translation);

		// Scale
		var tmpVec2 = target.tmpVec2;
		tmpVec2.setv(rhs.scale);
		// Scale scale
		tmpVec2.mulv(lhs.scale);

		// Rotation
		var tmpMat1 = target.tmpMat1;
		// Rotate rotation
		Matrix3x3.combine(lhs.rotation, rhs.rotation, tmpMat1);

		target.rotation.copy(tmpMat1);
		target.scale.setv(tmpVec2);
		target.translation.setv(tmpVec);

		target.update();

		return target;
	};

	/**
	 * Combines new transform into this one. This will only work if scaling in the left hand transform is uniform
	 * @param {Transform} rhs right hand side transform
	 * @returns {Transform} this for chaining
	 */
	Transform.prototype.combine = function(rhs) {
		return Transform.combine(this, rhs, this);
	};

	// TODO: sort this crap out!
	Transform.prototype.multiply = function (a, b) {
		Matrix4x4.combine(a.matrix, b.matrix, this.matrix);

		this.tmpMat1.data.set(a.rotation.data);
		//this.tmpMat1.multiplyDiagonalPost(a.scale, this.tmpMat1);
		this.rotation.data.set(b.rotation.data);
		//this.rotation.multiplyDiagonalPost(b.scale, this.rotation);
		Matrix3x3.combine(this.tmpMat1, this.rotation, this.rotation);
		this.translation.setv(b.translation);
		this.translation.mulv(a.scale);
		this.tmpMat1.applyPost(this.translation).addv(a.translation);
		this.scale.setv(a.scale).mulv(b.scale);
	};

	/**
	 * Set Transform to identity
	 */
	Transform.prototype.setIdentity = function () {
		this.matrix.setIdentity();

		this.translation.setv(Vector3.ZERO);
		this.rotation.setIdentity();
		this.scale.setv(Vector3.ONE);
	};

	/**
	 * Applies this transform to supplied vector as a point
	 * @param {Vector3} point
	 * @param {Vector3} store
	 * @returns {Vector3} store
	 * @example
	 * // Vector3 object, one unit right, two units up, two units back
	 * var v1 = new Vector3(1, 2, 2);
	 * // Vector3 to store the local position
	 * var localPos = new Vector3();
	 * // converts v1 to be in 'world space' based on the entities postion / rotation
	 * entity.transformComponent.transform.applyForward(v1, localPos);
	 */
	Transform.prototype.applyForward = function (point, store) {
		store.setv(point);

		// store.set(store.x * this.scale.x, store.y * this.scale.y, store.z * this.scale.z);
		// this.rotation.applyPost(store);
		// store.add(this.translation);

		this.matrix.applyPostPoint(store);

		return store;
	};

	/**
	 * Applies this transform to supplied vector as a direction-vector (translation will not affect it)
	 * @param {Vector3} vector
	 * @param {Vector3} store
	 * @returns {Vector3} store
	 * @example
	 * // Vector3 pointing in the direction we want
	 * var back = new Vector3(0, 0, 1);
	 * // Vector3 to store the local 'back'
	 * var localBack = new Vector3();
	 * // converts 'back' to a localized direction based on the entities rotation
	 * entity.transformComponent.transform.applyForwardVector(back, localBack);
	 */
	Transform.prototype.applyForwardVector = function (vector, store) {
		store.copy(vector);

		store.set(store.x * this.scale.x, store.y * this.scale.y, store.z * this.scale.z);
		this.rotation.applyPost(store);

		return store;
	};

	/**
	 * Updates the transform according to set scaling, rotation and translation. This is done automatically by the engine
	 */
	Transform.prototype.update = function () {
		var target = this.matrix.data;
		var rotation = this.rotation.data;
		var scale = this.scale.data;
		var translation = this.translation.data;

		target[0] = scale[0] * rotation[0];
		target[1] = scale[0] * rotation[1];
		target[2] = scale[0] * rotation[2];
		target[3] = 0.0;
		target[4] = scale[1] * rotation[3];
		target[5] = scale[1] * rotation[4];
		target[6] = scale[1] * rotation[5];
		target[7] = 0.0;
		target[8] = scale[2] * rotation[6];
		target[9] = scale[2] * rotation[7];
		target[10] = scale[2] * rotation[8];
		target[11] = 0.0;
		target[12] = translation[0];
		target[13] = translation[1];
		target[14] = translation[2];
		target[15] = 1.0;
	};

	/**
	 * Copy supplied transform into this transform
	 * @param {Transform} transform
	 */
	Transform.prototype.copy = function (transform) {
		this.matrix.copy(transform.matrix);

		this.translation.setv(transform.translation);
		this.rotation.copy(transform.rotation);
		this.scale.setv(transform.scale);
	};

	/**
	 * Set this transform's rotation to rotation around X, Y and Z axis.
	 * The rotation is applied in XYZ order.
	 * @param {number} x
	 * @param {number} y
	 * @param {number} z
	 */
	Transform.prototype.setRotationXYZ = function (x, y, z) {
		this.rotation.fromAngles(x, y, z);
	};

	/**
	 * Sets the transform to look in a specific direction.
	 * Please note: This function contains a known bug resulting in looking in the opposite direction
	 * for non-camera and non-light entities.
	 * @param {Vector3} position Target position.
	 * @param {Vector3} [up=(0, 1, 0)] Up vector.
	 */
	Transform.prototype.lookAt = function (position, up) {
		if (!up) {
			up = Vector3.UNIT_Y;
		}
		// REVIEW: this is actually using the wrong direction, it should be reversed.
		//   this.tmpVec.setv(position).subv(this.translation).normalize();
		// However we might need the old behavior for lights and cameras.
		this.tmpVec.setv(this.translation).subv(position).normalize();
		this.rotation.lookAt(this.tmpVec, up);
	};

	/**
	 * Invert this transform and store it in supplied transform
	 * @param {Transform} store
	 * @returns {Transform} store
	 */
	Transform.prototype.invert = function (store) {
		var result = store;
		if (!result) {
			result = new Transform();
		}

		// if (_identity) {
		// result.setIdentity();
		// return result;
		// }

		result.matrix.copy(this.matrix);
		result.matrix.invert();

		var newRotation = result.rotation.copy(this.rotation);
		// if (_uniformScale) {
		// var sx = this.scale.x;
		// newRotation.transposeLocal();
		// if (sx !== 1.0) {
		// newRotation.multiplyLocal(1.0 / sx);
		// }
		// } else {
		newRotation.multiplyDiagonalPost(this.scale, newRotation).invert();
		// }

		result.translation.copy(this.translation);
		result.rotation.applyPost(result.translation).invert();

		// result.update();

		return result;
	};

	Transform.prototype.toString = function () {
		return '' + this.matrix;
	};

	return Transform;
});<|endoftext|>


<commit_before>// Hide the packages frame.
var framesets = document.getElementsByTagName('frameset');
if (framesets) {
  var frameset = framesets[1];
  if (frameset) {
    frameset.setAttribute('rows', '0,*');
    frameset.setAttribute('border', 0);
    frameset.setAttribute('frameborder', 0);
    frameset.setAttribute('framespacing', 0);
  }
}
<commit_msg>Google Chrome extension: packages frame is shown only when that setting has been configured, hidden otherwise.<commit_after>/**
 * This script is distributed under the MIT licence.
 * http://en.wikipedia.org/wiki/MIT_License
 *
 * Copyright (c) 2009 Steven G. Brown
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

if (localStorage.getItem('hide_package_frame') === 'true') {
  // Hide the packages frame.
  var framesets = document.getElementsByTagName('frameset');
  if (framesets) {
    var frameset = framesets[1];
    if (frameset) {
      frameset.setAttribute('rows', '0,*');
      frameset.setAttribute('border', 0);
      frameset.setAttribute('frameborder', 0);
      frameset.setAttribute('framespacing', 0);
    }
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

var fs        = require('fs');
var writeGood = require('../write-good');
var annotate  = require('../lib/annotate');

var args      = process.argv.slice(2);
var files     = args.filter(function (arg) {
  return arg.substr(0, 2) !== '--';
});

if (args[0] === '--version'){
  var version = require('../package.json').version;
  console.log('write-good version ' + version);
  process.exit(0);
}

if (files.length === 0) {
  console.log('You did not provide any files to check');
  process.exit(1);
}

var opts      = {
  weasel   : null,
  illusion : null,
  so       : null,
  thereIs  : null,
  passive  : null,
  adverb   : null,
  tooWordy : null,
  cliches  : null
};

var include = true;
var shouldParse = false;

args.filter(function (arg) {
  return arg.substr(0, 2) === '--';
}).map(function (arg) {
  return arg.substr(2);
}).forEach(function (arg) {
  if (arg.substr(0, 3) === 'no-') {
    opts[arg.substr(3)] = false;
  } else if(arg == 'parse') {
  //overload the lint option logic above, to include
  //an operational flag: --parse, which means parse-happy output
  //and follow a more conventional Unix exit code
    shouldParse = true;
  }else {
    opts[arg] = true;
    include = false;
  }
});

Object.keys(opts).forEach(function (name) {
  if (typeof opts[name] !== 'boolean') {
    opts[name] = include;
  }
});

var exitCode = 0;
files.forEach(function (file) {
  var contents = fs.readFileSync(file, 'utf8');
  var suggestions = writeGood(contents, opts);

  if(shouldParse){
    exitCode = suggestions.length > 0 ? -1 : 0;
    console.log(annotate(contents, suggestions, true).map(function(ann){return [file,ann.line,ann.col, ann.reason].join(":")}).join("\n"));
  }else{
    exitCode += suggestions.length;
    if (suggestions.length) {
      console.log('In ' + file);
      console.log('=============');
      console.log(annotate(contents, suggestions).join('\n-------------\n'));
    }
  }
});

process.exit(exitCode);
<commit_msg>Using --parse some results are still in more than one line<commit_after>#!/usr/bin/env node

var fs        = require('fs');
var writeGood = require('../write-good');
var annotate  = require('../lib/annotate');

var args      = process.argv.slice(2);
var files     = args.filter(function (arg) {
  return arg.substr(0, 2) !== '--';
});

if (args[0] === '--version'){
  var version = require('../package.json').version;
  console.log('write-good version ' + version);
  process.exit(0);
}

if (files.length === 0) {
  console.log('You did not provide any files to check');
  process.exit(1);
}

var opts      = {
  weasel   : null,
  illusion : null,
  so       : null,
  thereIs  : null,
  passive  : null,
  adverb   : null,
  tooWordy : null,
  cliches  : null
};

var include = true;
var shouldParse = false;

args.filter(function (arg) {
  return arg.substr(0, 2) === '--';
}).map(function (arg) {
  return arg.substr(2);
}).forEach(function (arg) {
  if (arg.substr(0, 3) === 'no-') {
    opts[arg.substr(3)] = false;
  } else if(arg == 'parse') {
  //overload the lint option logic above, to include
  //an operational flag: --parse, which means parse-happy output
  //and follow a more conventional Unix exit code
    shouldParse = true;
  }else {
    opts[arg] = true;
    include = false;
  }
});

Object.keys(opts).forEach(function (name) {
  if (typeof opts[name] !== 'boolean') {
    opts[name] = include;
  }
});

var exitCode = 0;
files.forEach(function (file) {
  var contents = fs.readFileSync(file, 'utf8');
  var suggestions = writeGood(contents, opts);

  if(shouldParse){
    exitCode = suggestions.length > 0 ? -1 : 0;
    console.log(annotate(contents, suggestions, true).map(function(ann){return [file,ann.line,ann.col, ann.reason.replace("\n", " ")].join(":")}).join("\n"));
  }else{
    exitCode += suggestions.length;
    if (suggestions.length) {
      console.log('In ' + file);
      console.log('=============');
      console.log(annotate(contents, suggestions).join('\n-------------\n'));
    }
  }
});

process.exit(exitCode);
<|endoftext|>


<commit_before>/* @flow weak */

/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import {
  Image,
  View,
} from 'react-native';
import dismissKeyboard from 'dismissKeyboard'; // eslint-disable-line import/no-unresolved

import globalStyles, { BACKGROUND_COLOR, SUSSOL_ORANGE } from './globalStyles';

import { Navigator } from './navigation';
import { Spinner } from './widgets/Spinner';
import { PAGES, FINALISABLE_PAGES } from './pages';

import {
  FinaliseButton,
  FinaliseModal,
  LoginModal,
  SyncState,
} from './widgets';

import { Synchroniser } from './sync';
import { SyncAuthenticator, UserAuthenticator } from './authentication';
import { Database, schema, UIDatabase } from './database';
import { Scheduler } from './Scheduler';
import { Settings } from './settings';

const SYNC_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds
const AUTHENTICATION_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds

export default class mSupplyMobileApp extends React.Component {

  constructor() {
    super();
    const database = new Database(schema);
    this.database = new UIDatabase(database);
    this.settings = new Settings(this.database);
    this.userAuthenticator = new UserAuthenticator(this.database, this.settings);
    const syncAuthenticator = new SyncAuthenticator(this.database, this.settings);
    this.synchroniser = new Synchroniser(database, syncAuthenticator, this.settings);
    this.scheduler = new Scheduler();
    const initialised = this.synchroniser.isInitialised();
    this.state = {
      confirmFinalise: false,
      currentUser: null,
      initialised: initialised,
      isSyncing: false,
      syncError: '',
      lastSync: null, // Date of the last successful sync
      finaliseItem: null,
      isLoading: false,
    };
  }

  componentWillMount() {
    this.logOut = this.logOut.bind(this);
    this.onAuthentication = this.onAuthentication.bind(this);
    this.onInitialised = this.onInitialised.bind(this);
    this.runWithLoadingIndicator = this.runWithLoadingIndicator.bind(this);
    this.renderFinaliseButton = this.renderFinaliseButton.bind(this);
    this.renderLoadingIndicator = this.renderLoadingIndicator.bind(this);
    this.renderScene = this.renderScene.bind(this);
    this.renderSyncState = this.renderSyncState.bind(this);
    this.synchronise = this.synchronise.bind(this);
    this.scheduler.schedule(this.synchronise,
                            SYNC_INTERVAL);
    this.scheduler.schedule(() => {
      if (this.state.currentUser !== null) { // Only reauthenticate if currently logged in
        this.userAuthenticator.reauthenticate(this.onAuthentication);
      }
    }, AUTHENTICATION_INTERVAL);
  }

  componentWillUnmount() {
    this.scheduler.clearAll();
  }

  onAuthentication(user) {
    this.setState({ currentUser: user });
  }

  onInitialised() {
    this.setState({ initialised: true });
  }

  async runWithLoadingIndicator(functionToRun) {
    await new Promise((resolve) => {
      this.setState({ isLoading: true }, () => setTimeout(resolve, 1));
    });
    functionToRun();
    this.setState({ isLoading: false });
  }

  async synchronise() {
    if (!this.state.initialised || this.state.isSyncing) return; // If already syncing, skip
    try {
      this.setState({ isSyncing: true });
      await this.synchroniser.synchronise();
      this.setState({
        isSyncing: false,
        syncError: '',
      });
    } catch (error) {
      this.setState({
        isSyncing: false,
        syncError: error.message,
      });
    }
  }

  logOut() {
    this.setState({ currentUser: null });
  }

  renderFinaliseButton() {
    return (
      <FinaliseButton
        isFinalised={this.state.finaliseItem.record.status === 'finalised'}
        onPress={() => this.setState({ confirmFinalise: true })}
      />);
  }

  renderLogo() {
    return (
      <Image
        resizeMode="contain"
        source={require('./images/logo.png')}
      />
    );
  }

  renderLoadingIndicator() {
    return (
      <View style={globalStyles.loadingIndicatorContainer}>
        <Spinner isSpinning={this.state.isLoading} color={SUSSOL_ORANGE} />
      </View>);
  }

  renderScene(props) {
    const navigateTo = (key, title, extraProps, navType) => {
      dismissKeyboard();
      if (!navType) navType = 'push';
      const navigationProps = { key, title, ...extraProps };
      // If the page we're going to has a key value pair in FINALISABLE_PAGES, get the finaliseItem
      // details corresponding to that key. Set the new state and render the finalise Button
      if (FINALISABLE_PAGES[key]) {
        const { recordToFinaliseKey, ...finaliseItem } = FINALISABLE_PAGES[key];
        finaliseItem.record = extraProps[recordToFinaliseKey];
        this.setState({ finaliseItem: finaliseItem });
        navigationProps.renderRightComponent = this.renderFinaliseButton;
      }

      // Now navigate to the page, passing on any extra props and the finalise button if required
      props.onNavigate({ type: navType, ...navigationProps });
    };
    const { key, ...extraProps } = props.scene.route;
    const Page = PAGES[key]; // Get the page the navigation key relates to
    // Return the requested page with any extra props passed to navigateTo in pageProps
    return (
      <Page
        navigateTo={navigateTo}
        database={this.database}
        settings={this.settings}
        logOut={this.logOut}
        currentUser={this.state.currentUser}
        runWithLoadingIndicator={this.runWithLoadingIndicator}
        {...extraProps}
      />);
  }

  renderSyncState() {
    return (
      <SyncState
        isSyncing={this.state.isSyncing}
        syncError={this.state.syncError}
        settings={this.settings}
      />
    );
  }

  render() {
    if (!this.state.initialised) {
      const FirstUsePage = PAGES.firstUse;
      return (
        <FirstUsePage
          synchroniser={this.synchroniser}
          onInitialised={this.onInitialised}
        />
      );
    }
    return (
      <View style={globalStyles.appBackground}>
        <Navigator
          renderScene={this.renderScene}
          renderCentreComponent={this.renderLogo}
          renderRightComponent={this.renderSyncState}
          navBarStyle={globalStyles.navBarStyle}
          backgroundColor={BACKGROUND_COLOR}
        />
        <FinaliseModal
          database={this.database}
          isOpen={this.state.confirmFinalise}
          onClose={() => this.setState({ confirmFinalise: false })}
          finaliseItem={this.state.finaliseItem}
          user={this.state.currentUser}
          runWithLoadingIndicator={this.runWithLoadingIndicator}
        />
        <LoginModal
          authenticator={this.userAuthenticator}
          settings={this.settings}
          isAuthenticated={this.state.currentUser !== null}
          onAuthentication={this.onAuthentication}
        />
        {this.state.isLoading && this.renderLoadingIndicator()}
      </View>
    );
  }
}
<commit_msg>Comment describing reason for setTimeout<commit_after>/* @flow weak */

/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2016
 */

import React from 'react';
import {
  Image,
  View,
} from 'react-native';
import dismissKeyboard from 'dismissKeyboard'; // eslint-disable-line import/no-unresolved

import globalStyles, { BACKGROUND_COLOR, SUSSOL_ORANGE } from './globalStyles';

import { Navigator } from './navigation';
import { Spinner } from './widgets/Spinner';
import { PAGES, FINALISABLE_PAGES } from './pages';

import {
  FinaliseButton,
  FinaliseModal,
  LoginModal,
  SyncState,
} from './widgets';

import { Synchroniser } from './sync';
import { SyncAuthenticator, UserAuthenticator } from './authentication';
import { Database, schema, UIDatabase } from './database';
import { Scheduler } from './Scheduler';
import { Settings } from './settings';

const SYNC_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds
const AUTHENTICATION_INTERVAL = 10 * 60 * 1000; // 10 minutes in milliseconds

export default class mSupplyMobileApp extends React.Component {

  constructor() {
    super();
    const database = new Database(schema);
    this.database = new UIDatabase(database);
    this.settings = new Settings(this.database);
    this.userAuthenticator = new UserAuthenticator(this.database, this.settings);
    const syncAuthenticator = new SyncAuthenticator(this.database, this.settings);
    this.synchroniser = new Synchroniser(database, syncAuthenticator, this.settings);
    this.scheduler = new Scheduler();
    const initialised = this.synchroniser.isInitialised();
    this.state = {
      confirmFinalise: false,
      currentUser: null,
      initialised: initialised,
      isSyncing: false,
      syncError: '',
      lastSync: null, // Date of the last successful sync
      finaliseItem: null,
      isLoading: false,
    };
  }

  componentWillMount() {
    this.logOut = this.logOut.bind(this);
    this.onAuthentication = this.onAuthentication.bind(this);
    this.onInitialised = this.onInitialised.bind(this);
    this.runWithLoadingIndicator = this.runWithLoadingIndicator.bind(this);
    this.renderFinaliseButton = this.renderFinaliseButton.bind(this);
    this.renderLoadingIndicator = this.renderLoadingIndicator.bind(this);
    this.renderScene = this.renderScene.bind(this);
    this.renderSyncState = this.renderSyncState.bind(this);
    this.synchronise = this.synchronise.bind(this);
    this.scheduler.schedule(this.synchronise,
                            SYNC_INTERVAL);
    this.scheduler.schedule(() => {
      if (this.state.currentUser !== null) { // Only reauthenticate if currently logged in
        this.userAuthenticator.reauthenticate(this.onAuthentication);
      }
    }, AUTHENTICATION_INTERVAL);
  }

  componentWillUnmount() {
    this.scheduler.clearAll();
  }

  onAuthentication(user) {
    this.setState({ currentUser: user });
  }

  onInitialised() {
    this.setState({ initialised: true });
  }

  async runWithLoadingIndicator(functionToRun) {
    // We here set up an asyncronous promise that will be resolved after a timeout
    // of 1 millisecond. This allows a fraction of a delay during which the javascript
    // thread unblocks and allows our spinner animation to start up. We cannot simply
    // call the functionToRun inside a setTimeout as that relegates to a lower
    // priority and results in very slow performance.
    await new Promise((resolve) => {
      this.setState({ isLoading: true }, () => setTimeout(resolve, 1));
    });
    functionToRun();
    this.setState({ isLoading: false });
  }

  async synchronise() {
    if (!this.state.initialised || this.state.isSyncing) return; // If already syncing, skip
    try {
      this.setState({ isSyncing: true });
      await this.synchroniser.synchronise();
      this.setState({
        isSyncing: false,
        syncError: '',
      });
    } catch (error) {
      this.setState({
        isSyncing: false,
        syncError: error.message,
      });
    }
  }

  logOut() {
    this.setState({ currentUser: null });
  }

  renderFinaliseButton() {
    return (
      <FinaliseButton
        isFinalised={this.state.finaliseItem.record.status === 'finalised'}
        onPress={() => this.setState({ confirmFinalise: true })}
      />);
  }

  renderLogo() {
    return (
      <Image
        resizeMode="contain"
        source={require('./images/logo.png')}
      />
    );
  }

  renderLoadingIndicator() {
    return (
      <View style={globalStyles.loadingIndicatorContainer}>
        <Spinner isSpinning={this.state.isLoading} color={SUSSOL_ORANGE} />
      </View>);
  }

  renderScene(props) {
    const navigateTo = (key, title, extraProps, navType) => {
      dismissKeyboard();
      if (!navType) navType = 'push';
      const navigationProps = { key, title, ...extraProps };
      // If the page we're going to has a key value pair in FINALISABLE_PAGES, get the finaliseItem
      // details corresponding to that key. Set the new state and render the finalise Button
      if (FINALISABLE_PAGES[key]) {
        const { recordToFinaliseKey, ...finaliseItem } = FINALISABLE_PAGES[key];
        finaliseItem.record = extraProps[recordToFinaliseKey];
        this.setState({ finaliseItem: finaliseItem });
        navigationProps.renderRightComponent = this.renderFinaliseButton;
      }

      // Now navigate to the page, passing on any extra props and the finalise button if required
      props.onNavigate({ type: navType, ...navigationProps });
    };
    const { key, ...extraProps } = props.scene.route;
    const Page = PAGES[key]; // Get the page the navigation key relates to
    // Return the requested page with any extra props passed to navigateTo in pageProps
    return (
      <Page
        navigateTo={navigateTo}
        database={this.database}
        settings={this.settings}
        logOut={this.logOut}
        currentUser={this.state.currentUser}
        runWithLoadingIndicator={this.runWithLoadingIndicator}
        {...extraProps}
      />);
  }

  renderSyncState() {
    return (
      <SyncState
        isSyncing={this.state.isSyncing}
        syncError={this.state.syncError}
        settings={this.settings}
      />
    );
  }

  render() {
    if (!this.state.initialised) {
      const FirstUsePage = PAGES.firstUse;
      return (
        <FirstUsePage
          synchroniser={this.synchroniser}
          onInitialised={this.onInitialised}
        />
      );
    }
    return (
      <View style={globalStyles.appBackground}>
        <Navigator
          renderScene={this.renderScene}
          renderCentreComponent={this.renderLogo}
          renderRightComponent={this.renderSyncState}
          navBarStyle={globalStyles.navBarStyle}
          backgroundColor={BACKGROUND_COLOR}
        />
        <FinaliseModal
          database={this.database}
          isOpen={this.state.confirmFinalise}
          onClose={() => this.setState({ confirmFinalise: false })}
          finaliseItem={this.state.finaliseItem}
          user={this.state.currentUser}
          runWithLoadingIndicator={this.runWithLoadingIndicator}
        />
        <LoginModal
          authenticator={this.userAuthenticator}
          settings={this.settings}
          isAuthenticated={this.state.currentUser !== null}
          onAuthentication={this.onAuthentication}
        />
        {this.state.isLoading && this.renderLoadingIndicator()}
      </View>
    );
  }
}
<|endoftext|>