<commit_before>// Copyright 2017 SAP SE.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http: //www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific
// language governing permissions and limitations under the License.

'use strict';

var path = require('path');
var assign = require('object-assign');
var clone = require('clone');
var css = require('css');

var createParser = require('./less/parser');
var diff = require('./diff');
var scope = require('./scope');

var fileUtils = require('./fileUtils');

// Plugins
var RTLPlugin = require('./plugin/rtl');
var ImportCollectorPlugin = require('./plugin/import-collector');
var VariableCollectorPlugin = require('./plugin/variable-collector');

// Workaround for a performance issue in the "css" parser module when used in combination
// with the "colors" module that enhances the String prototype.
// See: https://github.com/reworkcss/css/issues/88
//
// This function removes all properties added by "colors" and returns a function
// that restores them  afterwards.
// To be used before/after calling "css.parse"
function cleanupStringPrototype() {
	var customGetters = {}, customProps = {}, s = "", key;

	for (key in s) {
		if (!s.hasOwnProperty(key)) {
			var getter = String.prototype.__lookupGetter__(key);
			if (typeof getter === "function") {
				customGetters[key] = getter;
			} else {
				customProps[key] = String.prototype[key];
			}
			Reflect.deleteProperty(String.prototype, key);
		}
	}

	return function restore() {
		for (key in customGetters) {
			if (customGetters.hasOwnProperty(key)) {
				String.prototype.__defineGetter__(key, customGetters[key]);
			}
		}
		for (key in customProps) {
			if (customProps.hasOwnProperty(key)) {
				String.prototype[key] = customProps[key];
			}
		}
	}
}

function dotThemingFileToPath(s) {
	if (s.indexOf(".") > -1) {
		s = "../" + s.replace(/\./g, "/");
	}

	return s;
}

var Builder = function() {
	this.themeCacheMapping = {};
};

Builder.prototype.getThemeCache = function(rootPath) {
	return this.themeCacheMapping[rootPath];
};

Builder.prototype.setThemeCache = function(rootPath, cache) {
	return this.themeCacheMapping[rootPath] = cache;
};

Builder.prototype.clearCache = function() {
	this.themeCacheMapping = {};
}

Builder.prototype.cacheTheme = function(result) {
	var that = this;
	var rootpath;

	// Theme can only be cached if list of imports is available
	if (result.imports.length === 0) {
		return Promise.resolve(result);
	}

	// Rootpath of theme is always the first entry
	rootpath = result.imports[0];

	return fileUtils.statFiles(result.imports).then(function(stats) {
		that.setThemeCache(rootpath, {
			result: result,
			stats: stats
		});

		return result;
	});

};

Builder.prototype.build = function(options) {
	var that = this;

	// Stores mapping between "virtual" paths (used within LESS) and real filesystem paths.
	// Only relevant when using the "rootPaths" option.
	var mFileMappings = {};

	// Assign default options
	options = assign({
		lessInput: null,
		lessInputPath: null,
		rtl: true,
		rootPaths: [],
		parser: {},
		compiler: {},
		library: {}
	}, options);

	// Set default of "relativeUrls" parser option to "true" (less default is "false")
	if (!options.parser.hasOwnProperty("relativeUrls")) {
		options.parser.relativeUrls = true;
	}

	function fileHandler(file, currentFileInfo, handleDataAndCallCallback, callback) {

		var pathname = path.normalize(currentFileInfo.currentDirectory + file);

		fileUtils.readFile(pathname, options.rootPaths).then(function(result) {
			if (!result) {
				console.log("File not found");
				callback({ type: 'File', message: "'" + file + "' wasn't found" })
			} else {

				try {
					// Save import mapping to calculate full import paths later on
					mFileMappings[currentFileInfo.rootFilename] = mFileMappings[currentFileInfo.rootFilename] || {};
					mFileMappings[currentFileInfo.rootFilename][pathname] = result.path;

					handleDataAndCallCallback(pathname, result.content);
				} catch (e) {
					console.log(e);
					callback(e);
				}

			}
		}, function(err) {
			console.log(err);
			callback(err);
		});
	}

	function compile(config) {
		return new Promise(function(resolve, reject) {

			var parserOptions = clone(options.parser);
			var rootpath;

			if (config.path) {
				// Keep rootpath for later usage in the ImportCollectorPlugin
				rootpath = config.path;
				parserOptions.filename = config.localPath;
			}

			// Keep filename for later usage (see ImportCollectorPlugin) as less modifies the parserOptions.filename
			var filename = parserOptions.filename;

			// Only use custom file handler when "rootPaths" are defined
			var fnFileHandler;
			if (options.rootPaths && options.rootPaths.length > 0) {
				fnFileHandler = fileHandler;
			}

			var parser = createParser(parserOptions, fnFileHandler);

			parser.parse(config.content, function(err, tree) {

				if (err) {
					reject(err);
					return;
				}

				var result = {};

				result.tree = tree;

				// plugins to collect imported files and variable values
				var oImportCollector = new ImportCollectorPlugin({
					importMappings: mFileMappings[filename]
				});
				var oVariableCollector = new VariableCollectorPlugin();

				// render to css
				result.css = tree.toCSS(assign(options.compiler, {
					plugins: [ oImportCollector, oVariableCollector ]
				}));

				// retrieve imported files
				result.imports = oImportCollector.getImports();

				// retrieve imported variables
				result.variables = oVariableCollector.getVariables();

				// also compile rtl-version if requested
				if (options.rtl) {
					result.cssRtl = tree.toCSS(assign(options.compiler, {
						plugins: [ new RTLPlugin() ]
					}));
				}

				if (rootpath) {
					result.imports.unshift(rootpath);
				}

				resolve(result);

			});
		});
	}

	function addInlineParameters(result) {
		return new Promise(function(resolve, reject) {
			if (typeof options.library === "object" && typeof options.library.name === "string") {
				var parameters = JSON.stringify(result.variables);

				// escape all chars that could cause problems with css parsers using URI-Encoding (% + HEX-Code)
				var escapedChars = "%{}()'\"\\";
				for (var i = 0; i < escapedChars.length; i++) {
					var char = escapedChars.charAt(i);
					var hex = char.charCodeAt(0).toString(16).toUpperCase();
					parameters = parameters.replace(new RegExp("\\" + char, "g"), "%" + hex);
				}

				var parameterStyleRule =
					"\n/* Inline theming parameters */\n#sap-ui-theme-" +
					options.library.name.replace(/\./g, "\\.") +
					" { background-image: url('data:text/plain;utf-8," + parameters + "'); }\n";

				// embed parameter variables as plain-text string into css
				result.css += parameterStyleRule;
				if (result.cssRtl) {
					result.cssRtl += parameterStyleRule;
				}
			}
			resolve(result);
		});
	}

	function readDotTheming(dotThemingInputPath) {
		return fileUtils.readFile(dotThemingInputPath, options.rootPaths).then(function(result) {

			var dotTheming;
			var dotThemingFilePath;

			if (result) {
				dotTheming = JSON.parse(result.content);
				dotThemingFilePath = result.path;
			}

			if (dotTheming && dotTheming.mCssScopes) {

				// Currently only the "library" target is supported
				var cssScope = dotTheming.mCssScopes["library"];

				if (cssScope) {

					var aScopes = cssScope.aScopes;
					var oScopeConfig = aScopes[0]; // Currenlty only one scope is supported

					var sBaseFile = dotThemingFileToPath(cssScope.sBaseFile || cssScopeTarget);
					var sEmbeddedCompareFile = dotThemingFileToPath(oScopeConfig.sEmbeddedCompareFile);
					var sEmbeddedFile = dotThemingFileToPath(oScopeConfig.sEmbeddedFile);

					// Currently, only support the use case when "sBaseFile" equals "sEmbeddedCompareFile"
					if (sBaseFile !== sEmbeddedCompareFile) {
						throw new Error("Unsupported content in \"" + dotThemingInputPath + "\": " +
							"\"sBaseFile\" (\"" + (cssScope.sBaseFile || cssScopeTarget) + "\") must be identical with " +
							"\"sEmbeddedCompareFile\" (\"" + oScopeConfig.sEmbeddedCompareFile + "\")");
					}

					var embeddedCompareFilePath = path.posix.join(themeDir, sEmbeddedCompareFile) + '.source.less';
					var embeddedFilePath = path.posix.join(themeDir, sEmbeddedFile) + '.source.less';

					// 1. Compile base + embedded files (both default + RTL variants)
					return Promise.all([
						fileUtils.readFile(embeddedCompareFilePath, options.rootPaths).then(compile),
						fileUtils.readFile(embeddedFilePath, options.rootPaths).then(compile)
					]).then(function(results) {
						return {
							embeddedCompare: results[0],
							embedded: results[1]
						};
					}).then(function(results) {

						// baseFile or embeddedFile
						var sLibraryBaseFile = dotTheming.mCssScopes.library.sBaseFile;
						var sScopeName = oScopeConfig.sSelector;

						function applyScope(embeddedCompareCss, embeddedCss, bRtl) {

							var restoreStringPrototype = cleanupStringPrototype();

							// Create diff object between embeddedCompare and embedded
							var oBase = css.parse(embeddedCompareCss);
							var oEmbedded = css.parse(embeddedCss);

							restoreStringPrototype();

							var oDiff = diff(oBase, oEmbedded);

							// Create scope
							var sScopeSelector = '.' + sScopeName;
							var oScope = scope(oDiff.diff, sScopeSelector);

							var oCssScopeRoot;

							if (oDiff.stack) {
								oCssScopeRoot = scope.scopeCssRoot(oDiff.stack.stylesheet.rules, sScopeName);

								if (oCssScopeRoot) {
									oScope.stylesheet.rules.unshift(oCssScopeRoot);
								}
							}

							// Append scope + stack to embeddedCompareFile (actually target file, which is currently always the same i.e. "library.css")
							// The stack gets appended to the embeddedFile only
							var sAppend = css.stringify(oScope);

							if (sLibraryBaseFile !== "library" && oDiff.stack && oDiff.stack.stylesheet.rules.length > 0) {
								sAppend +=  "\n" + css.stringify(oDiff.stack);
							}

							return sAppend + "\n";

						}

						results.embeddedCompare.css += applyScope(results.embeddedCompare.css, results.embedded.css);
						if (options.rtl) {
							results.embeddedCompare.cssRtl += applyScope(results.embeddedCompare.cssRtl, results.embedded.cssRtl, true);
						}

						// Create diff between embeddedCompare and embeded variables
						var oVariablesBase = results.embeddedCompare.variables;
						var oVariablesEmbedded = results.embedded.variables;
						var oVariablesDiff = {};

						for (var sKey in oVariablesEmbedded) {
							if (sKey in oVariablesBase) {
								if (oVariablesBase[sKey] != oVariablesEmbedded[sKey]) {
									oVariablesDiff[sKey] = oVariablesEmbedded[sKey];
								}
							}
						}

						// Merge variables
						var oVariables = {};
						oVariables["default"] = oVariablesBase;
						oVariables["scopes"] = {};
						oVariables["scopes"][sScopeName] = oVariablesDiff;

						results.embeddedCompare.variables = oVariables;

						var concatImports = function(aImportsBase, aImportsEmbedded) {
							var aConcats = aImportsBase.concat(aImportsEmbedded);

							return aConcats.filter(function(sImport, sIndex) {
								return aConcats.indexOf(sImport) == sIndex;
							})
						};

						if (sLibraryBaseFile !== "library") {
							results.embeddedCompare.imports = concatImports(results.embedded.imports, results.embeddedCompare.imports);
						} else {
							results.embeddedCompare.imports = concatImports(results.embeddedCompare.imports, results.embedded.imports);
						}

						// add .theming file to result.embeddedCompare.imports
						results.embeddedCompare.imports.push(dotThemingFilePath);

						// 6. Resolve promise with complete result object (css, cssRtl, variables, imports)
						return results.embeddedCompare;

					});
				}
			}

			// No css diffing and scoping
			return fileUtils.readFile(options.lessInputPath, options.rootPaths).then(compile);
		});
	}

	if (options.lessInput && options.lessInputPath) {
		return Promise.reject(new Error("Please only provide either `lessInput` or `lessInputPath` but not both."));
	}

	if (!options.lessInput && !options.lessInputPath) {
		return Promise.reject(new Error("Missing required option. Please provide either `lessInput` or `lessInputPath`."));
	}

	if (options.lessInput) {

		return compile({
			content: options.lessInput
		}).then(addInlineParameters).then(that.cacheTheme.bind(that));

	} else {
		var themeDir = path.posix.dirname(options.lessInputPath);

		// Always use the sap/ui/core library to lookup .theming files
		var coreThemeDir = themeDir.replace(/^.*\/themes\//, "/sap/ui/core/themes/");
		var dotThemingInputPath = path.posix.join(coreThemeDir, '.theming');

		return fileUtils.findFile(options.lessInputPath, options.rootPaths).then(function(fileInfo) {

			if (!fileInfo) {
				throw new Error("`lessInputPath` " + options.lessInputPath + " could not be found.");
			}

			// check theme has been already cached
			var themeCache;
			if (fileInfo.path) {
				themeCache = that.getThemeCache(fileInfo.path);
			}

			// Compile theme if not cached or RTL is requested and missing in cache
			if (!themeCache || (options.rtl && !themeCache.result.cssRtl)) {
				return readDotTheming(dotThemingInputPath).then(addInlineParameters).then(that.cacheTheme.bind(that));
			} else {
				return fileUtils.statFiles(themeCache.result.imports).then(function(newStats) {
					for (var i = 0; i < newStats.length; i++) {
						// check if .theming and less files have changed since last less compilation
						if (!newStats[i] || newStats[i].stat.mtime.getTime() !== themeCache.stats[i].stat.mtime.getTime()) {
							return readDotTheming(dotThemingInputPath).then(addInlineParameters).then(that.cacheTheme.bind(that));
						}
					}

					// serve from cache
					return themeCache.result;
				});
			}
		});
	}
};

module.exports.Builder = Builder;
<commit_msg>Fix Node.js < v6 (missing Reflection API)<commit_after>// Copyright 2017 SAP SE.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http: //www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific
// language governing permissions and limitations under the License.

'use strict';

var path = require('path');
var assign = require('object-assign');
var clone = require('clone');
var css = require('css');

var createParser = require('./less/parser');
var diff = require('./diff');
var scope = require('./scope');

var fileUtils = require('./fileUtils');

// Plugins
var RTLPlugin = require('./plugin/rtl');
var ImportCollectorPlugin = require('./plugin/import-collector');
var VariableCollectorPlugin = require('./plugin/variable-collector');

// Workaround for a performance issue in the "css" parser module when used in combination
// with the "colors" module that enhances the String prototype.
// See: https://github.com/reworkcss/css/issues/88
//
// This function removes all properties added by "colors" and returns a function
// that restores them  afterwards.
// To be used before/after calling "css.parse"
function cleanupStringPrototype() {
	var customGetters = {}, customProps = {}, s = "", key;

	for (key in s) {
		if (!s.hasOwnProperty(key)) {
			var getter = String.prototype.__lookupGetter__(key);
			if (typeof getter === "function") {
				customGetters[key] = getter;
			} else {
				customProps[key] = String.prototype[key];
			}
			if (typeof Reflect !== "undefined") {
				Reflect.deleteProperty(String.prototype, key);
			} else {
				delete String.prototype[key];
			}
		}
	}

	return function restore() {
		for (key in customGetters) {
			if (customGetters.hasOwnProperty(key)) {
				String.prototype.__defineGetter__(key, customGetters[key]);
			}
		}
		for (key in customProps) {
			if (customProps.hasOwnProperty(key)) {
				String.prototype[key] = customProps[key];
			}
		}
	}
}

function dotThemingFileToPath(s) {
	if (s.indexOf(".") > -1) {
		s = "../" + s.replace(/\./g, "/");
	}

	return s;
}

var Builder = function() {
	this.themeCacheMapping = {};
};

Builder.prototype.getThemeCache = function(rootPath) {
	return this.themeCacheMapping[rootPath];
};

Builder.prototype.setThemeCache = function(rootPath, cache) {
	return this.themeCacheMapping[rootPath] = cache;
};

Builder.prototype.clearCache = function() {
	this.themeCacheMapping = {};
}

Builder.prototype.cacheTheme = function(result) {
	var that = this;
	var rootpath;

	// Theme can only be cached if list of imports is available
	if (result.imports.length === 0) {
		return Promise.resolve(result);
	}

	// Rootpath of theme is always the first entry
	rootpath = result.imports[0];

	return fileUtils.statFiles(result.imports).then(function(stats) {
		that.setThemeCache(rootpath, {
			result: result,
			stats: stats
		});

		return result;
	});

};

Builder.prototype.build = function(options) {
	var that = this;

	// Stores mapping between "virtual" paths (used within LESS) and real filesystem paths.
	// Only relevant when using the "rootPaths" option.
	var mFileMappings = {};

	// Assign default options
	options = assign({
		lessInput: null,
		lessInputPath: null,
		rtl: true,
		rootPaths: [],
		parser: {},
		compiler: {},
		library: {}
	}, options);

	// Set default of "relativeUrls" parser option to "true" (less default is "false")
	if (!options.parser.hasOwnProperty("relativeUrls")) {
		options.parser.relativeUrls = true;
	}

	function fileHandler(file, currentFileInfo, handleDataAndCallCallback, callback) {

		var pathname = path.normalize(currentFileInfo.currentDirectory + file);

		fileUtils.readFile(pathname, options.rootPaths).then(function(result) {
			if (!result) {
				console.log("File not found");
				callback({ type: 'File', message: "'" + file + "' wasn't found" })
			} else {

				try {
					// Save import mapping to calculate full import paths later on
					mFileMappings[currentFileInfo.rootFilename] = mFileMappings[currentFileInfo.rootFilename] || {};
					mFileMappings[currentFileInfo.rootFilename][pathname] = result.path;

					handleDataAndCallCallback(pathname, result.content);
				} catch (e) {
					console.log(e);
					callback(e);
				}

			}
		}, function(err) {
			console.log(err);
			callback(err);
		});
	}

	function compile(config) {
		return new Promise(function(resolve, reject) {

			var parserOptions = clone(options.parser);
			var rootpath;

			if (config.path) {
				// Keep rootpath for later usage in the ImportCollectorPlugin
				rootpath = config.path;
				parserOptions.filename = config.localPath;
			}

			// Keep filename for later usage (see ImportCollectorPlugin) as less modifies the parserOptions.filename
			var filename = parserOptions.filename;

			// Only use custom file handler when "rootPaths" are defined
			var fnFileHandler;
			if (options.rootPaths && options.rootPaths.length > 0) {
				fnFileHandler = fileHandler;
			}

			var parser = createParser(parserOptions, fnFileHandler);

			parser.parse(config.content, function(err, tree) {

				if (err) {
					reject(err);
					return;
				}

				var result = {};

				result.tree = tree;

				// plugins to collect imported files and variable values
				var oImportCollector = new ImportCollectorPlugin({
					importMappings: mFileMappings[filename]
				});
				var oVariableCollector = new VariableCollectorPlugin();

				// render to css
				result.css = tree.toCSS(assign(options.compiler, {
					plugins: [ oImportCollector, oVariableCollector ]
				}));

				// retrieve imported files
				result.imports = oImportCollector.getImports();

				// retrieve imported variables
				result.variables = oVariableCollector.getVariables();

				// also compile rtl-version if requested
				if (options.rtl) {
					result.cssRtl = tree.toCSS(assign(options.compiler, {
						plugins: [ new RTLPlugin() ]
					}));
				}

				if (rootpath) {
					result.imports.unshift(rootpath);
				}

				resolve(result);

			});
		});
	}

	function addInlineParameters(result) {
		return new Promise(function(resolve, reject) {
			if (typeof options.library === "object" && typeof options.library.name === "string") {
				var parameters = JSON.stringify(result.variables);

				// escape all chars that could cause problems with css parsers using URI-Encoding (% + HEX-Code)
				var escapedChars = "%{}()'\"\\";
				for (var i = 0; i < escapedChars.length; i++) {
					var char = escapedChars.charAt(i);
					var hex = char.charCodeAt(0).toString(16).toUpperCase();
					parameters = parameters.replace(new RegExp("\\" + char, "g"), "%" + hex);
				}

				var parameterStyleRule =
					"\n/* Inline theming parameters */\n#sap-ui-theme-" +
					options.library.name.replace(/\./g, "\\.") +
					" { background-image: url('data:text/plain;utf-8," + parameters + "'); }\n";

				// embed parameter variables as plain-text string into css
				result.css += parameterStyleRule;
				if (result.cssRtl) {
					result.cssRtl += parameterStyleRule;
				}
			}
			resolve(result);
		});
	}

	function readDotTheming(dotThemingInputPath) {
		return fileUtils.readFile(dotThemingInputPath, options.rootPaths).then(function(result) {

			var dotTheming;
			var dotThemingFilePath;

			if (result) {
				dotTheming = JSON.parse(result.content);
				dotThemingFilePath = result.path;
			}

			if (dotTheming && dotTheming.mCssScopes) {

				// Currently only the "library" target is supported
				var cssScope = dotTheming.mCssScopes["library"];

				if (cssScope) {

					var aScopes = cssScope.aScopes;
					var oScopeConfig = aScopes[0]; // Currenlty only one scope is supported

					var sBaseFile = dotThemingFileToPath(cssScope.sBaseFile || cssScopeTarget);
					var sEmbeddedCompareFile = dotThemingFileToPath(oScopeConfig.sEmbeddedCompareFile);
					var sEmbeddedFile = dotThemingFileToPath(oScopeConfig.sEmbeddedFile);

					// Currently, only support the use case when "sBaseFile" equals "sEmbeddedCompareFile"
					if (sBaseFile !== sEmbeddedCompareFile) {
						throw new Error("Unsupported content in \"" + dotThemingInputPath + "\": " +
							"\"sBaseFile\" (\"" + (cssScope.sBaseFile || cssScopeTarget) + "\") must be identical with " +
							"\"sEmbeddedCompareFile\" (\"" + oScopeConfig.sEmbeddedCompareFile + "\")");
					}

					var embeddedCompareFilePath = path.posix.join(themeDir, sEmbeddedCompareFile) + '.source.less';
					var embeddedFilePath = path.posix.join(themeDir, sEmbeddedFile) + '.source.less';

					// 1. Compile base + embedded files (both default + RTL variants)
					return Promise.all([
						fileUtils.readFile(embeddedCompareFilePath, options.rootPaths).then(compile),
						fileUtils.readFile(embeddedFilePath, options.rootPaths).then(compile)
					]).then(function(results) {
						return {
							embeddedCompare: results[0],
							embedded: results[1]
						};
					}).then(function(results) {

						// baseFile or embeddedFile
						var sLibraryBaseFile = dotTheming.mCssScopes.library.sBaseFile;
						var sScopeName = oScopeConfig.sSelector;

						function applyScope(embeddedCompareCss, embeddedCss, bRtl) {

							var restoreStringPrototype = cleanupStringPrototype();

							// Create diff object between embeddedCompare and embedded
							var oBase = css.parse(embeddedCompareCss);
							var oEmbedded = css.parse(embeddedCss);

							restoreStringPrototype();

							var oDiff = diff(oBase, oEmbedded);

							// Create scope
							var sScopeSelector = '.' + sScopeName;
							var oScope = scope(oDiff.diff, sScopeSelector);

							var oCssScopeRoot;

							if (oDiff.stack) {
								oCssScopeRoot = scope.scopeCssRoot(oDiff.stack.stylesheet.rules, sScopeName);

								if (oCssScopeRoot) {
									oScope.stylesheet.rules.unshift(oCssScopeRoot);
								}
							}

							// Append scope + stack to embeddedCompareFile (actually target file, which is currently always the same i.e. "library.css")
							// The stack gets appended to the embeddedFile only
							var sAppend = css.stringify(oScope);

							if (sLibraryBaseFile !== "library" && oDiff.stack && oDiff.stack.stylesheet.rules.length > 0) {
								sAppend +=  "\n" + css.stringify(oDiff.stack);
							}

							return sAppend + "\n";

						}

						results.embeddedCompare.css += applyScope(results.embeddedCompare.css, results.embedded.css);
						if (options.rtl) {
							results.embeddedCompare.cssRtl += applyScope(results.embeddedCompare.cssRtl, results.embedded.cssRtl, true);
						}

						// Create diff between embeddedCompare and embeded variables
						var oVariablesBase = results.embeddedCompare.variables;
						var oVariablesEmbedded = results.embedded.variables;
						var oVariablesDiff = {};

						for (var sKey in oVariablesEmbedded) {
							if (sKey in oVariablesBase) {
								if (oVariablesBase[sKey] != oVariablesEmbedded[sKey]) {
									oVariablesDiff[sKey] = oVariablesEmbedded[sKey];
								}
							}
						}

						// Merge variables
						var oVariables = {};
						oVariables["default"] = oVariablesBase;
						oVariables["scopes"] = {};
						oVariables["scopes"][sScopeName] = oVariablesDiff;

						results.embeddedCompare.variables = oVariables;

						var concatImports = function(aImportsBase, aImportsEmbedded) {
							var aConcats = aImportsBase.concat(aImportsEmbedded);

							return aConcats.filter(function(sImport, sIndex) {
								return aConcats.indexOf(sImport) == sIndex;
							})
						};

						if (sLibraryBaseFile !== "library") {
							results.embeddedCompare.imports = concatImports(results.embedded.imports, results.embeddedCompare.imports);
						} else {
							results.embeddedCompare.imports = concatImports(results.embeddedCompare.imports, results.embedded.imports);
						}

						// add .theming file to result.embeddedCompare.imports
						results.embeddedCompare.imports.push(dotThemingFilePath);

						// 6. Resolve promise with complete result object (css, cssRtl, variables, imports)
						return results.embeddedCompare;

					});
				}
			}

			// No css diffing and scoping
			return fileUtils.readFile(options.lessInputPath, options.rootPaths).then(compile);
		});
	}

	if (options.lessInput && options.lessInputPath) {
		return Promise.reject(new Error("Please only provide either `lessInput` or `lessInputPath` but not both."));
	}

	if (!options.lessInput && !options.lessInputPath) {
		return Promise.reject(new Error("Missing required option. Please provide either `lessInput` or `lessInputPath`."));
	}

	if (options.lessInput) {

		return compile({
			content: options.lessInput
		}).then(addInlineParameters).then(that.cacheTheme.bind(that));

	} else {
		var themeDir = path.posix.dirname(options.lessInputPath);

		// Always use the sap/ui/core library to lookup .theming files
		var coreThemeDir = themeDir.replace(/^.*\/themes\//, "/sap/ui/core/themes/");
		var dotThemingInputPath = path.posix.join(coreThemeDir, '.theming');

		return fileUtils.findFile(options.lessInputPath, options.rootPaths).then(function(fileInfo) {

			if (!fileInfo) {
				throw new Error("`lessInputPath` " + options.lessInputPath + " could not be found.");
			}

			// check theme has been already cached
			var themeCache;
			if (fileInfo.path) {
				themeCache = that.getThemeCache(fileInfo.path);
			}

			// Compile theme if not cached or RTL is requested and missing in cache
			if (!themeCache || (options.rtl && !themeCache.result.cssRtl)) {
				return readDotTheming(dotThemingInputPath).then(addInlineParameters).then(that.cacheTheme.bind(that));
			} else {
				return fileUtils.statFiles(themeCache.result.imports).then(function(newStats) {
					for (var i = 0; i < newStats.length; i++) {
						// check if .theming and less files have changed since last less compilation
						if (!newStats[i] || newStats[i].stat.mtime.getTime() !== themeCache.stats[i].stat.mtime.getTime()) {
							return readDotTheming(dotThemingInputPath).then(addInlineParameters).then(that.cacheTheme.bind(that));
						}
					}

					// serve from cache
					return themeCache.result;
				});
			}
		});
	}
};

module.exports.Builder = Builder;
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Projects } from '../api/documents.js';
import './document.js'
import './previewview.html';

Template.previewview.onCreated(function bodyOnCreated() {
});

Template.previewview.helpers({
  previewview() {
    return Projects.find({}).fetch();
    },
});

var readLines = function (docs, extension){
  var lines = docs.fetch()[0].files[0].lines;
  var result="";
  for (var i=0; i<lines.length; i++) {
    if (result) result += "\n";
    result = result+lines[i].text;
  }
  document.getElementById("preview").innerHTML=result;
  return result;
}

var readLinesCSS = function (docs){
  var lines = docs.fetch()[0].files[1].lines;
  var result="";
  for (var i=0; i<lines.length; i++) {
    if (result) result += "\n";
    result = result+lines[i].text;
  }
  var css = document.createElement("style");
  css.innerHTML = result;
  document.head.appendChild(css);
  return result;
}

var readLinesJS = function (docs){
  var lines = docs.fetch()[0].files[2].lines;
  var result = "";
  for (var i=0; i<lines.length; i++) {
    if (result) result += "\n";
    result = result+lines[i].text;
  }
  var js = document.createElement("script");
  js.innerHTML = result;
  document.head.appendChild(js);
  return result;
}

var searchs = function (docs,filename){
  var files = docs.files;
  var result="";
  for (var i=0; i<files.length; i++) {
    var name= docs.files[i].name;
    var extension= docs.files[i].extension;
    var nameExtencion = name+"."+extension;
    if (filename==nameExtencion) {
     var lines = docs.files[i].lines;
       for (var i=0; i<lines.length; i++) {
        result = result+lines[i].text+"\n";
      }

    }
  }
  return result;
}

Template.previewview.onRendered( function() {
  this.autorun(() => {
     var subscriptions = Meteor.subscribe('projects');
     const isReady = subscriptions.ready();
     var docs = Projects.find({});
     if (isReady && docs) {
      var lines = readLines(docs);
      readLinesCSS(docs);
      readLinesJS(docs);
     }
  });
});

<commit_msg>removed unused function<commit_after>import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Projects } from '../api/documents.js';
import './document.js'
import './previewview.html';

Template.previewview.onCreated(function bodyOnCreated() {
});

Template.previewview.helpers({
  previewview() {
    return Projects.find({}).fetch();
    },
});

var readLines = function (docs, extension){
  var lines = docs.fetch()[0].files[0].lines;
  var result="";
  for (var i=0; i<lines.length; i++) {
    if (result) result += "\n";
    result = result+lines[i].text;
  }
  document.getElementById("preview").innerHTML=result;
  return result;
}

var readLinesCSS = function (docs){
  var lines = docs.fetch()[0].files[1].lines;
  var result="";
  for (var i=0; i<lines.length; i++) {
    if (result) result += "\n";
    result = result+lines[i].text;
  }
  var css = document.createElement("style");
  css.innerHTML = result;
  document.head.appendChild(css);
  return result;
}

var readLinesJS = function (docs){
  var lines = docs.fetch()[0].files[2].lines;
  var result = "";
  for (var i=0; i<lines.length; i++) {
    if (result) result += "\n";
    result = result+lines[i].text;
  }
  var js = document.createElement("script");
  js.innerHTML = result;
  document.head.appendChild(js);
  return result;
}

Template.previewview.onRendered( function() {
  this.autorun(() => {
    var subscriptions = Meteor.subscribe('projects');
    const isReady = subscriptions.ready();
    var docs = Projects.find({});
    if (isReady && docs) {
      var lines = readLines(docs);
      readLinesCSS(docs);
      readLinesJS(docs);
    }
  });
});<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { propType } from 'graphql-anywhere';
import styled from 'styled-components';

import selectableChannelFragment from 'react/components/ConnectionSelectionList/components/SelectableChannel/fragments/selectableChannel';

import ColoredChannelSpan from 'react/components/UI/ColoredChannelSpan';
import TickerTapeHover from 'react/components/UI/TickerTapeHover';

import { inputPadding } from 'react/components/UI/Inputs';
import { baseMixin as baseTextMixin } from 'react/components/UI/Text';

const Container = styled.div.attrs({
  role: 'button',
  tabIndex: 0,
  f: 1,
})`
  ${baseTextMixin}
  position: relative;
  margin-top: -1px;
  line-height: 1;
  user-select: none;
  cursor: pointer;
  color: ${x => x.theme.colors.gray.semiBold};
  border: 1px solid ${x => x.theme.colors.gray.regular};
  background-color: ${x => x.theme.colors.gray.hint};
  white-space: nowrap;
  overflow: hidden;

  &:hover {
    z-index: 1;
    border: 1px solid ${x => x.theme.colors.gray.semiBold};
  }

  &:before {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 1em;
    background: linear-gradient(to left, ${x => x.theme.colors.gray.hint}, ${x => x.theme.colors.utility.transparent});
    z-index: 1;
  }

  &:hover,
  &[data-selected="true"] {
    &:before {
      width: 3em;
      background linear-gradient(to left, ${x => x.theme.colors.gray.hint} 60%, ${x => x.theme.colors.utility.transparent})
    }

    &:after {
      content: '✔';
      position: absolute;
      top: 50%;
      right: 0;
      width: 2em;
      text-align: center;
      transform: translateY(-50%);
      z-index: 1;
    }
  }

  &[data-selected="true"] {
    > div {
      opacity: 0.5;
    }
  }
`;

const HoverableInner = styled(TickerTapeHover).attrs({
  speed: 1,
  offsetBuffer: 32,
})`
  padding: ${inputPadding}; // TODO
`;

const Separator = styled.div`
  display: inline-block;
  width: 1px;
  height: 0.75em;
  margin: 0 0.75em;
  vertical-align: baseline;
  transform: rotate(30deg);
  background-color: ${x => x.theme.colors.gray.medium};
`;

export default class SelectableChannel extends Component {
  static propTypes = {
    channel: propType(selectableChannelFragment).isRequired,
    onSelection: PropTypes.func,
  }

  static defaultProps = {
    onSelection: () => {},
  }

  state = {
    isSelected: false,
  }

  toggleSelection = () => {
    const { onSelection, channel } = this.props;

    this.setState(({ isSelected }) => {
      onSelection(!isSelected, channel.id);

      return { isSelected: !isSelected };
    });
  }

  render() {
    const { isSelected } = this.state;
    const { channel: { title, visibility, user: { name } } } = this.props;

    return (
      <Container onClick={this.toggleSelection} data-selected={isSelected}>
        <HoverableInner>
          {name}
          <Separator />

          <ColoredChannelSpan visibility={visibility}>
            {title}
          </ColoredChannelSpan>
        </HoverableInner>
      </Container>
    );
  }
}
<commit_msg>Left-align connect selectable channel<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { propType } from 'graphql-anywhere';
import styled from 'styled-components';

import selectableChannelFragment from 'react/components/ConnectionSelectionList/components/SelectableChannel/fragments/selectableChannel';

import ColoredChannelSpan from 'react/components/UI/ColoredChannelSpan';
import TickerTapeHover from 'react/components/UI/TickerTapeHover';

import { inputPadding } from 'react/components/UI/Inputs';
import { baseMixin as baseTextMixin } from 'react/components/UI/Text';

const Container = styled.div.attrs({
  role: 'button',
  tabIndex: 0,
  f: 1,
})`
  ${baseTextMixin}
  position: relative;
  margin-top: -1px;
  line-height: 1;
  user-select: none;
  cursor: pointer;
  color: ${x => x.theme.colors.gray.semiBold};
  border: 1px solid ${x => x.theme.colors.gray.regular};
  background-color: ${x => x.theme.colors.gray.hint};
  white-space: nowrap;
  overflow: hidden;
  text-align: left;

  &:hover {
    z-index: 1;
    border: 1px solid ${x => x.theme.colors.gray.semiBold};
  }

  &:before {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 1em;
    background: linear-gradient(to left, ${x => x.theme.colors.gray.hint}, ${x => x.theme.colors.utility.transparent});
    z-index: 1;
  }

  &:hover,
  &[data-selected="true"] {
    &:before {
      width: 3em;
      background linear-gradient(to left, ${x => x.theme.colors.gray.hint} 60%, ${x => x.theme.colors.utility.transparent})
    }

    &:after {
      content: '✔';
      position: absolute;
      top: 50%;
      right: 0;
      width: 2em;
      text-align: center;
      transform: translateY(-50%);
      z-index: 1;
    }
  }

  &[data-selected="true"] {
    > div {
      opacity: 0.5;
    }
  }
`;

const HoverableInner = styled(TickerTapeHover).attrs({
  speed: 1,
  offsetBuffer: 32,
})`
  padding: ${inputPadding}; // TODO
`;

const Separator = styled.div`
  display: inline-block;
  width: 1px;
  height: 0.75em;
  margin: 0 0.75em;
  vertical-align: baseline;
  transform: rotate(30deg);
  background-color: ${x => x.theme.colors.gray.medium};
`;

export default class SelectableChannel extends Component {
  static propTypes = {
    channel: propType(selectableChannelFragment).isRequired,
    onSelection: PropTypes.func,
  }

  static defaultProps = {
    onSelection: () => {},
  }

  state = {
    isSelected: false,
  }

  toggleSelection = () => {
    const { onSelection, channel } = this.props;

    this.setState(({ isSelected }) => {
      onSelection(!isSelected, channel.id);

      return { isSelected: !isSelected };
    });
  }

  render() {
    const { isSelected } = this.state;
    const { channel: { title, visibility, user: { name } } } = this.props;

    return (
      <Container onClick={this.toggleSelection} data-selected={isSelected}>
        <HoverableInner>
          {name}
          <Separator />

          <ColoredChannelSpan visibility={visibility}>
            {title}
          </ColoredChannelSpan>
        </HoverableInner>
      </Container>
    );
  }
}
<|endoftext|>


<commit_before>// Barbiche
// version: 0.1.0
// author: Manuel Baclet <manuel@eda.sarl>
// license: MIT

var prefix = 'bb-';
var destructive = false;
var re;
var store = {};

var context = {
	stack: []
};

context.resolve = function(identifier) {
	var m = this.stack.length - 1;
	var value;
	while (value === undefined && m >= 0) {
		value = this.stack[m][identifier];
		m--;
	}
	return (value === undefined) ? window[identifier] : value;
};

context.init = function(arr) {
	this.stack = arr || [];
};

context.push = function(obj) {
	this.stack.push(obj);
};

context.pop = function() {
	return this.stack.pop();
};

var Parser = require('../parser.js');
Parser.parser.yy.context = context;

function Barbiche(node) {
	if (typeof(node) == 'string') {
		if (store[node]) return store[node];
		else node = document.querySelector('#' + node);
	}
	if (!(this instanceof Barbiche)) {
		return new Barbiche(node);
	}
	if (node) {
		if (node.id) store[node.id] = this;
		this.closures = {};
		this.node = (destructive) ? node : node.cloneNode(true);
		this.ready = false;
	}
	return this;
}

Barbiche.setPrefix = function(str) {
	prefix = str;
};

Barbiche.setDestructive = function(bool) {
	destructive = bool;
};

Barbiche.setDelimiters = function(arr) {
	var str = '{{([^{}]*)}}|{{{([^{}]*)}}}|([^{}]+)';
	var escaped = arr.map(function(char) {
		return char.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
	});
	re = new RegExp(str.replace(/{|}/g, function(match) {if (match == '{') return escaped[0]; else return escaped[1];}), 'g');
};

Barbiche.setDelimiters(['{', '}']);

Barbiche.clean = function(name) {
	if (name) delete store[name];
	else {
		for (var key in store) {
			delete store[key];
		}
	}
};

function addPrefix(str) {
	return prefix + str;
}

var compile_works = {};
compile_works[Node.ELEMENT_NODE] = function(node, template) {
	if (node.hasAttribute(prefix + 'repeat') && node.nodeName != 'TEMPLATE') {
		if (node.hasAttribute(prefix + 'text') || node.hasAttribute(prefix + 'html')) node.removeAttribute(prefix + 'repeat');
		else {
			var wrapper = document.createElement('template');
			wrapper.setAttribute(prefix + 'repeat', node.getAttribute(prefix + 'repeat'));
			node.removeAttribute(prefix + 'repeat');
			['if', 'alias'].map(addPrefix).forEach(function(attr) {
				if (node.hasAttribute(attr)) {
					wrapper.setAttribute(attr, node.getAttribute(attr));
					node.removeAttribute(attr);
				}
			});
			node.before(wrapper);
			wrapper.content.appendChild(node);
			node = wrapper;
		}
	}
	['if', 'alias', 'text', 'html', 'repeat', 'import', 'attr', 'class'].map(addPrefix).forEach(function(attr) {
		if (node.hasAttribute(attr)) {
			var parsed = Parser.parse(node.getAttribute(attr));
			node.setAttribute(attr, template._addClosure(parsed));
		}
	});
	if (node.nodeName == 'TEMPLATE') {
		compile(node.content, template);
	} else {
		Array.from(node.childNodes).forEach(function(child) {
			compile(child, template);
		});
	}
}

compile_works[Node.TEXT_NODE] = function(node, template) {
	var value = node.nodeValue;
	var tokenFound = false;
	var res;
	var stack = [];
	while(res = re.exec(value)) {
		if (res[3]) {
			stack.push({
				content: res[3],
				type: 'plain'
			});
		} else if (res[1]) {
			stack.push({
				content: res[1],
				type: 'text'
			});
			tokenFound = true;
		} else {
			stack.push({
				content: res[2],
				type: 'html'
			});
			tokenFound = true;
		}
	}
	if (tokenFound) {
		function resolve(accu) {
			var exp = accu.join('+');
			if (exp) {
				var t = document.createElement('template');
				t.setAttribute(prefix + 'text', exp);
				node.before(t); compile(t, template);
			}
		}
		resolve(stack.reduce(function(accu, item) {
			if (item.type == 'plain') {
				accu.push('"' + item.content.replace(/('|"|\n|\t|\r)/g, function() {return '\\' + arguments[1];}) + '"');
				return accu;
			} else if (item.type == 'text') {
				accu.push(item.content);
				return accu;
			} else {
				resolve(accu);
				var t = document.createElement('template');
				t.setAttribute(prefix + 'html', item.content);
				node.before(t); compile(t, template);
				return [];
			}
		}, []));
		node.remove();
	}
};

compile_works[Node.COMMENT_NODE] = function(node, template) {};

compile_works[Node.DOCUMENT_FRAGMENT_NODE] = function(node, template) {
	Array.from(node.childNodes).forEach(function(child) {compile(child, template);});
};

Barbiche.prototype._addClosure = (function() {
	var counter = 0;
	return function(fun) {
		counter++;
		var str = 'fun' + counter;
		this.closures[str] = fun;
		return str;
	};
})();

Barbiche.prototype._compile = function() {
	compile(this.node.content, this);
	this.ready = true;
	return this;
};

function compile(node, template) {
	(compile_works[node.nodeType])(node, template);
}

Barbiche.prototype._clone = function() {
	if (!this.ready) this._compile();
	var t = new Barbiche();
	t.node = this.node.cloneNode(true);
	t.closures = this.closures;
	return t;
}

Barbiche.prototype.merge = function() {
	var clone = this._clone();
	context.init(Array.from(arguments));
	merge(clone.node.content, clone);
	context.init();
	return clone.node.content;
}

var works = {};
works[Node.ELEMENT_NODE] = function(node, template) {
	var nodeContext = {};
	var nodeContextPushed = false;
	if (node.hasAttribute(prefix + 'if')) {
		var value = (template.closures[node.getAttribute(prefix + 'if')])();
		if (value) node.removeAttribute(prefix + 'if');
		else return node.remove();
	}
	if (node.hasAttribute(prefix + 'alias')) {
		var parsed = (template.closures[node.getAttribute(prefix + 'alias')])();
		parsed.forEach(function(item) {
			nodeContext[item.name] = item.value;
		});
		context.push(nodeContext);
		nodeContextPushed = true;
		node.removeAttribute(prefix + 'alias');
	}
	if (node.hasAttribute(prefix + 'text')) {
		var value = (template.closures[node.getAttribute(prefix + 'text')])();
		if (value !== undefined) {
			node.replaceWith(value);
		} else node.remove();
	} else if (node.hasAttribute(prefix + 'html')) {
		var value = (template.closures[node.getAttribute(prefix + 'html')])();
		if (value !== undefined) {
			var template = document.createElement('template');
			template.innerHTML = value;
			node.replaceWith(template.content);
		} else node.remove();
	} else if (node.nodeName == "TEMPLATE") {
		if (node.hasAttribute(prefix + 'repeat')) {
			var closure = null;
			if (node.hasAttribute(prefix + 'import')) {
				closure = template.closures[node.getAttribute(prefix + 'import')];
			}
			if (!nodeContextPushed) {
				context.push(nodeContext);
				nodeContextPushed = true;
			}
			var parsed = (template.closures[node.getAttribute(prefix + 'repeat')])();
			var order = parsed.order || 'before';
			//iterate on cartesian product of arrays:
			(parsed.reduceRight(function(accu, task) {
				var alias = task.name;
				var value = task.value;
				return function() {
					value.forEach(function(item, index) {
						nodeContext[alias] = value[index];
						nodeContext['_' + alias + '_'] = index;
						accu();
					})
				};
			}, function() {
				var target = closure && Barbiche(closure()).node;
				var copy = (target || node).cloneNode(true);
				node[order](merge(copy.content, template));
			}))();
		} else if (node.hasAttribute(prefix + 'import')) {
			var importId = (template.closures[node.getAttribute(prefix + 'import')])();
			var clone = Barbiche(importId)._clone();
			node.before(merge(clone.node.content, clone));
		} else {
			node.before(merge(node.content, template));
		}
		node.remove();
	} else {
		if (node.hasAttribute(prefix + 'attr')) {
			var parsed = (template.closures[node.getAttribute(prefix + 'attr')])();
			parsed.forEach(function(item) {
				var value = item.value;
				var name = item.name;
				if (name) {
					if (typeof value == "string") node.setAttribute(name, value);
					else node.removeAttribute(name);
				}
			});
			node.removeAttribute(prefix + 'attr');
		}
		if (node.hasAttribute(prefix + 'class')) {
			var parsed = (template.closures[node.getAttribute(prefix + 'class')])();
			parsed.forEach(function(item) {
				var value = item.value;
				var name = item.name;
				if (name) {
					if (value) node.classList.add(name);
					else node.classList.remove(name);
				}
			});
			node.removeAttribute(prefix + 'class');
		}
		Array.from(node.children).forEach(function(child) {merge(child, template);});
	}
	if (nodeContextPushed) context.pop();
};

works[Node.TEXT_NODE] = function(node, template) {};

works[Node.COMMENT_NODE] = function(node, template) {};

works[Node.DOCUMENT_FRAGMENT_NODE] = function(node, template) {
	Array.from(node.children || node.childNodes).forEach(function(child) {merge(child, template);});
};

function merge(node, template) {
	(works[node.nodeType])(node, template);
	return node;
}

module.exports = Barbiche;
<commit_msg>Perf improvement<commit_after>// Barbiche
// version: 0.1.0
// author: Manuel Baclet <manuel@eda.sarl>
// license: MIT

var prefix = 'bb-';
var destructive = false;
var re;
var store = {};

var context = {
	stack: []
};

context.resolve = function(identifier) {
	var m = this.stack.length - 1;
	var value;
	while (value === undefined && m >= 0) {
		value = this.stack[m][identifier];
		m--;
	}
	return (value === undefined) ? window[identifier] : value;
};

context.init = function(arr) {
	this.stack = arr || [];
};

context.push = function(obj) {
	this.stack.push(obj);
};

context.pop = function() {
	return this.stack.pop();
};

var Parser = require('../parser.js');
Parser.parser.yy.context = context;

function Barbiche(node) {
	if (typeof(node) == 'string') {
		if (store[node]) return store[node];
		else node = document.querySelector('#' + node);
	}
	if (!(this instanceof Barbiche)) {
		return new Barbiche(node);
	}
	if (node) {
		if (node.id) store[node.id] = this;
		this.closures = {};
		this.node = (destructive) ? node : node.cloneNode(true);
		this.ready = false;
	}
	return this;
}

Barbiche.setPrefix = function(str) {
	prefix = str;
};

Barbiche.setDestructive = function(bool) {
	destructive = bool;
};

Barbiche.setDelimiters = function(arr) {
	var str = '{{([^{}]*)}}|{{{([^{}]*)}}}|([^{}]+)';
	var escaped = arr.map(function(char) {
		return char.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
	});
	re = new RegExp(str.replace(/{|}/g, function(match) {if (match == '{') return escaped[0]; else return escaped[1];}), 'g');
};

Barbiche.setDelimiters(['{', '}']);

Barbiche.clean = function(name) {
	if (name) delete store[name];
	else {
		for (var key in store) {
			delete store[key];
		}
	}
};

function addPrefix(str) {
	return prefix + str;
}

var compile_works = {};
compile_works[Node.ELEMENT_NODE] = function(node, template) {
	if (node.hasAttribute(prefix + 'repeat') && node.nodeName != 'TEMPLATE') {
		if (node.hasAttribute(prefix + 'text') || node.hasAttribute(prefix + 'html')) node.removeAttribute(prefix + 'repeat');
		else {
			var wrapper = document.createElement('template');
			wrapper.setAttribute(prefix + 'repeat', node.getAttribute(prefix + 'repeat'));
			node.removeAttribute(prefix + 'repeat');
			['if', 'alias'].map(addPrefix).forEach(function(attr) {
				if (node.hasAttribute(attr)) {
					wrapper.setAttribute(attr, node.getAttribute(attr));
					node.removeAttribute(attr);
				}
			});
			node.before(wrapper);
			wrapper.content.appendChild(node);
			node = wrapper;
		}
	}
	var bbAttrs = {};
	var attrFound = false;
	['if', 'alias', 'text', 'html', 'repeat', 'import', 'attr', 'class'].forEach(function(attr) {
		if (node.hasAttribute(prefix + attr)) {
			attrFound = true;
			var parsed = Parser.parse(node.getAttribute(prefix + attr));
			bbAttrs[attr] = template._addClosure(parsed);
			node.removeAttribute(prefix + attr);
		}
	});
	if (attrFound) node.setAttribute(prefix + 'global', JSON.stringify(bbAttrs));
	if (node.nodeName == 'TEMPLATE') {
		compile(node.content, template);
	} else {
		Array.from(node.childNodes).forEach(function(child) {
			compile(child, template);
		});
	}
}

compile_works[Node.TEXT_NODE] = function(node, template) {
	var value = node.nodeValue;
	var tokenFound = false;
	var res;
	var stack = [];
	while(res = re.exec(value)) {
		if (res[3]) {
			stack.push({
				content: res[3],
				type: 'plain'
			});
		} else if (res[1]) {
			stack.push({
				content: res[1],
				type: 'text'
			});
			tokenFound = true;
		} else {
			stack.push({
				content: res[2],
				type: 'html'
			});
			tokenFound = true;
		}
	}
	if (tokenFound) {
		function resolve(accu) {
			var exp = accu.join('+');
			if (exp) {
				var t = document.createElement('template');
				t.setAttribute(prefix + 'text', exp);
				node.before(t); compile(t, template);
			}
		}
		resolve(stack.reduce(function(accu, item) {
			if (item.type == 'plain') {
				accu.push('"' + item.content.replace(/('|"|\n|\t|\r)/g, function() {return '\\' + arguments[1];}) + '"');
				return accu;
			} else if (item.type == 'text') {
				accu.push(item.content);
				return accu;
			} else {
				resolve(accu);
				var t = document.createElement('template');
				t.setAttribute(prefix + 'html', item.content);
				node.before(t); compile(t, template);
				return [];
			}
		}, []));
		node.remove();
	}
};

compile_works[Node.COMMENT_NODE] = function(node, template) {};

compile_works[Node.DOCUMENT_FRAGMENT_NODE] = function(node, template) {
	Array.from(node.childNodes).forEach(function(child) {compile(child, template);});
};

Barbiche.prototype._addClosure = (function() {
	var counter = 0;
	return function(fun) {
		counter++;
		var str = 'fun' + counter;
		this.closures[str] = fun;
		return str;
	};
})();

Barbiche.prototype._compile = function() {
	compile(this.node.content, this);
	this.ready = true;
	return this;
};

function compile(node, template) {
	(compile_works[node.nodeType])(node, template);
}

Barbiche.prototype._clone = function() {
	if (!this.ready) this._compile();
	var t = new Barbiche();
	t.node = this.node.cloneNode(true);
	t.closures = this.closures;
	return t;
}

Barbiche.prototype.merge = function() {
	var clone = this._clone();
	context.init(Array.from(arguments));
	merge(clone.node.content, clone);
	context.init();
	return clone.node.content;
}

var works = {};
works[Node.ELEMENT_NODE] = function(node, template) {
	var nodeContext = {};
	var nodeContextPushed = false;
	var bbAttrs;
	if (node.hasAttribute(prefix + 'global')) {
		bbAttrs = JSON.parse(node.getAttribute(prefix + 'global'));
		node.removeAttribute(prefix + 'global');
	}
	bbAttrs = bbAttrs || {};
	if (bbAttrs.if) {
		var value = (template.closures[bbAttrs.if])();
		if (!value) return node.remove();
	}
	if (bbAttrs.alias) {
		var parsed = (template.closures[bbAttrs.alias])();
		parsed.forEach(function(item) {
			nodeContext[item.name] = item.value;
		});
		context.push(nodeContext);
		nodeContextPushed = true;
	}
	if (bbAttrs.text) {
		var value = (template.closures[bbAttrs.text])();
		if (value !== undefined) {
			node.replaceWith(value);
		} else node.remove();
	} else if (bbAttrs.html) {
		var value = (template.closures[bbAttrs.html])();
		if (value !== undefined) {
			var template = document.createElement('template');
			template.innerHTML = value;
			node.replaceWith(template.content);
		} else node.remove();
	} else if (node.nodeName == "TEMPLATE") {
		if (bbAttrs.repeat) {
			var closure;
			if (bbAttrs.import) {
				closure = template.closures[bbAttrs.import];
			}
			if (!nodeContextPushed) {
				context.push(nodeContext);
				nodeContextPushed = true;
			}
			var parsed = (template.closures[bbAttrs.repeat])();
			var order = parsed.order || 'before';
			//iterate on cartesian product of arrays:
			(parsed.reduceRight(function(accu, task) {
				var alias = task.name;
				var value = task.value;
				return function() {
					value.forEach(function(item, index) {
						nodeContext[alias] = value[index];
						nodeContext['_' + alias + '_'] = index;
						accu();
					})
				};
			}, function() {
				var target = closure && Barbiche(closure()).node;
				var copy = (target || node).cloneNode(true);
				node[order](merge(copy.content, template));
			}))();
		} else if (bbAttrs.import) {
			var importId = (template.closures[bbAttrs.import])();
			var clone = Barbiche(importId)._clone();
			node.before(merge(clone.node.content, clone));
		} else {
			node.before(merge(node.content, template));
		}
		node.remove();
	} else {
		if (bbAttrs.attr) {
			var parsed = (template.closures[bbAttrs.attr])();
			parsed.forEach(function(item) {
				var value = item.value;
				var name = item.name;
				if (name) {
					if (typeof value == "string") node.setAttribute(name, value);
					else node.removeAttribute(name);
				}
			});
		}
		if (bbAttrs.class) {
			var parsed = (template.closures[bbAttrs.class])();
			parsed.forEach(function(item) {
				var value = item.value;
				var name = item.name;
				if (name) {
					if (value) node.classList.add(name);
					else node.classList.remove(name);
				}
			});
		}
		Array.from(node.children).forEach(function(child) {merge(child, template);});
	}
	if (nodeContextPushed) context.pop();
};

works[Node.TEXT_NODE] = function(node, template) {};

works[Node.COMMENT_NODE] = function(node, template) {};

works[Node.DOCUMENT_FRAGMENT_NODE] = function(node, template) {
	Array.from(node.children || node.childNodes).forEach(function(child) {merge(child, template);});
};

function merge(node, template) {
	(works[node.nodeType])(node, template);
	return node;
}

module.exports = Barbiche;
<|endoftext|>


<commit_before>'use strict';

var Q = require('q'),
    util = require('util'),
    events = require('events');

var STATES = {
  OPEN : 'OPEN',
  CLOSED: 'CLOSED',
  HALF: 'HALF-OPEN'
};

var CircuitBreaker = module.exports = function (func, options) {
  events.EventEmitter.call(this);

  this.options = options || {};
  this._func = func;
  this.timeout = this.options.timeout || 10000; // default 10 second timeout (ms)
  this.resetTimeout = this.options.resetTimeout || 60000; // default 1 minute reset timeout (ms)
  this.maxFailures = this.options.maxFailures || 5; // default max number of failures to open circuit

  // Initially circuit is always closed
  this.forceClosed();
};

util.inherits(CircuitBreaker, events.EventEmitter);

var internals = {};

internals.parseArgs = function(argsArray) {

  var result = [];
  for(var i = 0; i < argsArray.length; i++) {
    result.push(argsArray[i]);
  }

  return result;
};

CircuitBreaker.prototype.invoke = function () {
  var self = this;

  if(self.isOpen() || (self.isHalfOpen() && self._halfOpenCallPending)) {
    return self._fastFail();
  } else if(self.isHalfOpen() && !self._halfOpenCallPending) {
    self._halfOpenCallPending = true;
    return self._callFunction.apply(self, arguments).fin(function () {
      self._halfOpenCallPending = false;
    });
  } else {
    return self._callFunction.apply(self, arguments);
  }
};

CircuitBreaker.prototype._fastFail = function () {
  return Q.fcall(function () {
    throw new Error('Circuit Breaker open');
  });
};

CircuitBreaker.prototype._callFunction = function () {
  var self = this;

  var deferred = Q.defer();

  var args = internals.parseArgs(arguments);

  args.push(deferred.makeNodeResolver());

  setTimeout(deferred.reject, self.timeout);

  var promise = deferred.promise;

  promise.then(function () {
    self.handleSuccess();
  }, function(err) {
    self.handleFailure(err);
  });

  self._func.apply(self._func, args);

  return promise;
};

CircuitBreaker.prototype.handleSuccess = function () {
  this.forceClosed();
};

CircuitBreaker.prototype.handleFailure = function () {
  ++this._numFailures;

  if(this.isHalfOpen() || this._numFailures >= this.maxFailures) {
    this.forceOpen();
  }
};

CircuitBreaker.prototype.isOpen = function () {
  return this.state === STATES.OPEN;
};

CircuitBreaker.prototype.isHalfOpen = function () {
  return this.state === STATES.HALF;
};

CircuitBreaker.prototype.isClosed = function () {
  return this.state === STATES.CLOSED;
};

CircuitBreaker.prototype.forceOpen = function () {
  var self = this;

  if(this.state === STATES.OPEN) {
    return;
  }

  this.state = STATES.OPEN;

  // After reset timeout circuit should enter half open state
  setTimeout(function () {
    self.forceHalfOpen();
  }, self.resetTimeout);

  self.emit('open');
};

CircuitBreaker.prototype.forceClosed = function () {
  this.state = STATES.CLOSED;
  this._numFailures = 0;

  this.emit('close');
};

CircuitBreaker.prototype.forceHalfOpen = function () {
  this.state = STATES.HALF;

  this.emit('halfOpen');
};
<commit_msg>slight refactoring cleanup of callFunction<commit_after>'use strict';

var Q = require('q'),
    util = require('util'),
    events = require('events');

var STATES = {
  OPEN : 'OPEN',
  CLOSED: 'CLOSED',
  HALF: 'HALF-OPEN'
};

var CircuitBreaker = module.exports = function (func, options) {
  events.EventEmitter.call(this);

  this.options = options || {};
  this._func = func;
  this.timeout = this.options.timeout || 10000; // default 10 second timeout (ms)
  this.resetTimeout = this.options.resetTimeout || 60000; // default 1 minute reset timeout (ms)
  this.maxFailures = this.options.maxFailures || 5; // default max number of failures to open circuit

  // Initially circuit is always closed
  this.forceClosed();
};

util.inherits(CircuitBreaker, events.EventEmitter);

var internals = {};

internals.parseArgs = function(argsArray) {

  var result = [];
  for(var i = 0; i < argsArray.length; i++) {
    result.push(argsArray[i]);
  }

  return result;
};

CircuitBreaker.prototype.invoke = function () {
  var self = this;

  if(self.isOpen() || (self.isHalfOpen() && self._halfOpenCallPending)) {
    return self._fastFail();
  } else if(self.isHalfOpen() && !self._halfOpenCallPending) {
    self._halfOpenCallPending = true;
    return self._callFunction.apply(self, arguments).fin(function () {
      self._halfOpenCallPending = false;
    });
  } else {
    return self._callFunction.apply(self, arguments);
  }
};

CircuitBreaker.prototype._fastFail = function () {
  return Q.fcall(function () {
    throw new Error('Circuit Breaker open');
  });
};

CircuitBreaker.prototype._callFunction = function () {
  var self = this;

  var deferred = Q.defer();

  var args = internals.parseArgs(arguments);

  args.push(deferred.makeNodeResolver());

  setTimeout(deferred.reject, self.timeout);

  var promise = deferred.promise;

  promise.then(self.handleSuccess.bind(self), self.handleFailure.bind(self));

  self._func.apply(self._func, args);

  return promise;
};

CircuitBreaker.prototype.handleSuccess = function () {
  this.forceClosed();
};

CircuitBreaker.prototype.handleFailure = function () {
  ++this._numFailures;

  if(this.isHalfOpen() || this._numFailures >= this.maxFailures) {
    this.forceOpen();
  }
};

CircuitBreaker.prototype.isOpen = function () {
  return this.state === STATES.OPEN;
};

CircuitBreaker.prototype.isHalfOpen = function () {
  return this.state === STATES.HALF;
};

CircuitBreaker.prototype.isClosed = function () {
  return this.state === STATES.CLOSED;
};

CircuitBreaker.prototype.forceOpen = function () {
  var self = this;

  if(this.state === STATES.OPEN) {
    return;
  }

  this.state = STATES.OPEN;

  // After reset timeout circuit should enter half open state
  setTimeout(function () {
    self.forceHalfOpen();
  }, self.resetTimeout);

  self.emit('open');
};

CircuitBreaker.prototype.forceClosed = function () {
  this.state = STATES.CLOSED;
  this._numFailures = 0;

  this.emit('close');
};

CircuitBreaker.prototype.forceHalfOpen = function () {
  this.state = STATES.HALF;

  this.emit('halfOpen');
};
<|endoftext|>


<commit_before>(function (ns) {

    var TYPE_LIST = {};

    var SOURCE_MAP = {},
        SOURCE_LIST = []

    var ShadeStudio = function() {
        this.paramList = [];
        this.paramForm = null;
        this.console = null;
        this.lastErrorLocation = null;
        this.storage = storageSupported() ? ns.localStorage : {};
        this.paramStateLoaded = false;
    };

    ShadeStudio.prototype = {
        init: function() {
            initTypeList();
            this.javaScriptEditor = CodeMirror.fromTextArea(document.querySelector("textarea"), {
                mode: "javascript",
                lineNumbers: true

            });
            this.javaScriptEditor.on("change", this.onEdit.bind(this));
            this.codeViewer = CodeMirror(document.querySelector(".codeOutput"), {
                value: "",
                mode:  "x-shader/x-fragment",
                lineNumbers: true
            });
            this.codeViewer.on("change", this.compileGL.bind(this));

            this.paramForm = document.getElementById("paramList");
            this.console = $("#console");

            if (this.storage.lastShaderCode !== undefined) {
                this.javaScriptEditor.setValue(this.storage.lastShaderCode);
            };
            try {
                this.gl = $(".theCanvas")[0].getContext("experimental-webgl");
                this.initGL();
            } catch(e) {
                this.addConsoleText(e.toString(), true);
                this.gl = null;
            }

        },
        onEdit: function(instance, obj) {
            var newValue = this.javaScriptEditor.getValue();
            var codeCorrect = false;
            this.storage.lastShaderCode = newValue;
            if(this.lastErrorLocation && this.lastErrorLocation.start.line){
                this.javaScriptEditor.removeLineClass(this.lastErrorLocation.start.line -1, 'background', 'line-error');
                this.lastErrorLocation = null;
            }
            $("#main").removeClass("error");
            $("#main").removeClass("codeError");
            try {
                var params = Shade.extractParameters(newValue);
                console.log(params);
                codeCorrect = true;
                this.updateParameterSelection(params);
                this.updateOutput();

            } catch (e) {
                console.log(e.toString());
                console.log(e.loc);
                $("#main").addClass("error");
                if(!codeCorrect) $("#main").addClass("codeError");
                var errorLocation = e.loc || { start: { line: e.lineNumber }};
                this.lastErrorLocation = errorLocation;
                if(errorLocation.start.line)
                    this.javaScriptEditor.addLineClass(errorLocation.start.line - 1, 'background', 'line-error');
                //this.javaScriptEditor.setLineClass(lineNumber, 'background', 'line-error');
                this.addConsoleText(e.toString(), true)
            }
        },
        updateParameterSelection: function(params){
            if(this.paramList.join("j") == params.join(";"))
                return;
            this.paramList = params;

            var newSelects = {};
            for(var i = 0; i < params.length; ++i){
                var paramName = params[i], sourceName = "_" + paramName + "__source";
                var oldField = this.paramForm.elements[paramName],
                    oldSourceField = this.paramForm.elements[sourceName];
                newSelects[paramName] = createParamSelect(paramName,
                    oldField && oldField.value, oldSourceField && oldSourceField.value);
            }
            var list = $("#inputList");
            list.empty();
            for(var name in newSelects){
                list.append(newSelects[name]);
            }
            if(!this.paramStateLoaded){
                this.paramStateLoaded = true;
                if(this.storage.lastParamState){
                    this.loadParamInfo(JSON.parse(this.storage.lastParamState));
                }
            }

        },
        loadParamInfo: function(paramData){
            for(var name in paramData){
                var data = paramData[name];
                var sourceName = "_" + name + "__source";
                this.paramForm.elements[name].value = data.type;
                this.paramForm.elements[sourceName].value = data.source;
            }
        },

        updateOutput: function(){
            var contextData = {
                "global.shade" : [
                    {
                      "extra": {
                          "type": "object",
                          "kind": "any",
                          "global" : true,
                          "info" : {}
                      }
                    }
                ]
            }
            var paramState = {};
            for(var i = 0; i < this.paramList.length; ++i){
                var name = this.paramList[i], sourceName = "_" + name + "__source";
                var selection = {
                    type: this.paramForm.elements[name].value,
                    source: this.paramForm.elements[sourceName].value
                };
                paramState[name] = selection;

                var dest = contextData["global.shade"][0].extra.info[name] = {};
                var typeData = TYPE_LIST[selection.type];

                for(var j in typeData){
                    dest[j] = typeData[j];
                }
                dest["source"] = SOURCE_MAP[selection.source];
            }
            this.storage.lastParamState = JSON.stringify(paramState);
            var code = this.javaScriptEditor.getValue();

            var aast = Shade.parseAndInferenceExpression(code, { inject: contextData, loc: true });
            var result = Shade.compileFragmentShader(aast);

            this.codeViewer.setValue(result);
            this.compileGL();
        },
        addConsoleText: function(text, error){
            var lastElement = this.console.find("li:last-child");
            var lastText = lastElement.find(".text").text();
            if(text == lastText){
                var counter = lastElement.find(".counter");
                if(counter.length){
                    var newCount = counter.text()*1 + 1;
                    counter.text(newCount);
                }
                else{
                    lastElement.append($('2'));
                }
                return;
            }
            var entry = $('
'+ text + '
');
            if(error) entry.addClass("error");
            this.console.append(entry);
            this.console[0].scrollTop = this.console[0].scrollHeight;
        },
        initGL: function () {
            var gl = this.gl;
            var ext = gl.getExtension('OES_standard_derivatives');
            if (!ext)
                this.addConsoleText("Standard derivates are not supported on your graphics card");
        },
        compileGL: function() {
            var fragmentSource = this.codeViewer.getValue();
            if(!this.gl)
                return;
            var info = this.compileShader(this.gl.FRAGMENT_SHADER, fragmentSource);
            if (info.error) {
                this.addConsoleText(info.error, true);
            } else {
                this.addConsoleText("GLSL: Compiled fragment shader successfully");
                this.render(info.shader);
            }
        },
        compileShader: function(kind, source) {
            var gl = this.gl;
            var shader = gl.createShader(kind);
            gl.shaderSource(shader, source);
            gl.compileShader(shader);

            if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) == 0) {
                var errorString = "Failed to compile: ";
                errorString += gl.getShaderInfoLog(shader);
                gl.getError();
                return { error: errorString };
            } else {
                return { shader: shader };
            }
        },
        render : function(fragmentShader) {
            var gl = this.gl;
            var canvasWidth = $(".theCanvas")[0].width = $(".theCanvas")[0].clientWidth,
                canvasHeight = $(".theCanvas")[0].height = $(".theCanvas")[0].clientHeight;
            gl.viewport( 0, 0, canvasWidth, canvasHeight );
            var vertex = this.compileShader(gl.VERTEX_SHADER, ["attribute vec2 a_position;","void main() { gl_Position = vec4(a_position, 0, 1); }"].join("\n"));
            if(vertex.error)
                return;

            var program = gl.createProgram();
            gl.attachShader(program, fragmentShader);
            gl.attachShader(program, vertex.shader);
            gl.linkProgram(program);
            if (gl.getProgramParameter(program, gl.LINK_STATUS) == 0) {
                var errorString = "Shader linking failed: \n";
                errorString += gl.getProgramInfoLog(program);
                gl.getError();
                this.addConsoleText(errorString, true);
                return;
            }
            gl.useProgram(program);
            // Set system parameters

            var location;
            location = gl.getUniformLocation(program, "_sys_height"); location && gl.uniform1f(location, canvasHeight);
            location = gl.getUniformLocation(program, "_sys_width"); location && gl.uniform1f(location, canvasWidth);
            location = gl.getUniformLocation(program, "_sys_coords"); location && gl.uniform3f(location, canvasWidth, canvasHeight, 1.0);

            var positionLocation = gl.getAttribLocation(program, "a_position");
            var buffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1.0, -1.0,1.0, -1.0,-1.0,  1.0,-1.0,  1.0,1.0, -1.0,1.0,  1.0]), gl.STATIC_DRAW);
            gl.enableVertexAttribArray(positionLocation);
            gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
            gl.drawArrays(gl.TRIANGLES, 0, 6);
        }
    }

    function createParamSelect(selectName, selectedValue, sourceValue){
        var listEntry = $('
' + selectName +'
');

        var select = $("<select></select>");
        for(var name in TYPE_LIST){
            select.append($("<option>" + name + "</option>"));
        }
        select[0].name = selectName;
        select[0].value = selectedValue || "UNDEFINED";
        select.change(function(){
            ns.ShadeStudio.onEdit();
        });
        listEntry.append(select);

        var sourceButton = $('<input class="sourceButton" type="button" name="_' + selectName + '__source" />');
        sourceButton[0].value = sourceValue || SOURCE_LIST[0];
        sourceButton.click(function(){
            var idx = SOURCE_LIST.indexOf(this.value);
            if(idx == -1 || idx == SOURCE_LIST.length - 1)
                this.value = SOURCE_LIST[0];
            else
                this.value = SOURCE_LIST[idx + 1];
            ns.ShadeStudio.onEdit();
        });
        listEntry.append(sourceButton);

        return listEntry;
    }

    function initTypeList(){
        for(var name in Shade.TYPES){
            if(name != "OBJECT"){
                TYPE_LIST[name] = { type: Shade.TYPES[name], kind: undefined};
            }
        }
        for(var name in Shade.OBJECT_KINDS){
            var objName = "OBJECT_" + name;
            TYPE_LIST[objName] = { type: Shade.TYPES.OBJECT, kind: Shade.OBJECT_KINDS[name]};
        }
        for(var name in Shade.SOURCES){
            var key = name.charAt(0).toUpperCase();
            SOURCE_MAP[key] = Shade.SOURCES[name];
            SOURCE_LIST.push(key);
        }
    }

    function storageSupported() {
        try {
            return 'localStorage' in ns && ns['localStorage'] !== null;
        } catch (e) {
            return false;
        }
    }

    ns.ShadeStudio = new ShadeStudio();

}(window));
<commit_msg>Studio: Animated time parameter<commit_after>(function (ns) {

    var TYPE_LIST = {};

    var SOURCE_MAP = {},
        SOURCE_LIST = []

    var ShadeStudio = function() {
        this.paramList = [];
        this.paramForm = null;
        this.console = null;
        this.lastErrorLocation = null;
        this.storage = storageSupported() ? ns.localStorage : {};
        this.paramStateLoaded = false;
    };

    ShadeStudio.prototype = {
        init: function() {
            initTypeList();
            this.javaScriptEditor = CodeMirror.fromTextArea(document.querySelector("textarea"), {
                mode: "javascript",
                lineNumbers: true

            });
            this.javaScriptEditor.on("change", this.onEdit.bind(this));
            this.codeViewer = CodeMirror(document.querySelector(".codeOutput"), {
                value: "",
                mode:  "x-shader/x-fragment",
                lineNumbers: true
            });
            this.codeViewer.on("change", this.compileGL.bind(this));

            this.paramForm = document.getElementById("paramList");
            this.console = $("#console");

            if (this.storage.lastShaderCode !== undefined) {
                this.javaScriptEditor.setValue(this.storage.lastShaderCode);
            };
            try {
                this.gl = $(".theCanvas")[0].getContext("experimental-webgl");
                this.initGL();
                $(".theCanvas").mouseenter(this.setAnimate.bind(this, true))
                               .mouseleave(this.setAnimate.bind(this, false));
            } catch(e) {
                this.addConsoleText(e.toString(), true);
                this.gl = null;
            }

        },
        onEdit: function(instance, obj) {
            var newValue = this.javaScriptEditor.getValue();
            var codeCorrect = false;
            this.storage.lastShaderCode = newValue;
            if(this.lastErrorLocation && this.lastErrorLocation.start.line){
                this.javaScriptEditor.removeLineClass(this.lastErrorLocation.start.line -1, 'background', 'line-error');
                this.lastErrorLocation = null;
            }
            $("#main").removeClass("error");
            $("#main").removeClass("codeError");
            try {
                var params = Shade.extractParameters(newValue);
                console.log(params);
                codeCorrect = true;
                this.updateParameterSelection(params);
                this.updateOutput();

            } catch (e) {
                console.log(e.toString());
                console.log(e.loc);
                $("#main").addClass("error");
                if(!codeCorrect) $("#main").addClass("codeError");
                var errorLocation = e.loc || { start: { line: e.lineNumber }};
                this.lastErrorLocation = errorLocation;
                if(errorLocation.start.line)
                    this.javaScriptEditor.addLineClass(errorLocation.start.line - 1, 'background', 'line-error');
                //this.javaScriptEditor.setLineClass(lineNumber, 'background', 'line-error');
                this.addConsoleText(e.toString(), true)
            }
        },
        updateParameterSelection: function(params){
            if(this.paramList.join("j") == params.join(";"))
                return;
            this.paramList = params;

            var newSelects = {};
            for(var i = 0; i < params.length; ++i){
                var paramName = params[i], sourceName = "_" + paramName + "__source";
                var oldField = this.paramForm.elements[paramName],
                    oldSourceField = this.paramForm.elements[sourceName];
                newSelects[paramName] = createParamSelect(paramName,
                    oldField && oldField.value, oldSourceField && oldSourceField.value);
            }
            var list = $("#inputList");
            list.empty();
            for(var name in newSelects){
                list.append(newSelects[name]);
            }
            if(!this.paramStateLoaded){
                this.paramStateLoaded = true;
                if(this.storage.lastParamState){
                    this.loadParamInfo(JSON.parse(this.storage.lastParamState));
                }
            }

        },
        loadParamInfo: function(paramData){
            for(var name in paramData){
                var data = paramData[name];
                var sourceName = "_" + name + "__source";
                this.paramForm.elements[name].value = data.type;
                this.paramForm.elements[sourceName].value = data.source;
            }
        },

        updateOutput: function(){
            var contextData = {
                "global.shade" : [
                    {
                      "extra": {
                          "type": "object",
                          "kind": "any",
                          "global" : true,
                          "info" : {}
                      }
                    }
                ]
            }
            var paramState = {};
            for(var i = 0; i < this.paramList.length; ++i){
                var name = this.paramList[i], sourceName = "_" + name + "__source";
                var selection = {
                    type: this.paramForm.elements[name].value,
                    source: this.paramForm.elements[sourceName].value
                };
                paramState[name] = selection;

                var dest = contextData["global.shade"][0].extra.info[name] = {};
                var typeData = TYPE_LIST[selection.type];

                for(var j in typeData){
                    dest[j] = typeData[j];
                }
                dest["source"] = SOURCE_MAP[selection.source];
            }
            this.storage.lastParamState = JSON.stringify(paramState);
            var code = this.javaScriptEditor.getValue();

            var aast = Shade.parseAndInferenceExpression(code, { inject: contextData, loc: true });
            var result = Shade.compileFragmentShader(aast);

            this.codeViewer.setValue(result);
            this.compileGL();
        },
        addConsoleText: function(text, error){
            var lastElement = this.console.find("li:last-child");
            var lastText = lastElement.find(".text").text();
            if(text == lastText){
                var counter = lastElement.find(".counter");
                if(counter.length){
                    var newCount = counter.text()*1 + 1;
                    counter.text(newCount);
                }
                else{
                    lastElement.append($('2'));
                }
                return;
            }
            var entry = $('
'+ text + '
');
            if(error) entry.addClass("error");
            this.console.append(entry);
            this.console[0].scrollTop = this.console[0].scrollHeight;
        },
        initGL: function () {
            var gl = this.gl;
            var ext = gl.getExtension('OES_standard_derivatives');
            if (!ext)
                this.addConsoleText("Standard derivates are not supported on your graphics card");

            this.quad = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, this.quad);
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1.0, -1.0,1.0, -1.0,-1.0,  1.0,-1.0,  1.0,1.0, -1.0,1.0,  1.0]), gl.STATIC_DRAW);
        },
        compileGL: function() {
            var fragmentSource = this.codeViewer.getValue();
            if(!this.gl)
                return;
            var info = this.compileShader(this.gl.FRAGMENT_SHADER, fragmentSource);
            if (info.error) {
                this.addConsoleText(info.error, true);
            } else {
                this.addConsoleText("GLSL: Compiled fragment shader successfully");
                this.compileProgram(info.shader);
                this.renderFrame();
            }
        },
        compileShader: function(kind, source) {
            var gl = this.gl;
            var shader = gl.createShader(kind);
            gl.shaderSource(shader, source);
            gl.compileShader(shader);

            if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) == 0) {
                var errorString = "Failed to compile: ";
                errorString += gl.getShaderInfoLog(shader);
                gl.getError();
                return { error: errorString };
            } else {
                return { shader: shader };
            }
        },
        compileProgram : function(fragmentShader) {
            var gl = this.gl;
            this.program = null;

            var canvasWidth = $(".theCanvas")[0].width = $(".theCanvas")[0].clientWidth,
                canvasHeight = $(".theCanvas")[0].height = $(".theCanvas")[0].clientHeight;

            gl.viewport( 0, 0, canvasWidth, canvasHeight );
            var vertex = this.compileShader(gl.VERTEX_SHADER, ["attribute vec2 a_position;","void main() { gl_Position = vec4(a_position, 0, 1); }"].join("\n"));
            if(vertex.error)
                return;

            var program = gl.createProgram();
            gl.attachShader(program, fragmentShader);
            gl.attachShader(program, vertex.shader);
            gl.linkProgram(program);
            if (gl.getProgramParameter(program, gl.LINK_STATUS) == 0) {
                var errorString = "Shader linking failed: \n";
                errorString += gl.getProgramInfoLog(program);
                gl.getError();
                this.addConsoleText(errorString, true);
                return;
            }
            this.program = program;
            gl.useProgram(program);
            // Set system parameters

            var location;
            location = gl.getUniformLocation(program, "_sys_height"); location && gl.uniform1f(location, canvasHeight);
            location = gl.getUniformLocation(program, "_sys_width"); location && gl.uniform1f(location, canvasWidth);
            location = gl.getUniformLocation(program, "_sys_coords"); location && gl.uniform3f(location, canvasWidth, canvasHeight, 1.0);
        },
        renderFrame: function(time) {
            var gl = this.gl;
            var program = this.program;
            if (!(gl && program))
                return;

            time = time || 0;

            gl.useProgram(program);

            var location;
            location = gl.getUniformLocation(program, "_env_time"); location && gl.uniform1f(location, time);

            var positionLocation = gl.getAttribLocation(program, "a_position");
            gl.bindBuffer(gl.ARRAY_BUFFER, this.quad);
            gl.enableVertexAttribArray(positionLocation);
            gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
            gl.drawArrays(gl.TRIANGLES, 0, 6);
        },
        setAnimate: function(start) {
            this.animStatus = start;
            if (start) {
                this.startTime = Date.now();
                this.tick();
            }
        },
        tick: function() {
            var time = Date.now();
            this.renderFrame((time - this.startTime) / 1000.0);
            if (this.animStatus == true) {
                window.requestAnimationFrame(this.tick.bind(this));
            }
        }
    }

    function createParamSelect(selectName, selectedValue, sourceValue){
        var listEntry = $('
' + selectName +'
');

        var select = $("<select></select>");
        for(var name in TYPE_LIST){
            select.append($("<option>" + name + "</option>"));
        }
        select[0].name = selectName;
        select[0].value = selectedValue || "UNDEFINED";
        select.change(function(){
            ns.ShadeStudio.onEdit();
        });
        listEntry.append(select);

        var sourceButton = $('<input class="sourceButton" type="button" name="_' + selectName + '__source" />');
        sourceButton[0].value = sourceValue || SOURCE_LIST[0];
        sourceButton.click(function(){
            var idx = SOURCE_LIST.indexOf(this.value);
            if(idx == -1 || idx == SOURCE_LIST.length - 1)
                this.value = SOURCE_LIST[0];
            else
                this.value = SOURCE_LIST[idx + 1];
            ns.ShadeStudio.onEdit();
        });
        listEntry.append(sourceButton);

        return listEntry;
    }

    function initTypeList(){
        for(var name in Shade.TYPES){
            if(name != "OBJECT"){
                TYPE_LIST[name] = { type: Shade.TYPES[name], kind: undefined};
            }
        }
        for(var name in Shade.OBJECT_KINDS){
            var objName = "OBJECT_" + name;
            TYPE_LIST[objName] = { type: Shade.TYPES.OBJECT, kind: Shade.OBJECT_KINDS[name]};
        }
        for(var name in Shade.SOURCES){
            var key = name.charAt(0).toUpperCase();
            SOURCE_MAP[key] = Shade.SOURCES[name];
            SOURCE_LIST.push(key);
        }
    }

    function storageSupported() {
        try {
            return 'localStorage' in ns && ns['localStorage'] !== null;
        } catch (e) {
            return false;
        }
    }

    ns.ShadeStudio = new ShadeStudio();

}(window));
<|endoftext|>


<commit_before>'use strict';

import GoResultsHighlighter from './lib/wrapper';
import { asArray } from './lib/utils';
import './styles/bookmark.less';

// exactly one result per row is allowed
const CELL_RESULT_REGEXP = /^[^0-9]*([0-9]+[-+=?])[^-+?]*$/;
const RESULT_REGEXP = /[0-9]+[-+?]/g;

/**
 * Applies highlighter to all elements matching given selector if they look like Go results.
 *
 * @param {string} selector - CSS-like selector
 * @param {HighlighterSettings} settings - highlighter settings
 * @param {boolean} [force=false] - whether the check for results should be ignored
 */
function applyHighlighter(selector, settings, force) {
    const elementsWithGoResults = asArray(document.querySelectorAll(selector))
        .filter(/** Element */ element => {

            if (force) {
                return true;
            }

            // table element will be treated as results if any of its cells contain SINGLE result
            // string.
            if (element.nodeName === 'TABLE') {
                const rowsCount = element.rows.length;

                for (let i = 0; i < rowsCount; i++) {
                    const cellsCount = element.rows[i].cells.length;

                    for (let j = 0; j < cellsCount; j++) {
                        console.log(element.rows[i].cells[j].textContent, CELL_RESULT_REGEXP.test(element.rows[i].cells[j].textContent));
                        if (CELL_RESULT_REGEXP.test(element.rows[i].cells[j].textContent)) {
                            return true;
                        }
                    }
                }

                return false;
            }

            // other element will be treated as results if it contains at least 6 Go results strings.
            const foundGoResults = element.textContent.match(RESULT_REGEXP);

            // why 6? I assume a tournament with at least 3 participants and 2 rounds.
            return foundGoResults && foundGoResults.length > 6;
        });

    if (!elementsWithGoResults.length) {
        let newSelector;

        // if force flag is set it means that user has tried to provide any selector
        if (force) {
            newSelector = prompt(`Could not find any elements matching "${selector}" selector. Do you want to provide another one?`);
        } else {
            newSelector = prompt(`Could not find any tables with Go results ("${selector}"). If you are confident that this page has one - please provide a specific selector to the element.`);
        }

        if (newSelector) {
            applyHighlighter(newSelector, settings, true);
        } else {
            console.log('Could not find any elements with Go results.');
        }

        return;
    }

    let appliedCount = 0;
    let skippedCount = 0;

    elementsWithGoResults
        .forEach(element => {
            if (element.goResultsHighlighter) {
                skippedCount += 1;
                return;
            }

            new GoResultsHighlighter(element, settings);
            appliedCount += 1;
        });

    console.log(`Go Results Highlighter was applied to ${appliedCount} DOM elements. ${skippedCount} had Highlighter before.`);
}

if (location.hostname.indexOf('europeangodatabase') !== -1) {
    applyHighlighter('#tab_wallist', { placeColumn: 1 });
} else {
    applyHighlighter('table, pre');
}<commit_msg>Removed superfluous console<commit_after>'use strict';

import GoResultsHighlighter from './lib/wrapper';
import { asArray } from './lib/utils';
import './styles/bookmark.less';

// exactly one result per row is allowed
const CELL_RESULT_REGEXP = /^[^0-9]*([0-9]+[-+=?])[^-+?]*$/;
const RESULT_REGEXP = /[0-9]+[-+?]/g;

/**
 * Applies highlighter to all elements matching given selector if they look like Go results.
 *
 * @param {string} selector - CSS-like selector
 * @param {HighlighterSettings} settings - highlighter settings
 * @param {boolean} [force=false] - whether the check for results should be ignored
 */
function applyHighlighter(selector, settings, force) {
    const elementsWithGoResults = asArray(document.querySelectorAll(selector))
        .filter(/** Element */ element => {

            if (force) {
                return true;
            }

            // table element will be treated as results if any of its cells contain SINGLE result
            // string.
            if (element.nodeName === 'TABLE') {
                const rowsCount = element.rows.length;

                for (let i = 0; i < rowsCount; i++) {
                    const cellsCount = element.rows[i].cells.length;

                    for (let j = 0; j < cellsCount; j++) {
                        if (CELL_RESULT_REGEXP.test(element.rows[i].cells[j].textContent)) {
                            return true;
                        }
                    }
                }

                return false;
            }

            // other element will be treated as results if it contains at least 6 Go results strings.
            const foundGoResults = element.textContent.match(RESULT_REGEXP);

            // why 6? I assume a tournament with at least 3 participants and 2 rounds.
            return foundGoResults && foundGoResults.length > 6;
        });

    if (!elementsWithGoResults.length) {
        let newSelector;

        // if force flag is set it means that user has tried to provide any selector
        if (force) {
            newSelector = prompt(`Could not find any elements matching "${selector}" selector. Do you want to provide another one?`);
        } else {
            newSelector = prompt(`Could not find any tables with Go results ("${selector}"). If you are confident that this page has one - please provide a specific selector to the element.`);
        }

        if (newSelector) {
            applyHighlighter(newSelector, settings, true);
        } else {
            console.log('Could not find any elements with Go results.');
        }

        return;
    }

    let appliedCount = 0;
    let skippedCount = 0;

    elementsWithGoResults
        .forEach(element => {
            if (element.goResultsHighlighter) {
                skippedCount += 1;
                return;
            }

            new GoResultsHighlighter(element, settings);
            appliedCount += 1;
        });

    console.log(`Go Results Highlighter was applied to ${appliedCount} DOM elements. ${skippedCount} had Highlighter before.`);
}

if (location.hostname.indexOf('europeangodatabase') !== -1) {
    applyHighlighter('#tab_wallist', { placeColumn: 1 });
} else {
    applyHighlighter('table, pre');
}<|endoftext|>


<commit_before>import stringify from 'json-stringify-safe';
import v4 from 'uuid';
import { fork } from 'node-debug-helper';
import _debug from 'debug';

const debug = _debug('fastboot-pool');

let count = 0;

export default function init({
  fastbootFilename,
  requestCountUntilFork
}) {
  let fb1Promise = init();
  let fb2Promise = init();

  let resetCount = 0;

  let responseLookup = {};

  let waitingResponse = [];

  function swap() {
    let wait = waitAndKill(waitingResponse);

    let promise = fb1Promise.then(fb1 => {
      return init().then(fb2 => {
        return wait(fb1).then(() => {
          return fb2;
        });
      });
    });

    fb1Promise = fb2Promise;

    fb2Promise = promise;

    waitingResponse = [];
  }

  function waitAndKill(waitingResponse) {
    return fb => {
      return Promise.all(waitingResponse).then(() => {
        debug(fb.pid + ' waskilled');
        fb.kill('SIGINT');
      });
    };
  }

  function init() {
    return new Promise(resolve2 => {
      let fb = fork(`${__dirname}/fork.js`, ['--filename=' + fastbootFilename]);

      fb.on('exit', (code, signal) => {
        if (code === 1) {
          throw new Error(`Failed to run your fastboot file. Code ${code} signal ${signal}`);
        }
      });

      fb.on('message', ({
        message,
        key,
        body
      }) => {
        let resolve;
        let reject;
        if (responseLookup[key]) {
          resolve = responseLookup[key].resolve;
          reject = responseLookup[key].reject;
        }
        switch (message) {
          case 'waiting':
            debug(body + ' iswaiting');

            resolve2(fb);
            break;
          case 'renderComplete':
            delete responseLookup[key];

            resolve(body.html);

            debug(fb.pid + ' wasrendered ' + body.requestNumber + ' currentcount ' + --count);

            break;
          case 'error':
            delete responseLookup[key];

            reject(body);

            break;
        }
      });
    });
  }

  return function render(message) {
    count++;
    let promise;
    if (++resetCount === requestCountUntilFork) {
      promise = fb2Promise;
      swap();
      resetCount = 1;
    } else {
      promise = fb1Promise;
    }
    let requestNumber = resetCount;
    promise = promise.then(function(fb) {
      let key = v4();
      return new Promise((resolve, reject) => {
        responseLookup[key] = {
          resolve,
          reject
        };

        fb.send({
          message: stringify(message),
          key,
          requestNumber
        });
      });
    });

    waitingResponse.push(promise);

    return promise;
  };
}
<commit_msg>fix double error<commit_after>import stringify from 'json-stringify-safe';
import v4 from 'uuid';
import { fork } from 'node-debug-helper';
import _debug from 'debug';

const debug = _debug('fastboot-pool');

let count = 0;

export default function init({
  fastbootFilename,
  requestCountUntilFork
}) {
  let fb1Promise = init();

  // wait for the first one to finish in case it fails to init fastboot
  // to prevent doubled error message
  let fb2Promise = fb1Promise.then(init);

  let resetCount = 0;

  let responseLookup = {};

  let waitingResponse = [];

  function swap() {
    let wait = waitAndKill(waitingResponse);

    let promise = fb1Promise.then(fb1 => {
      return init().then(fb2 => {
        return wait(fb1).then(() => {
          return fb2;
        });
      });
    });

    fb1Promise = fb2Promise;

    fb2Promise = promise;

    waitingResponse = [];
  }

  function waitAndKill(waitingResponse) {
    return fb => {
      return Promise.all(waitingResponse).then(() => {
        debug(fb.pid + ' waskilled');
        fb.kill('SIGINT');
      });
    };
  }

  function init() {
    return new Promise(resolve2 => {
      let fb = fork(`${__dirname}/fork.js`, ['--filename=' + fastbootFilename]);

      fb.on('exit', (code, signal) => {
        if (code === 1) {
          throw new Error(`Failed to run your fastboot file. Code ${code} signal ${signal}`);
        }
      });

      fb.on('message', ({
        message,
        key,
        body
      }) => {
        let resolve;
        let reject;
        if (responseLookup[key]) {
          resolve = responseLookup[key].resolve;
          reject = responseLookup[key].reject;
        }
        switch (message) {
          case 'waiting':
            debug(body + ' iswaiting');

            resolve2(fb);
            break;
          case 'renderComplete':
            delete responseLookup[key];

            resolve(body.html);

            debug(fb.pid + ' wasrendered ' + body.requestNumber + ' currentcount ' + --count);

            break;
          case 'error':
            delete responseLookup[key];

            reject(body);

            break;
        }
      });
    });
  }

  return function render(message) {
    count++;
    let promise;
    if (++resetCount === requestCountUntilFork) {
      promise = fb2Promise;
      swap();
      resetCount = 1;
    } else {
      promise = fb1Promise;
    }
    let requestNumber = resetCount;
    promise = promise.then(function(fb) {
      let key = v4();
      return new Promise((resolve, reject) => {
        responseLookup[key] = {
          resolve,
          reject
        };

        fb.send({
          message: stringify(message),
          key,
          requestNumber
        });
      });
    });

    waitingResponse.push(promise);

    return promise;
  };
}
<|endoftext|>