<commit_before>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
var OptionsApply = require("./OptionsApply");

var LoaderTargetPlugin = require("./LoaderTargetPlugin");
var FunctionModulePlugin = require("./FunctionModulePlugin");
var EvalDevToolModulePlugin = require("./EvalDevToolModulePlugin");
var SourceMapDevToolPlugin = require("./SourceMapDevToolPlugin");
var EvalSourceMapDevToolPlugin = require("./EvalSourceMapDevToolPlugin");

var EntryOptionPlugin = require("./EntryOptionPlugin");
var RecordIdsPlugin = require("./RecordIdsPlugin");

var APIPlugin = require("./APIPlugin");
var ConstPlugin = require("./ConstPlugin");
var RequireJsStuffPlugin = require("./RequireJsStuffPlugin");
var NodeStuffPlugin = require("./NodeStuffPlugin");
var CompatibilityPlugin = require("./CompatibilityPlugin");
var DefinePlugin = require("./DefinePlugin");

var MovedToPluginWarningPlugin = require("./MovedToPluginWarningPlugin");
var TemplatedPathPlugin = require("./TemplatedPathPlugin");
var WarnCaseSensitiveModulesPlugin = require("./WarnCaseSensitiveModulesPlugin");

var LoaderPlugin = require("./dependencies/LoaderPlugin");
var CommonJsPlugin = require("./dependencies/CommonJsPlugin");
var AMDPlugin = require("./dependencies/AMDPlugin");
var RequireContextPlugin = require("./dependencies/RequireContextPlugin");
var RequireEnsurePlugin = require("./dependencies/RequireEnsurePlugin");
var RequireIncludePlugin = require("./dependencies/RequireIncludePlugin");

var RemoveParentModulesPlugin = require("./optimize/RemoveParentModulesPlugin");
var RemoveEmptyChunksPlugin = require("./optimize/RemoveEmptyChunksPlugin");
var MergeDuplicateChunksPlugin = require("./optimize/MergeDuplicateChunksPlugin");
var FlagIncludedChunksPlugin = require("./optimize/FlagIncludedChunksPlugin");

var UnsafeCachePlugin = require("enhanced-resolve/lib/UnsafeCachePlugin");
var ModulesInDirectoriesPlugin = require("enhanced-resolve/lib/ModulesInDirectoriesPlugin");
var ModulesInRootPlugin = require("enhanced-resolve/lib/ModulesInRootPlugin");
var ModuleTemplatesPlugin = require("enhanced-resolve/lib/ModuleTemplatesPlugin");
var ModuleAsFilePlugin = require("enhanced-resolve/lib/ModuleAsFilePlugin");
var ModuleAsDirectoryPlugin = require("enhanced-resolve/lib/ModuleAsDirectoryPlugin");
var ModuleAliasPlugin = require("enhanced-resolve/lib/ModuleAliasPlugin");
var DirectoryDefaultFilePlugin = require("enhanced-resolve/lib/DirectoryDefaultFilePlugin");
var DirectoryDescriptionFilePlugin = require("enhanced-resolve/lib/DirectoryDescriptionFilePlugin");
var DirectoryDescriptionFileFieldAliasPlugin = require("enhanced-resolve/lib/DirectoryDescriptionFileFieldAliasPlugin");
var FileAppendPlugin = require("enhanced-resolve/lib/FileAppendPlugin");
var DirectoryResultPlugin = require("enhanced-resolve/lib/DirectoryResultPlugin");
var ResultSymlinkPlugin = require("enhanced-resolve/lib/ResultSymlinkPlugin");

function WebpackOptionsApply() {
	OptionsApply.call(this);
}
module.exports = WebpackOptionsApply;

WebpackOptionsApply.prototype = Object.create(OptionsApply.prototype);
WebpackOptionsApply.prototype.process = function(options, compiler) {
	compiler.context = options.context;
	if(options.plugins && Array.isArray(options.plugins)) {
		compiler.apply.apply(compiler, options.plugins);
	}
	compiler.outputPath = options.output.path;
	compiler.recordsInputPath = options.recordsInputPath || options.recordsPath;
	compiler.recordsOutputPath = options.recordsOutputPath || options.recordsPath;
	compiler.name = options.name;
	if(typeof options.target === "string") {
		switch(options.target) {
			case "web":
				var JsonpTemplatePlugin = require("./JsonpTemplatePlugin");
				var NodeSourcePlugin = require("./node/NodeSourcePlugin");
				compiler.apply(
					new JsonpTemplatePlugin(options.output),
					new FunctionModulePlugin(options.output),
					new NodeSourcePlugin(options.node),
					new LoaderTargetPlugin("web")
				);
				break;
			case "webworker":
				var WebWorkerTemplatePlugin = require("./webworker/WebWorkerTemplatePlugin");
				var NodeSourcePlugin = require("./node/NodeSourcePlugin");
				compiler.apply(
					new WebWorkerTemplatePlugin(options.output),
					new FunctionModulePlugin(options.output),
					new NodeSourcePlugin(options.node),
					new LoaderTargetPlugin("webworker")
				);
				break;
			case "node":
			case "async-node":
				var NodeTemplatePlugin = require("./node/NodeTemplatePlugin");
				var NodeTargetPlugin = require("./node/NodeTargetPlugin");
				compiler.apply(
					new NodeTemplatePlugin(options.output, options.target === "async-node"),
					new FunctionModulePlugin(options.output),
					new NodeTargetPlugin(),
					new LoaderTargetPlugin("node")
				);
				break;
			case "node-webkit":
				var JsonpTemplatePlugin = require("./JsonpTemplatePlugin");
				var NodeTargetPlugin = require("./node/NodeTargetPlugin");
				var ExternalsPlugin = require("./ExternalsPlugin");
				compiler.apply(
					new JsonpTemplatePlugin(options.output),
					new FunctionModulePlugin(options.output),
					new NodeTargetPlugin(),
					new ExternalsPlugin("commonjs", "nw.gui"),
					new LoaderTargetPlugin("node-webkit")
				);
				break;
			case "atom":
			case "electron":
				var NodeTemplatePlugin = require("./node/NodeTemplatePlugin");
				var NodeTargetPlugin = require("./node/NodeTargetPlugin");
				var ExternalsPlugin = require("./ExternalsPlugin");
				compiler.apply(
					new NodeTemplatePlugin(options.output, true),
					new FunctionModulePlugin(options.output),
					new NodeTargetPlugin(),
					new ExternalsPlugin("commonjs", [
						"app",
						"auto-updater",
						"browser-window",
						"content-tracing",
						"dialog",
						"global-shortcut",
						"ipc",
						"menu",
						"menu-item",
						"power-monitor",
						"protocol",
						"tray",
						"remote",
						"web-view",
						"clipboard",
						"crash-reporter",
						"screen",
						"shell",
						"native-image"
					]),
					new LoaderTargetPlugin(options.target)
				);
				break;
			default:
				throw new Error("Unsupported target '" + options.target + "'.");
		}
	} else if(options.target !== false) {
		options.target(compiler);
	} else {
		throw new Error("Unsupported target '" + options.target + "'.");
	}
	if(options.output.library || options.output.libraryTarget !== "var") {
		var LibraryTemplatePlugin = require("./LibraryTemplatePlugin");
		compiler.apply(new LibraryTemplatePlugin(options.output.library, options.output.libraryTarget, options.output.umdNamedDefine));
	}
	if(options.externals) {
		var ExternalsPlugin = require("./ExternalsPlugin");
		compiler.apply(new ExternalsPlugin(options.output.libraryTarget, options.externals));
	}

	if(options.hot) {
		compiler.apply(new MovedToPluginWarningPlugin("hot", "HotModuleReplacementPlugin"));
		var HotModuleReplacementPlugin = require("./HotModuleReplacementPlugin");
		compiler.apply(new HotModuleReplacementPlugin(options.output));
	}

	if(options.devtool && (options.devtool.indexOf("sourcemap") >= 0 || options.devtool.indexOf("source-map") >= 0)) {
		var hidden = options.devtool.indexOf("hidden") >= 0;
		var inline = options.devtool.indexOf("inline") >= 0;
		var evalWrapped = options.devtool.indexOf("eval") >= 0;
		var cheap = options.devtool.indexOf("cheap") >= 0;
		var moduleMaps = options.devtool.indexOf("module") >= 0;
		var legacy = options.devtool.indexOf("@") >= 0;
		var modern = options.devtool.indexOf("#") >= 0;
		var comment = legacy && modern ? "\n/*\n//@ sourceMappingURL=[url]\n//# sourceMappingURL=[url]\n*/" :
			legacy ? "\n/*\n//@ sourceMappingURL=[url]\n*/" :
			modern ? "\n//# sourceMappingURL=[url]" :
			null;
		var Plugin = evalWrapped ? EvalSourceMapDevToolPlugin : SourceMapDevToolPlugin;
		compiler.apply(new Plugin({
			filename: inline ? null : options.output.sourceMapFilename,
			moduleFilenameTemplate: options.output.devtoolModuleFilenameTemplate,
			fallbackModuleFilenameTemplate: options.output.devtoolFallbackModuleFilenameTemplate,
			append: hidden ? false : comment,
			module: moduleMaps ? true : cheap ? false : true,
			columns: cheap ? false : true,
			lineToLine: options.output.devtoolLineToLine
		}));
	} else if(options.devtool && options.devtool.indexOf("eval") >= 0) {
		var legacy = options.devtool.indexOf("@") >= 0;
		var modern = options.devtool.indexOf("#") >= 0;
		var comment = legacy && modern ? "//@ sourceURL=[url]\n//# sourceURL=[url]" :
			legacy ? "//@ sourceURL=[url]" :
			modern ? "//# sourceURL=[url]" :
			null;
		compiler.apply(new EvalDevToolModulePlugin(comment, options.output.devtoolModuleFilenameTemplate));
	}

	compiler.apply(new EntryOptionPlugin());
	compiler.applyPluginsBailResult("entry-option", options.context, options.entry);

	if(options.prefetch) {
		compiler.apply(new MovedToPluginWarningPlugin("prefetch", "PrefetchPlugin"));
		var PrefetchPlugin = require("./PrefetchPlugin");
		options.prefetch.map(function(request) {
			compiler.apply(new PrefetchPlugin(options.context, request));
		});
	}
	compiler.apply(
		new CompatibilityPlugin(),
		new LoaderPlugin(),
		new NodeStuffPlugin(options.node),
		new RequireJsStuffPlugin(),
		new APIPlugin(),
		new ConstPlugin(),
		new RequireIncludePlugin(),
		new RequireEnsurePlugin(),
		new RequireContextPlugin(options.resolve.modulesDirectories, options.resolve.extensions),
		new AMDPlugin(options.module, options.amd || {}),
		new CommonJsPlugin(options.module)
	);

	compiler.apply(
		new RemoveParentModulesPlugin(),
		new RemoveEmptyChunksPlugin(),
		new MergeDuplicateChunksPlugin(),
		new FlagIncludedChunksPlugin()
	);

	compiler.apply(new TemplatedPathPlugin());

	compiler.apply(new RecordIdsPlugin());

	compiler.apply(new WarnCaseSensitiveModulesPlugin());

	if(options.optimize && options.optimize.occurenceOrder) {
		compiler.apply(new MovedToPluginWarningPlugin("optimize.occurenceOrder", "optimize.OccurrenceOrderPlugin"));
		var OccurrenceOrderPlugin = require("./optimize/OccurrenceOrderPlugin");
		compiler.apply(new OccurrenceOrderPlugin(options.optimize.occurenceOrderPreferEntry));
	}

	if(options.optimize && options.optimize.minChunkSize) {
		compiler.apply(new MovedToPluginWarningPlugin("optimize.minChunkSize", "optimize.MinChunkSizePlugin"));
		var MinChunkSizePlugin = require("./optimize/MinChunkSizePlugin");
		compiler.apply(new MinChunkSizePlugin(options.optimize));
	}

	if(options.optimize && options.optimize.maxChunks) {
		compiler.apply(new MovedToPluginWarningPlugin("optimize.maxChunks", "optimize.LimitChunkCountPlugin"));
		var LimitChunkCountPlugin = require("./optimize/LimitChunkCountPlugin");
		compiler.apply(new LimitChunkCountPlugin(options.optimize));
	}

	if(options.optimize.minimize) {
		compiler.apply(new MovedToPluginWarningPlugin("optimize.minimize", "optimize.UglifyJsPlugin"));
		var UglifyJsPlugin = require("./optimize/UglifyJsPlugin");
		if(options.optimize.minimize === true)
			compiler.apply(new UglifyJsPlugin());
		else
			compiler.apply(new UglifyJsPlugin(options.optimize.minimize));
	}

	if(options.cache === undefined ? options.watch : options.cache) {
		var CachePlugin = require("./CachePlugin");
		compiler.apply(new CachePlugin(typeof options.cache === "object" ? options.cache : null));
	}

	if(typeof options.provide === "object") {
		compiler.apply(new MovedToPluginWarningPlugin("provide", "ProvidePlugin"));
		var ProvidePlugin = require("./ProvidePlugin");
		compiler.apply(new ProvidePlugin(options.provide));
	}

	if(options.define) {
		compiler.apply(new MovedToPluginWarningPlugin("define", "DefinePlugin"));
		var defineObject = {};
		if(typeof options.define === "object") {
			Object.keys(options.define).forEach(function(key) {
				defineObject[key] = options.define[key];
			});
		}
		compiler.apply(new DefinePlugin(defineObject));
	}
	if(options.defineDebug !== false)
		compiler.apply(new DefinePlugin({
			DEBUG: !!options.debug
		}));

	compiler.applyPlugins("after-plugins", compiler);
	compiler.resolvers.normal.apply(
		new UnsafeCachePlugin(options.resolve.unsafeCache),
		options.resolve.packageAlias ? new DirectoryDescriptionFileFieldAliasPlugin("package.json", options.resolve.packageAlias) : function() {},
		new ModuleAliasPlugin(options.resolve.alias),
		makeRootPlugin("module", options.resolve.root),
		new ModulesInDirectoriesPlugin("module", options.resolve.modulesDirectories),
		makeRootPlugin("module", options.resolve.fallback),
		new ModuleAsFilePlugin("module"),
		new ModuleAsDirectoryPlugin("module"),
		new DirectoryDescriptionFilePlugin("package.json", options.resolve.packageMains),
		new DirectoryDefaultFilePlugin(["index"]),
		new FileAppendPlugin(options.resolve.extensions),
		new ResultSymlinkPlugin()
	);
	compiler.resolvers.context.apply(
		new UnsafeCachePlugin(options.resolve.unsafeCache),
		new ModuleAliasPlugin(options.resolve.alias),
		makeRootPlugin("module", options.resolve.root),
		new ModulesInDirectoriesPlugin("module", options.resolve.modulesDirectories),
		makeRootPlugin("module", options.resolve.fallback),
		new ModuleAsFilePlugin("module"),
		new ModuleAsDirectoryPlugin("module"),
		new DirectoryResultPlugin(),
		new ResultSymlinkPlugin()
	);
	compiler.resolvers.loader.apply(
		new UnsafeCachePlugin(options.resolve.unsafeCache),
		new ModuleAliasPlugin(options.resolveLoader.alias),
		makeRootPlugin("loader-module", options.resolveLoader.root),
		new ModulesInDirectoriesPlugin("loader-module", options.resolveLoader.modulesDirectories),
		makeRootPlugin("loader-module", options.resolveLoader.fallback),
		new ModuleTemplatesPlugin("loader-module", options.resolveLoader.moduleTemplates, "module"),
		new ModuleAsFilePlugin("module"),
		new ModuleAsDirectoryPlugin("module"),
		new DirectoryDescriptionFilePlugin("package.json", options.resolveLoader.packageMains),
		new DirectoryDefaultFilePlugin(["index"]),
		new FileAppendPlugin(options.resolveLoader.extensions),
		new ResultSymlinkPlugin()
	);
	compiler.applyPlugins("after-resolvers", compiler);
	return options;
};

function makeRootPlugin(name, root) {
	if(typeof root === "string")
		return new ModulesInRootPlugin(name, root);
	else if(Array.isArray(root)) {
		return function() {
			root.forEach(function(root) {
				this.apply(new ModulesInRootPlugin(name, root));
			}, this);
		};
	}
	return function() {};
}
<commit_msg>ignore electron as keyword in electron target<commit_after>/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/
var OptionsApply = require("./OptionsApply");

var LoaderTargetPlugin = require("./LoaderTargetPlugin");
var FunctionModulePlugin = require("./FunctionModulePlugin");
var EvalDevToolModulePlugin = require("./EvalDevToolModulePlugin");
var SourceMapDevToolPlugin = require("./SourceMapDevToolPlugin");
var EvalSourceMapDevToolPlugin = require("./EvalSourceMapDevToolPlugin");

var EntryOptionPlugin = require("./EntryOptionPlugin");
var RecordIdsPlugin = require("./RecordIdsPlugin");

var APIPlugin = require("./APIPlugin");
var ConstPlugin = require("./ConstPlugin");
var RequireJsStuffPlugin = require("./RequireJsStuffPlugin");
var NodeStuffPlugin = require("./NodeStuffPlugin");
var CompatibilityPlugin = require("./CompatibilityPlugin");
var DefinePlugin = require("./DefinePlugin");

var MovedToPluginWarningPlugin = require("./MovedToPluginWarningPlugin");
var TemplatedPathPlugin = require("./TemplatedPathPlugin");
var WarnCaseSensitiveModulesPlugin = require("./WarnCaseSensitiveModulesPlugin");

var LoaderPlugin = require("./dependencies/LoaderPlugin");
var CommonJsPlugin = require("./dependencies/CommonJsPlugin");
var AMDPlugin = require("./dependencies/AMDPlugin");
var RequireContextPlugin = require("./dependencies/RequireContextPlugin");
var RequireEnsurePlugin = require("./dependencies/RequireEnsurePlugin");
var RequireIncludePlugin = require("./dependencies/RequireIncludePlugin");

var RemoveParentModulesPlugin = require("./optimize/RemoveParentModulesPlugin");
var RemoveEmptyChunksPlugin = require("./optimize/RemoveEmptyChunksPlugin");
var MergeDuplicateChunksPlugin = require("./optimize/MergeDuplicateChunksPlugin");
var FlagIncludedChunksPlugin = require("./optimize/FlagIncludedChunksPlugin");

var UnsafeCachePlugin = require("enhanced-resolve/lib/UnsafeCachePlugin");
var ModulesInDirectoriesPlugin = require("enhanced-resolve/lib/ModulesInDirectoriesPlugin");
var ModulesInRootPlugin = require("enhanced-resolve/lib/ModulesInRootPlugin");
var ModuleTemplatesPlugin = require("enhanced-resolve/lib/ModuleTemplatesPlugin");
var ModuleAsFilePlugin = require("enhanced-resolve/lib/ModuleAsFilePlugin");
var ModuleAsDirectoryPlugin = require("enhanced-resolve/lib/ModuleAsDirectoryPlugin");
var ModuleAliasPlugin = require("enhanced-resolve/lib/ModuleAliasPlugin");
var DirectoryDefaultFilePlugin = require("enhanced-resolve/lib/DirectoryDefaultFilePlugin");
var DirectoryDescriptionFilePlugin = require("enhanced-resolve/lib/DirectoryDescriptionFilePlugin");
var DirectoryDescriptionFileFieldAliasPlugin = require("enhanced-resolve/lib/DirectoryDescriptionFileFieldAliasPlugin");
var FileAppendPlugin = require("enhanced-resolve/lib/FileAppendPlugin");
var DirectoryResultPlugin = require("enhanced-resolve/lib/DirectoryResultPlugin");
var ResultSymlinkPlugin = require("enhanced-resolve/lib/ResultSymlinkPlugin");

function WebpackOptionsApply() {
	OptionsApply.call(this);
}
module.exports = WebpackOptionsApply;

WebpackOptionsApply.prototype = Object.create(OptionsApply.prototype);
WebpackOptionsApply.prototype.process = function(options, compiler) {
	compiler.context = options.context;
	if(options.plugins && Array.isArray(options.plugins)) {
		compiler.apply.apply(compiler, options.plugins);
	}
	compiler.outputPath = options.output.path;
	compiler.recordsInputPath = options.recordsInputPath || options.recordsPath;
	compiler.recordsOutputPath = options.recordsOutputPath || options.recordsPath;
	compiler.name = options.name;
	if(typeof options.target === "string") {
		switch(options.target) {
			case "web":
				var JsonpTemplatePlugin = require("./JsonpTemplatePlugin");
				var NodeSourcePlugin = require("./node/NodeSourcePlugin");
				compiler.apply(
					new JsonpTemplatePlugin(options.output),
					new FunctionModulePlugin(options.output),
					new NodeSourcePlugin(options.node),
					new LoaderTargetPlugin("web")
				);
				break;
			case "webworker":
				var WebWorkerTemplatePlugin = require("./webworker/WebWorkerTemplatePlugin");
				var NodeSourcePlugin = require("./node/NodeSourcePlugin");
				compiler.apply(
					new WebWorkerTemplatePlugin(options.output),
					new FunctionModulePlugin(options.output),
					new NodeSourcePlugin(options.node),
					new LoaderTargetPlugin("webworker")
				);
				break;
			case "node":
			case "async-node":
				var NodeTemplatePlugin = require("./node/NodeTemplatePlugin");
				var NodeTargetPlugin = require("./node/NodeTargetPlugin");
				compiler.apply(
					new NodeTemplatePlugin(options.output, options.target === "async-node"),
					new FunctionModulePlugin(options.output),
					new NodeTargetPlugin(),
					new LoaderTargetPlugin("node")
				);
				break;
			case "node-webkit":
				var JsonpTemplatePlugin = require("./JsonpTemplatePlugin");
				var NodeTargetPlugin = require("./node/NodeTargetPlugin");
				var ExternalsPlugin = require("./ExternalsPlugin");
				compiler.apply(
					new JsonpTemplatePlugin(options.output),
					new FunctionModulePlugin(options.output),
					new NodeTargetPlugin(),
					new ExternalsPlugin("commonjs", "nw.gui"),
					new LoaderTargetPlugin("node-webkit")
				);
				break;
			case "atom":
			case "electron":
				var NodeTemplatePlugin = require("./node/NodeTemplatePlugin");
				var NodeTargetPlugin = require("./node/NodeTargetPlugin");
				var ExternalsPlugin = require("./ExternalsPlugin");
				compiler.apply(
					new NodeTemplatePlugin(options.output, true),
					new FunctionModulePlugin(options.output),
					new NodeTargetPlugin(),
					new ExternalsPlugin("commonjs", [
						"app",
						"auto-updater",
						"browser-window",
						"content-tracing",
						"dialog",
						"electron",
						"global-shortcut",
						"ipc",
						"menu",
						"menu-item",
						"power-monitor",
						"protocol",
						"tray",
						"remote",
						"web-view",
						"clipboard",
						"crash-reporter",
						"screen",
						"shell",
						"native-image"
					]),
					new LoaderTargetPlugin(options.target)
				);
				break;
			default:
				throw new Error("Unsupported target '" + options.target + "'.");
		}
	} else if(options.target !== false) {
		options.target(compiler);
	} else {
		throw new Error("Unsupported target '" + options.target + "'.");
	}
	if(options.output.library || options.output.libraryTarget !== "var") {
		var LibraryTemplatePlugin = require("./LibraryTemplatePlugin");
		compiler.apply(new LibraryTemplatePlugin(options.output.library, options.output.libraryTarget, options.output.umdNamedDefine));
	}
	if(options.externals) {
		var ExternalsPlugin = require("./ExternalsPlugin");
		compiler.apply(new ExternalsPlugin(options.output.libraryTarget, options.externals));
	}

	if(options.hot) {
		compiler.apply(new MovedToPluginWarningPlugin("hot", "HotModuleReplacementPlugin"));
		var HotModuleReplacementPlugin = require("./HotModuleReplacementPlugin");
		compiler.apply(new HotModuleReplacementPlugin(options.output));
	}

	if(options.devtool && (options.devtool.indexOf("sourcemap") >= 0 || options.devtool.indexOf("source-map") >= 0)) {
		var hidden = options.devtool.indexOf("hidden") >= 0;
		var inline = options.devtool.indexOf("inline") >= 0;
		var evalWrapped = options.devtool.indexOf("eval") >= 0;
		var cheap = options.devtool.indexOf("cheap") >= 0;
		var moduleMaps = options.devtool.indexOf("module") >= 0;
		var legacy = options.devtool.indexOf("@") >= 0;
		var modern = options.devtool.indexOf("#") >= 0;
		var comment = legacy && modern ? "\n/*\n//@ sourceMappingURL=[url]\n//# sourceMappingURL=[url]\n*/" :
			legacy ? "\n/*\n//@ sourceMappingURL=[url]\n*/" :
			modern ? "\n//# sourceMappingURL=[url]" :
			null;
		var Plugin = evalWrapped ? EvalSourceMapDevToolPlugin : SourceMapDevToolPlugin;
		compiler.apply(new Plugin({
			filename: inline ? null : options.output.sourceMapFilename,
			moduleFilenameTemplate: options.output.devtoolModuleFilenameTemplate,
			fallbackModuleFilenameTemplate: options.output.devtoolFallbackModuleFilenameTemplate,
			append: hidden ? false : comment,
			module: moduleMaps ? true : cheap ? false : true,
			columns: cheap ? false : true,
			lineToLine: options.output.devtoolLineToLine
		}));
	} else if(options.devtool && options.devtool.indexOf("eval") >= 0) {
		var legacy = options.devtool.indexOf("@") >= 0;
		var modern = options.devtool.indexOf("#") >= 0;
		var comment = legacy && modern ? "//@ sourceURL=[url]\n//# sourceURL=[url]" :
			legacy ? "//@ sourceURL=[url]" :
			modern ? "//# sourceURL=[url]" :
			null;
		compiler.apply(new EvalDevToolModulePlugin(comment, options.output.devtoolModuleFilenameTemplate));
	}

	compiler.apply(new EntryOptionPlugin());
	compiler.applyPluginsBailResult("entry-option", options.context, options.entry);

	if(options.prefetch) {
		compiler.apply(new MovedToPluginWarningPlugin("prefetch", "PrefetchPlugin"));
		var PrefetchPlugin = require("./PrefetchPlugin");
		options.prefetch.map(function(request) {
			compiler.apply(new PrefetchPlugin(options.context, request));
		});
	}
	compiler.apply(
		new CompatibilityPlugin(),
		new LoaderPlugin(),
		new NodeStuffPlugin(options.node),
		new RequireJsStuffPlugin(),
		new APIPlugin(),
		new ConstPlugin(),
		new RequireIncludePlugin(),
		new RequireEnsurePlugin(),
		new RequireContextPlugin(options.resolve.modulesDirectories, options.resolve.extensions),
		new AMDPlugin(options.module, options.amd || {}),
		new CommonJsPlugin(options.module)
	);

	compiler.apply(
		new RemoveParentModulesPlugin(),
		new RemoveEmptyChunksPlugin(),
		new MergeDuplicateChunksPlugin(),
		new FlagIncludedChunksPlugin()
	);

	compiler.apply(new TemplatedPathPlugin());

	compiler.apply(new RecordIdsPlugin());

	compiler.apply(new WarnCaseSensitiveModulesPlugin());

	if(options.optimize && options.optimize.occurenceOrder) {
		compiler.apply(new MovedToPluginWarningPlugin("optimize.occurenceOrder", "optimize.OccurrenceOrderPlugin"));
		var OccurrenceOrderPlugin = require("./optimize/OccurrenceOrderPlugin");
		compiler.apply(new OccurrenceOrderPlugin(options.optimize.occurenceOrderPreferEntry));
	}

	if(options.optimize && options.optimize.minChunkSize) {
		compiler.apply(new MovedToPluginWarningPlugin("optimize.minChunkSize", "optimize.MinChunkSizePlugin"));
		var MinChunkSizePlugin = require("./optimize/MinChunkSizePlugin");
		compiler.apply(new MinChunkSizePlugin(options.optimize));
	}

	if(options.optimize && options.optimize.maxChunks) {
		compiler.apply(new MovedToPluginWarningPlugin("optimize.maxChunks", "optimize.LimitChunkCountPlugin"));
		var LimitChunkCountPlugin = require("./optimize/LimitChunkCountPlugin");
		compiler.apply(new LimitChunkCountPlugin(options.optimize));
	}

	if(options.optimize.minimize) {
		compiler.apply(new MovedToPluginWarningPlugin("optimize.minimize", "optimize.UglifyJsPlugin"));
		var UglifyJsPlugin = require("./optimize/UglifyJsPlugin");
		if(options.optimize.minimize === true)
			compiler.apply(new UglifyJsPlugin());
		else
			compiler.apply(new UglifyJsPlugin(options.optimize.minimize));
	}

	if(options.cache === undefined ? options.watch : options.cache) {
		var CachePlugin = require("./CachePlugin");
		compiler.apply(new CachePlugin(typeof options.cache === "object" ? options.cache : null));
	}

	if(typeof options.provide === "object") {
		compiler.apply(new MovedToPluginWarningPlugin("provide", "ProvidePlugin"));
		var ProvidePlugin = require("./ProvidePlugin");
		compiler.apply(new ProvidePlugin(options.provide));
	}

	if(options.define) {
		compiler.apply(new MovedToPluginWarningPlugin("define", "DefinePlugin"));
		var defineObject = {};
		if(typeof options.define === "object") {
			Object.keys(options.define).forEach(function(key) {
				defineObject[key] = options.define[key];
			});
		}
		compiler.apply(new DefinePlugin(defineObject));
	}
	if(options.defineDebug !== false)
		compiler.apply(new DefinePlugin({
			DEBUG: !!options.debug
		}));

	compiler.applyPlugins("after-plugins", compiler);
	compiler.resolvers.normal.apply(
		new UnsafeCachePlugin(options.resolve.unsafeCache),
		options.resolve.packageAlias ? new DirectoryDescriptionFileFieldAliasPlugin("package.json", options.resolve.packageAlias) : function() {},
		new ModuleAliasPlugin(options.resolve.alias),
		makeRootPlugin("module", options.resolve.root),
		new ModulesInDirectoriesPlugin("module", options.resolve.modulesDirectories),
		makeRootPlugin("module", options.resolve.fallback),
		new ModuleAsFilePlugin("module"),
		new ModuleAsDirectoryPlugin("module"),
		new DirectoryDescriptionFilePlugin("package.json", options.resolve.packageMains),
		new DirectoryDefaultFilePlugin(["index"]),
		new FileAppendPlugin(options.resolve.extensions),
		new ResultSymlinkPlugin()
	);
	compiler.resolvers.context.apply(
		new UnsafeCachePlugin(options.resolve.unsafeCache),
		new ModuleAliasPlugin(options.resolve.alias),
		makeRootPlugin("module", options.resolve.root),
		new ModulesInDirectoriesPlugin("module", options.resolve.modulesDirectories),
		makeRootPlugin("module", options.resolve.fallback),
		new ModuleAsFilePlugin("module"),
		new ModuleAsDirectoryPlugin("module"),
		new DirectoryResultPlugin(),
		new ResultSymlinkPlugin()
	);
	compiler.resolvers.loader.apply(
		new UnsafeCachePlugin(options.resolve.unsafeCache),
		new ModuleAliasPlugin(options.resolveLoader.alias),
		makeRootPlugin("loader-module", options.resolveLoader.root),
		new ModulesInDirectoriesPlugin("loader-module", options.resolveLoader.modulesDirectories),
		makeRootPlugin("loader-module", options.resolveLoader.fallback),
		new ModuleTemplatesPlugin("loader-module", options.resolveLoader.moduleTemplates, "module"),
		new ModuleAsFilePlugin("module"),
		new ModuleAsDirectoryPlugin("module"),
		new DirectoryDescriptionFilePlugin("package.json", options.resolveLoader.packageMains),
		new DirectoryDefaultFilePlugin(["index"]),
		new FileAppendPlugin(options.resolveLoader.extensions),
		new ResultSymlinkPlugin()
	);
	compiler.applyPlugins("after-resolvers", compiler);
	return options;
};

function makeRootPlugin(name, root) {
	if(typeof root === "string")
		return new ModulesInRootPlugin(name, root);
	else if(Array.isArray(root)) {
		return function() {
			root.forEach(function(root) {
				this.apply(new ModulesInRootPlugin(name, root));
			}, this);
		};
	}
	return function() {};
}
<|endoftext|>


<commit_before>/**
 * Should objects by aligned by a bounding box?
 * [Bug] Scaled objects sometimes can not be aligned by edges
 *
 */
function initAligningGuidelines(canvas) {

  var ctx = canvas.getSelectionContext(),
      canvasHeight = canvas.getHeight(),
      aligningLineOffset = 5,
      aligningLineMargin = 4,
      aligningLineWidth = 1,
      aligningLineColor = 'rgb(0,255,0)';

  function drawVerticalLine(coords) {
    drawLine(
      coords.x + 0.5,
      coords.y1 > coords.y2 ? coords.y2 : coords.y1,
      coords.x + 0.5,
      coords.y2 > coords.y1 ? coords.y2 : coords.y1);
  }

  function drawHorizontalLine(coords) {
    drawLine(
      coords.x1 > coords.x2 ? coords.x2 : coords.x1,
      coords.y + 0.5,
      coords.x2 > coords.x1 ? coords.x2 : coords.x1,
      coords.y + 0.5);
  }

  function drawLine(x1, y1, x2, y2) {
    ctx.save();
    ctx.lineWidth = aligningLineWidth;
    ctx.strokeStyle = aligningLineColor;
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.stroke();
    ctx.restore();
  }

  function isInRange(value1, value2) {
    value1 = Math.round(value1);
    value2 = Math.round(value2);
    for (var i = value1 - aligningLineMargin, len = value1 + aligningLineMargin; i <= len; i++) {
      if (i === value2) {
        return true;
      }
    }
    return false;
  }

  var verticalLines = [ ],
      horizontalLines = [ ];

  canvas.on('object:moving', function(e) {

    var activeObject = e.target,
        canvasObjects = canvas.getObjects(),
        activeObjectLeft = activeObject.get('left'),
        activeObjectTop = activeObject.get('top'),
        activeObjectHeight = activeObject.getHeight(),
        activeObjectWidth = activeObject.getWidth(),
        noneInTheRange = true;

    // It should be trivial to DRY this up by encapsulating (repeating) creation of x1, x2, y1, and y2 into functions,
    // but we're not doing it here for perf. reasons -- as this a function that's invoked on every mouse move

    for (var i = canvasObjects.length; i--; ) {

      if (canvasObjects[i] === activeObject) continue;

      var objectLeft = canvasObjects[i].get('left'),
          objectTop = canvasObjects[i].get('top'),
          objectHeight = canvasObjects[i].getHeight(),
          objectWidth = canvasObjects[i].getWidth();

      // snap by the horizontal center line
      if (isInRange(objectLeft, activeObjectLeft)) {
        noneInTheRange = false;
        verticalLines.push({
          x: objectLeft,
          y1: (objectTop < activeObjectTop)
            ? (objectTop - objectHeight / 2 - aligningLineOffset)
            : (objectTop + objectHeight / 2 + aligningLineOffset),
          y2: (activeObjectTop > objectTop)
            ? (activeObjectTop + activeObjectHeight / 2 + aligningLineOffset)
            : (activeObjectTop - activeObjectHeight / 2 - aligningLineOffset)
        });
        activeObject.set('left', objectLeft);
      }

      // snap by the left edge
      if (isInRange(objectLeft - objectWidth / 2, activeObjectLeft - activeObjectWidth / 2)) {
        noneInTheRange = false;
        verticalLines.push({
          x: objectLeft - objectWidth / 2,
          y1: (objectTop < activeObjectTop)
            ? (objectTop - objectHeight / 2 - aligningLineOffset)
            : (objectTop + objectHeight / 2 + aligningLineOffset),
          y2: (activeObjectTop > objectTop)
            ? (activeObjectTop + activeObjectHeight / 2 + aligningLineOffset)
            : (activeObjectTop - activeObjectHeight / 2 - aligningLineOffset)
        });
        activeObject.set('left', objectLeft - objectWidth / 2 + activeObjectWidth / 2);
      }

      // snap by the right edge
      if (isInRange(objectLeft + objectWidth / 2, activeObjectLeft + activeObjectWidth / 2)) {
        noneInTheRange = false;
        verticalLines.push({
          x: objectLeft + objectWidth / 2,
          y1: (objectTop < activeObjectTop)
            ? (objectTop - objectHeight / 2 - aligningLineOffset)
            : (objectTop + objectHeight / 2 + aligningLineOffset),
          y2: (activeObjectTop > objectTop)
            ? (activeObjectTop + activeObjectHeight / 2 + aligningLineOffset)
            : (activeObjectTop - activeObjectHeight / 2 - aligningLineOffset)
        });
        activeObject.set('left', objectLeft + objectWidth / 2 - activeObjectWidth / 2);
      }

      // snap by the vertical center line
      if (isInRange(objectTop, activeObjectTop)) {
        noneInTheRange = false;
        horizontalLines.push({
          y: objectTop,
          x1: (objectLeft < activeObjectLeft)
            ? (objectLeft - objectWidth / 2 - aligningLineOffset)
            : (objectLeft + objectWidth / 2 + aligningLineOffset),
          x2: (activeObjectLeft > objectLeft)
            ? (activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset)
            : (activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset)
        });
        activeObject.set('top', objectTop);
      }

      // snap by the top edge
      if (isInRange(objectTop - objectHeight / 2, activeObjectTop - activeObjectHeight / 2)) {
        noneInTheRange = false;
        horizontalLines.push({
          y: objectTop - objectHeight / 2,
          x1: (objectLeft < activeObjectLeft)
            ? (objectLeft - objectWidth / 2 - aligningLineOffset)
            : (objectLeft + objectWidth / 2 + aligningLineOffset),
          x2: (activeObjectLeft > objectLeft)
            ? (activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset)
            : (activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset)
        });
        activeObject.set('top', objectTop - objectHeight / 2 + activeObjectHeight / 2);
      }

      // snap by the bottom edge
      if (isInRange(objectTop + objectHeight / 2, activeObjectTop + activeObjectHeight / 2)) {
        noneInTheRange = false;
        horizontalLines.push({
          y: objectTop + objectHeight / 2,
          x1: (objectLeft < activeObjectLeft)
            ? (objectLeft - objectWidth / 2 - aligningLineOffset)
            : (objectLeft + objectWidth / 2 + aligningLineOffset),
          x2: (activeObjectLeft > objectLeft)
            ? (activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset)
            : (activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset)
        });
        activeObject.set('top', objectTop + objectHeight / 2 - activeObjectHeight / 2);
      }
    }

    if (noneInTheRange) {
      verticalLines.length = horizontalLines.length = 0;
    }
  });

  canvas.on('after:render', function() {
    for (var i = verticalLines.length; i--; ) {
      drawVerticalLine(verticalLines[i]);
    }
    for (var i = horizontalLines.length; i--; ) {
      drawHorizontalLine(horizontalLines[i]);
    }
  });

  canvas.on('mouse:up', function() {
    verticalLines.length = horizontalLines.length = 0;
    canvas.renderAll();
  });
}<commit_msg>Fix for dynamic_origin + Remove lines correctly on object moving<commit_after>/**
 * Should objects by aligned by a bounding box?
 * [Bug] Scaled objects sometimes can not be aligned by edges
 *
 */
function initAligningGuidelines(canvas) {

  var ctx = canvas.getSelectionContext(),
      canvasHeight = canvas.getHeight(),
      aligningLineOffset = 5,
      aligningLineMargin = 4,
      aligningLineWidth = 1,
      aligningLineColor = 'rgb(0,255,0)';

  function drawVerticalLine(coords) {
    drawLine(
      coords.x + 0.5,
      coords.y1 > coords.y2 ? coords.y2 : coords.y1,
      coords.x + 0.5,
      coords.y2 > coords.y1 ? coords.y2 : coords.y1);
  }

  function drawHorizontalLine(coords) {
    drawLine(
      coords.x1 > coords.x2 ? coords.x2 : coords.x1,
      coords.y + 0.5,
      coords.x2 > coords.x1 ? coords.x2 : coords.x1,
      coords.y + 0.5);
  }

  function drawLine(x1, y1, x2, y2) {
    ctx.save();
    ctx.lineWidth = aligningLineWidth;
    ctx.strokeStyle = aligningLineColor;
    ctx.beginPath();
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.stroke();
    ctx.restore();
  }

  function isInRange(value1, value2) {
    value1 = Math.round(value1);
    value2 = Math.round(value2);
    for (var i = value1 - aligningLineMargin, len = value1 + aligningLineMargin; i <= len; i++) {
      if (i === value2) {
        return true;
      }
    }
    return false;
  }

  var verticalLines = [ ],
      horizontalLines = [ ];

  canvas.on('object:moving', function(e) {

    var activeObject = e.target,
        canvasObjects = canvas.getObjects(),
        activeObjectCenter = activeObject.getCenterPoint(),
        activeObjectLeft = activeObjectCenter.x,
        activeObjectTop = activeObjectCenter.y,
        activeObjectHeight = activeObject.getHeight(),
        activeObjectWidth = activeObject.getWidth(),
        horizontalInTheRange = false,
        verticalInTheRange = false,
        transform = canvas._currentTransform;

    if (!transform) return;

    // It should be trivial to DRY this up by encapsulating (repeating) creation of x1, x2, y1, and y2 into functions,
    // but we're not doing it here for perf. reasons -- as this a function that's invoked on every mouse move

    for (var i = canvasObjects.length; i--; ) {

      if (canvasObjects[i] === activeObject) continue;

      var objectCenter = canvasObjects[i].getCenterPoint(),
          objectLeft = objectCenter.x,
          objectTop = objectCenter.y,
          objectHeight = canvasObjects[i].getHeight(),
          objectWidth = canvasObjects[i].getWidth();

      // snap by the horizontal center line
      if (isInRange(objectLeft, activeObjectLeft)) {
        verticalInTheRange = true;
        verticalLines.push({
          x: objectLeft,
          y1: (objectTop < activeObjectTop)
            ? (objectTop - objectHeight / 2 - aligningLineOffset)
            : (objectTop + objectHeight / 2 + aligningLineOffset),
          y2: (activeObjectTop > objectTop)
            ? (activeObjectTop + activeObjectHeight / 2 + aligningLineOffset)
            : (activeObjectTop - activeObjectHeight / 2 - aligningLineOffset)
        });
        activeObject.setPositionByOrigin(new fabric.Point(objectLeft, activeObjectTop), transform.originX, transform.originY);
      }

      // snap by the left edge
      if (isInRange(objectLeft - objectWidth / 2, activeObjectLeft - activeObjectWidth / 2)) {
        verticalInTheRange = true;
        verticalLines.push({
          x: objectLeft - objectWidth / 2,
          y1: (objectTop < activeObjectTop)
            ? (objectTop - objectHeight / 2 - aligningLineOffset)
            : (objectTop + objectHeight / 2 + aligningLineOffset),
          y2: (activeObjectTop > objectTop)
            ? (activeObjectTop + activeObjectHeight / 2 + aligningLineOffset)
            : (activeObjectTop - activeObjectHeight / 2 - aligningLineOffset)
        });
        activeObject.setPositionByOrigin(new fabric.Point(objectLeft - objectWidth / 2 + activeObjectWidth / 2, activeObjectTop), transform.originX, transform.originY);
      }

      // snap by the right edge
      if (isInRange(objectLeft + objectWidth / 2, activeObjectLeft + activeObjectWidth / 2)) {
        verticalInTheRange = true;
        verticalLines.push({
          x: objectLeft + objectWidth / 2,
          y1: (objectTop < activeObjectTop)
            ? (objectTop - objectHeight / 2 - aligningLineOffset)
            : (objectTop + objectHeight / 2 + aligningLineOffset),
          y2: (activeObjectTop > objectTop)
            ? (activeObjectTop + activeObjectHeight / 2 + aligningLineOffset)
            : (activeObjectTop - activeObjectHeight / 2 - aligningLineOffset)
        });
        activeObject.setPositionByOrigin(new fabric.Point(objectLeft + objectWidth / 2 - activeObjectWidth / 2, activeObjectTop), transform.originX, transform.originY);
      }

      // snap by the vertical center line
      if (isInRange(objectTop, activeObjectTop)) {
        horizontalInTheRange = true;
        horizontalLines.push({
          y: objectTop,
          x1: (objectLeft < activeObjectLeft)
            ? (objectLeft - objectWidth / 2 - aligningLineOffset)
            : (objectLeft + objectWidth / 2 + aligningLineOffset),
          x2: (activeObjectLeft > objectLeft)
            ? (activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset)
            : (activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset)
        });
        activeObject.setPositionByOrigin(new fabric.Point(activeObjectLeft, objectTop), transform.originX, transform.originY);
      }

      // snap by the top edge
      if (isInRange(objectTop - objectHeight / 2, activeObjectTop - activeObjectHeight / 2)) {
        horizontalInTheRange = true;
        horizontalLines.push({
          y: objectTop - objectHeight / 2,
          x1: (objectLeft < activeObjectLeft)
            ? (objectLeft - objectWidth / 2 - aligningLineOffset)
            : (objectLeft + objectWidth / 2 + aligningLineOffset),
          x2: (activeObjectLeft > objectLeft)
            ? (activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset)
            : (activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset)
        });
        activeObject.setPositionByOrigin(new fabric.Point(activeObjectLeft, objectTop - objectHeight / 2 + activeObjectHeight / 2), transform.originX, transform.originY);
      }

      // snap by the bottom edge
      if (isInRange(objectTop + objectHeight / 2, activeObjectTop + activeObjectHeight / 2)) {
        horizontalInTheRange = true;
        horizontalLines.push({
          y: objectTop + objectHeight / 2,
          x1: (objectLeft < activeObjectLeft)
            ? (objectLeft - objectWidth / 2 - aligningLineOffset)
            : (objectLeft + objectWidth / 2 + aligningLineOffset),
          x2: (activeObjectLeft > objectLeft)
            ? (activeObjectLeft + activeObjectWidth / 2 + aligningLineOffset)
            : (activeObjectLeft - activeObjectWidth / 2 - aligningLineOffset)
        });
        activeObject.setPositionByOrigin(new fabric.Point(activeObjectLeft, objectTop + objectHeight / 2 - activeObjectHeight / 2), transform.originX, transform.originY);
      }
    }

    if (!horizontalInTheRange) {
      horizontalLines.length = 0;
    }

    if (!verticalInTheRange) {
      verticalLines.length = 0;
    }
  });

  canvas.on('after:render', function() {
    canvas.clearContext(canvas.contextTop);
    for (var i = verticalLines.length; i--; ) {
      drawVerticalLine(verticalLines[i]);
    }
    for (var i = horizontalLines.length; i--; ) {
      drawHorizontalLine(horizontalLines[i]);
    }
  });

  canvas.on('mouse:up', function() {
    verticalLines.length = horizontalLines.length = 0;
    canvas.renderAll();
  });
}
<|endoftext|>


<commit_before>function isString(x) {
  return typeof x === 'string';
}

function assertTheUnexpected(expect) {
  function AssertionError(err) {
    Error.call(this, err.message);

    this.stack = err.stack;
  }

  AssertionError.prototype = Object.create(Error.prototype);

  function createWrappedExpect(localExpect) {
    return function wrappedExpect() {
      var args = Array.prototype.slice.apply(arguments);
      // convert UnexpectedError to AssertionError
      try {
        localExpect.apply(localExpect, args);
      } catch (err) {
        throw new AssertionError(err);
      }
    };
  }

  var wrappedExpect = createWrappedExpect(expect);

  function checkTruthy(value) {
    wrappedExpect(value, 'to be truthy');
  }

  function prepareEqual(actual, expected) {
    var a = !actual;
    var b = !expected;

    // undo the null and undefined evaluate equal
    if (!(a && b)) {
      a = actual;
      b = expected;
    }

    if ((Number(a) || Number(b)) && (isString(a) || isString(b))) {
      a = String(a);
      b = String(b);
    }

    return {
      a: a,
      b: b
    };
  }

  return Object.assign(function (value) {
    checkTruthy(value);
  }, {
    AssertionError: AssertionError,
    deepEqual: function deepEqual(actual, expected) {
      var a = actual;
      var b = expected;

      if (typeof actual !== 'object' && typeof expected !== 'object') {
        var comparisonValues = prepareEqual(actual, expected);
        a = comparisonValues.a;
        b = comparisonValues.b;
      }

      wrappedExpect(a, 'to equal', b);

      // handle the lastIndex property
      if (actual instanceof RegExp && actual.hasOwnProperty('lastIndex')) {
        wrappedExpect(actual.lastIndex, 'to equal', expected.lastIndex);
      }
    },
    deepStrictEqual: function deepStrictEqual(actual, expected) {
      wrappedExpect(actual, 'to equal', expected);
    },
    equal: function equal(actual, expected) {
      var comarisonValues = prepareEqual(actual, expected);
      var a = comarisonValues.a;
      var b = comarisonValues.b;

      wrappedExpect(a, 'to be', b);
    },
    ifError: function ifError(value) {
      wrappedExpect(value, 'to be falsy').then(function () {
        throw value;
      });
    },
    notEqual: function notEqual(actual, expected) {
      wrappedExpect(actual, 'not to be', expected);
    },
    notDeepEqual: function notEqual(actual, expected) {
      wrappedExpect(actual, 'not to equal', expected);
    },
    notStrictEqual: function strictEqual(actual, expected) {
      wrappedExpect(actual, 'not to equal', expected);
    },
    ok: function (value) {
      checkTruthy(value);
    },
    strictEqual: function strictEqual(actual, expected) {
      wrappedExpect(actual, 'to equal', expected);
    },
  });
}

module.exports = assertTheUnexpected(require('unexpected'));
<commit_msg>Exclude boolean from the null/undefined hack.<commit_after>function isString(x) {
  return typeof x === 'string';
}

function assertTheUnexpected(expect) {
  function AssertionError(err) {
    Error.call(this, err.message);

    this.stack = err.stack;
  }

  AssertionError.prototype = Object.create(Error.prototype);

  function createWrappedExpect(localExpect) {
    return function wrappedExpect() {
      var args = Array.prototype.slice.apply(arguments);
      // convert UnexpectedError to AssertionError
      try {
        localExpect.apply(localExpect, args);
      } catch (err) {
        throw new AssertionError(err);
      }
    };
  }

  var wrappedExpect = createWrappedExpect(expect);

  function checkTruthy(value) {
    wrappedExpect(value, 'to be truthy');
  }

  function prepareEqual(actual, expected) {
    var a = !actual;
    var b = !expected;

    // undo the null and undefined evaluate equal
    if (!(a && b) && !(typeof actual === 'boolean' || typeof expected === 'boolean')) {
      a = actual;
      b = expected;
    }

    if ((Number(a) || Number(b)) && (isString(a) || isString(b))) {
      a = String(a);
      b = String(b);
    }

    return {
      a: a,
      b: b
    };
  }

  return Object.assign(function (value) {
    checkTruthy(value);
  }, {
    AssertionError: AssertionError,
    deepEqual: function deepEqual(actual, expected) {
      var a = actual;
      var b = expected;

      if (typeof actual !== 'object' && typeof expected !== 'object') {
        var comparisonValues = prepareEqual(actual, expected);
        a = comparisonValues.a;
        b = comparisonValues.b;
      }

      wrappedExpect(a, 'to equal', b);

      // handle the lastIndex property
      if (actual instanceof RegExp && actual.hasOwnProperty('lastIndex')) {
        wrappedExpect(actual.lastIndex, 'to equal', expected.lastIndex);
      }
    },
    deepStrictEqual: function deepStrictEqual(actual, expected) {
      wrappedExpect(actual, 'to equal', expected);
    },
    equal: function equal(actual, expected) {
      var comarisonValues = prepareEqual(actual, expected);
      var a = comarisonValues.a;
      var b = comarisonValues.b;

      wrappedExpect(a, 'to be', b);
    },
    ifError: function ifError(value) {
      wrappedExpect(value, 'to be falsy').then(function () {
        throw value;
      });
    },
    notEqual: function notEqual(actual, expected) {
      wrappedExpect(actual, 'not to be', expected);
    },
    notDeepEqual: function notEqual(actual, expected) {
      wrappedExpect(actual, 'not to equal', expected);
    },
    notStrictEqual: function strictEqual(actual, expected) {
      wrappedExpect(actual, 'not to equal', expected);
    },
    ok: function (value) {
      checkTruthy(value);
    },
    strictEqual: function strictEqual(actual, expected) {
      wrappedExpect(actual, 'to equal', expected);
    },
  });
}

module.exports = assertTheUnexpected(require('unexpected'));
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
// jshint node: true
'use strict';

// useful tool to visualize AST: http://esprima.org/demo/parse.html

/**
 * converts literal: {"type": "Literal", "value": 5,  "raw": "5" }
 * to string
 */
function literalToValue(literal) {
  return literal.value;
}

/**
 * converts unary to string
 * unary: { type: 'UnaryExpression', operator: '-', argument: { ... } }
 */
function unaryToValue(unary) {
  var argValue = expressionToValue(unary.argument);
  if (argValue === undefined)
    return;
  return unary.operator + argValue;
}

/**
 * converts identifier to its value
 * identifier { "type": "Identifier", "name": "Number }
 */
function identifierToValue(identifier) {
  return identifier.name;
}

/**
 * Function is a block statement.
 */
function functionDeclarationToValue(fn) {
  if (fn.body.type == "BlockStatement")
    return blockStatementToValue(fn.body);
}

function functionExpressionToValue(fn) {
  if (fn.body.type == "BlockStatement")
    return blockStatementToValue(fn.body);
}
/**
 * Block statement: find last return statement, and return its value
 */
function blockStatementToValue(block) {
  for (var i=block.body.length - 1; i>= 0; i--) {
    if (block.body[i].type === "ReturnStatement")
      return returnStatementToValue(block.body[i]);
  }
}

/**
 * Evaluates return's argument
 */
function returnStatementToValue(ret) {
  return expressionToValue(ret.argument);
}

/**
 * Enclose containing values in []
 */
function arrayExpressionToValue(arry) {
  var value = '[';
  for (var i=0; i<arry.elements.length; i++) {
    var v = expressionToValue(arry.elements[i]);
    if (v === undefined)
      continue;
    if (i !== 0)
      value += ', ';
    value += v;
  }
  value += ']';
  return value;
}

/**
 * Make it look like an object
 */
function objectExpressionToValue(obj) {
  var value = '{';
  for (var i=0; i<obj.properties.length; i++) {
    var k = expressionToValue(obj.properties[i].key);
    var v = expressionToValue(obj.properties[i].value);
    if (v === undefined)
      continue;
    if (i !== 0)
      value += ', ';
    value += '"' + k + '": ' + v;
  }
  value += '}';
  return value;
}

/**
 * MemberExpression references a variable with name
 */
function memberExpressionToValue(member) {
  return expressionToValue(member.object) + "." + expressionToValue(member.property);
}

/**
 * Tries to get a value from expression. Handles Literal, UnaryExpression
 * returns undefined on failure
 * valueExpression example:
 * { type: "Literal",
 */
function expressionToValue(valueExpression) {
  switch(valueExpression.type) {
    case 'Literal':
      return literalToValue(valueExpression);
    case 'UnaryExpression':
      return unaryToValue(valueExpression);
    case 'Identifier':
      return identifierToValue(valueExpression);
    case 'FunctionDeclaration':
      return functionDeclarationToValue(valueExpression);
    case 'FunctionExpression':
      return functionExpressionToValue(valueExpression);
    case 'ArrayExpression':
      return arrayExpressionToValue(valueExpression);
    case 'ObjectExpression':
      return objectExpressionToValue(valueExpression);
    case 'Identifier':
      return identifierToValue(valueExpression);
    case 'MemberExpression':
      return memberExpressionToValue(valueExpression);
    default:
      return;
  }
}

var CANT_CONVERT = 'UNKNOWN';
module.exports = {
  CANT_CONVERT: CANT_CONVERT,
  expressionToValue: expressionToValue
};
<commit_msg>support binaryexpresson with +<commit_after>/**
 * @license
 * Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
// jshint node: true
'use strict';

// useful tool to visualize AST: http://esprima.org/demo/parse.html

/**
 * converts literal: {"type": "Literal", "value": 5,  "raw": "5" }
 * to string
 */
function literalToValue(literal) {
  return literal.value;
}

/**
 * converts unary to string
 * unary: { type: 'UnaryExpression', operator: '-', argument: { ... } }
 */
function unaryToValue(unary) {
  var argValue = expressionToValue(unary.argument);
  if (argValue === undefined)
    return;
  return unary.operator + argValue;
}

/**
 * converts identifier to its value
 * identifier { "type": "Identifier", "name": "Number }
 */
function identifierToValue(identifier) {
  return identifier.name;
}

/**
 * Function is a block statement.
 */
function functionDeclarationToValue(fn) {
  if (fn.body.type == "BlockStatement")
    return blockStatementToValue(fn.body);
}

function functionExpressionToValue(fn) {
  if (fn.body.type == "BlockStatement")
    return blockStatementToValue(fn.body);
}
/**
 * Block statement: find last return statement, and return its value
 */
function blockStatementToValue(block) {
  for (var i=block.body.length - 1; i>= 0; i--) {
    if (block.body[i].type === "ReturnStatement")
      return returnStatementToValue(block.body[i]);
  }
}

/**
 * Evaluates return's argument
 */
function returnStatementToValue(ret) {
  return expressionToValue(ret.argument);
}

/**
 * Enclose containing values in []
 */
function arrayExpressionToValue(arry) {
  var value = '[';
  for (var i=0; i<arry.elements.length; i++) {
    var v = expressionToValue(arry.elements[i]);
    if (v === undefined)
      continue;
    if (i !== 0)
      value += ', ';
    value += v;
  }
  value += ']';
  return value;
}

/**
 * Make it look like an object
 */
function objectExpressionToValue(obj) {
  var value = '{';
  for (var i=0; i<obj.properties.length; i++) {
    var k = expressionToValue(obj.properties[i].key);
    var v = expressionToValue(obj.properties[i].value);
    if (v === undefined)
      continue;
    if (i !== 0)
      value += ', ';
    value += '"' + k + '": ' + v;
  }
  value += '}';
  return value;
}

/**
 * BinaryExpressions are of the form "literal" + "literal"
 */
function binaryExpressionToValue(member) {
  if (member.operator == "+") {
    return expressionToValue(member.left) + expressionToValue(member.right);
  }
  return
}

/**
 * MemberExpression references a variable with name
 */
function memberExpressionToValue(member) {
  return expressionToValue(member.object) + "." + expressionToValue(member.property);
}

/**
 * Tries to get a value from expression. Handles Literal, UnaryExpression
 * returns undefined on failure
 * valueExpression example:
 * { type: "Literal",
 */
function expressionToValue(valueExpression) {
  switch(valueExpression.type) {
    case 'Literal':
      return literalToValue(valueExpression);
    case 'UnaryExpression':
      return unaryToValue(valueExpression);
    case 'Identifier':
      return identifierToValue(valueExpression);
    case 'FunctionDeclaration':
      return functionDeclarationToValue(valueExpression);
    case 'FunctionExpression':
      return functionExpressionToValue(valueExpression);
    case 'ArrayExpression':
      return arrayExpressionToValue(valueExpression);
    case 'ObjectExpression':
      return objectExpressionToValue(valueExpression);
    case 'Identifier':
      return identifierToValue(valueExpression);
    case 'MemberExpression':
      return memberExpressionToValue(valueExpression);
    case 'BinaryExpression':
      return binaryExpressionToValue(valueExpression);
    default:
      console.log(valueExpression)
      return;
  }
}

var CANT_CONVERT = 'UNKNOWN';
module.exports = {
  CANT_CONVERT: CANT_CONVERT,
  expressionToValue: expressionToValue
};
<|endoftext|>


<commit_before>define([
    'ash'
], function (Ash) {
    var TickProvider = Ash.Class.extend({
        previousTime: 0,
        ticked: new Ash.Signals.Signal(),
        request: null,
        stats: null,
        exceptionCallback: null,

        constructor: function (stats, exceptionCallback) {
            this.stats = stats;
            this.exceptionCallback = exceptionCallback;
        },

        start: function () {
            this.request = requestAnimationFrame(this.tick.bind(this));
        },

        stop: function () {
            cancelAnimationFrame(this.request);
            this.request = null;
        },

        add: function (listener, context) {
            this.ticked.add(listener, context);
        },

        remove: function (listener, context) {
            this.ticked.remove(listener, context);
        },

        tick: function (timestamp) {
            if (this.stats) {
                this.stats.begin();
            }

            timestamp = timestamp || Date.now();
            var tmp = this.previousTime || timestamp;
            this.previousTime = timestamp;
            var delta = (timestamp - tmp) * 0.001;

            try {
                this.ticked.dispatch(delta);
            } catch (ex) {
                if (this.exceptionCallback) {
                    this.exceptionCallback(ex);
                } else {
                    throw ex;
                }
            }
            requestAnimationFrame(this.tick.bind(this));

            if (this.stats) {
                this.stats.end();
            }
        }
    });

    return TickProvider;
});
<commit_msg>fix tick provider not stopping<commit_after>define([
    'ash'
], function (Ash) {
    var TickProvider = Ash.Class.extend({

        previousTime: 0,
        ticked: new Ash.Signals.Signal(),
        request: null,
        stats: null,
        exceptionCallback: null,
		active: false,

        constructor: function (stats, exceptionCallback) {
            this.stats = stats;
            this.exceptionCallback = exceptionCallback;
        },

        start: function () {
			this.active = true;
            this.request = requestAnimationFrame(this.tick.bind(this));
        },

        stop: function () {
            cancelAnimationFrame(this.request);
            this.request = null;
			this.active = false;
        },

        add: function (listener, context) {
            this.ticked.add(listener, context);
        },

        remove: function (listener, context) {
            this.ticked.remove(listener, context);
        },

        tick: function (timestamp) {
            if (this.stats) {
                this.stats.begin();
            }

            timestamp = timestamp || Date.now();
            var tmp = this.previousTime || timestamp;
            this.previousTime = timestamp;
            var delta = (timestamp - tmp) * 0.001;

            try {
                this.ticked.dispatch(delta);
            } catch (ex) {
                if (this.exceptionCallback) {
                    this.exceptionCallback(ex);
                } else {
                    throw ex;
                }
            }

			if (this.active) {
				this.request = requestAnimationFrame(this.tick.bind(this));
			}

            if (this.stats) {
                this.stats.end();
            }
        }
    });

    return TickProvider;
});
<|endoftext|>


<commit_before>/** Tests for geojson-type sources in the map.
 *
 */

/* global it, it, describe, expect, beforeEach, afterEach */

import React from 'react';
import {createStore, combineReducers} from 'redux';
import {mount, configure} from 'enzyme';
import nock from 'nock';
import  Adapter from 'enzyme-adapter-react-16';

import SdkMap from '@boundlessgeo/sdk/components/map';
import MapReducer from '@boundlessgeo/sdk/reducers/map';
import MapboxReducer from '@boundlessgeo/sdk/reducers/mapbox';
import MapInfoReducer from '@boundlessgeo/sdk/reducers/mapinfo';
import * as MapActions from '@boundlessgeo/sdk/actions/map';
import * as MapboxActions from '@boundlessgeo/sdk/actions/mapbox';

configure({adapter: new Adapter()});

describe('tests for the geojson-type map sources', () => {
  let map;
  let store;
  let baseUrl;

  beforeEach(() => {
    store = createStore(combineReducers({
      map: MapReducer,
      mapbox: MapboxReducer,
      mapinfo: MapInfoReducer,
    }));

    baseUrl = 'http://example.com/base';
    store.dispatch(MapboxActions.configure({baseUrl}));
    const wrapper = mount(<SdkMap store={store} />);
    map = wrapper.instance().getWrappedInstance();
  });

  afterEach(() => {
    nock.cleanAll();
  });

  it('ensures map is not undefined', () => {
    expect(map).not.toBe(undefined);
  });

  function testGeojsonData(done, data, nFeatures, silence = false) {
    // when expecting console.errror to show something in the library,
    //  silence it from reporting.
    let error;
    if (silence) {
      error = global.console.error;
      global.console.error = () => {};
    }
    const src_name = 'test-source';
    store.dispatch(MapActions.addSource(src_name, {
      type: 'geojson',
      data,
    }));

    window.setTimeout(() => {
      if (silence) {
        global.console.error = error;
      }
      // check to see if the map source is now defined.
      expect(map.sources[src_name]).not.toBe(undefined);

      // check the feature count matches.
      setTimeout(() => {
        const src = map.sources[src_name];
        expect(src.getFeatures().length).toBe(nFeatures);
        done();
      }, 200);
    }, 0);
  }

  it('handles undefined data', (done) => {
    testGeojsonData(done, undefined, 0);
  });

  it('adds a geojson source with an empty object', (done) => {
    testGeojsonData(done, {}, 0);
  });

  it('adds a geojson source with a single feature', (done) => {
    testGeojsonData(done, {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [0, 0],
      },
      properties: {
        sample: 'value',
      },
    }, 1);
  });

  const feature_collection = {
    type: 'FeatureCollection',
    features: [{
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [0, 0],
      },
      properties: {
        sample: 'value',
      },
    }, {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [-45, 0],
      },
      properties: {
        sample: 'value2',
      },
    }],
  };

  it('adds a geojson feature collection with two features', (done) => {
    testGeojsonData(done, feature_collection, 2);
  });

  it('adds a geojson feature collection from a url', (done) => {
    // mock up the url to call
    nock('http://example.com')
      .get('/test.geojson')
      .reply(200, JSON.stringify(feature_collection));

    testGeojsonData(done, 'http://example.com/test.geojson', 2);
  });

  it('adds a geojson feature collection from a relative url', (done) => {
    // mock up the url to call
    nock('http://example.com')
      .get('/base/test.geojson')
      .reply(200, JSON.stringify(feature_collection));

    testGeojsonData(done, './test.geojson', 2);
  });

  it('adds a geojson feature collection with a BBOX', (done) => {
    // mock up the url to call
    nock('http://example.com')
      .get('/base/bbox.geojson?BBOX=-489196.98102512804,-489196.98102512874,489196.98102512804,489196.98102512734')
      .reply(200, JSON.stringify(feature_collection));

    testGeojsonData(done, '/bbox.geojson?BBOX={bbox-epsg-3857}', 2);
  });

  it('tries to fetch a geojson file that does not exist', (done) => {
    nock('http://example.com')
      .get('/no-where.geojson')
      .reply(404, 'alphabet soup');

    testGeojsonData(done, 'http://example.com/no-where.geojson', 0, true);
  });

  it('fetches a bad geojson file', (done) => {
    nock('http://example.com')
      .get('/bad.geojson')
      .reply(200, 'alphabet soup');

    testGeojsonData(done, 'http://example.com/bad.geojson', 0, true);
  });

  it('fetches by bbox then by relative url', (done) => {

    // mock up the url to call
    nock('http://example.com')
      .get('/base/bbox.geojson?BBOX=-489196.98102512804,-489196.98102512874,489196.98102512804,489196.98102512734')
      .reply(200, JSON.stringify(feature_collection));

    const next_fetch = () => {
      nock('http://example.com')
        .get('/base/test2.geojson')
        .reply(200, JSON.stringify(feature_collection));
      testGeojsonData(done, './test2.geojson', 2);
    };

    testGeojsonData(next_fetch, '/bbox.geojson?BBOX={bbox-epsg-3857}', 2);
  });

  it('fetches from a https location', (done) => {
    nock('https://foo.com')
      .get('/my.geojson')
      .reply(200, JSON.stringify(feature_collection));

    testGeojsonData(done, 'https://foo.com/my.geojson', 2);
  });

  it('dispatches an error', (done) => {
    nock('http://dummy')
      .get('/missing.geojson')
      .reply(404, '');

    const follow_up = () => {
      const errors = store.getState().mapinfo.sourceErrors;
      expect(errors['test-source']).toBe(true);
      done();
    };

    testGeojsonData(follow_up, 'http://dummy/missing.geojson', 0, true);
  });

  it('updates correctly', (done) => {
    const src_name = 'test-source';
    const data1 = {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [0, 0],
      },
      properties: {
        sample: 'value',
      },
    };
    const data2 = {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [0, 0],
      },
      properties: {
        sample: 'value2',
      },
    };
    store.dispatch(MapActions.addSource(src_name, {
      type: 'geojson',
      data: data1,
    }));
    window.setTimeout(() => {
      expect(map.sources[src_name].getFeatures()[0].get('sample')).toBe('value');
      store.dispatch(MapActions.removeFeatures(src_name));
      store.dispatch(MapActions.addFeatures(src_name, [data2]));
      window.setTimeout(() => {
        expect(map.sources[src_name].getFeatures()[0].get('sample')).toBe('value2');
        done();
      }, 200);
    }, 200);
  });

});
<commit_msg>Add unit test for broken draw example<commit_after>/** Tests for geojson-type sources in the map.
 *
 */

/* global it, it, describe, expect, beforeEach, afterEach */

import React from 'react';
import {createStore, combineReducers} from 'redux';
import {mount, configure} from 'enzyme';
import nock from 'nock';
import  Adapter from 'enzyme-adapter-react-16';

import SdkMap from '@boundlessgeo/sdk/components/map';
import MapReducer from '@boundlessgeo/sdk/reducers/map';
import MapboxReducer from '@boundlessgeo/sdk/reducers/mapbox';
import MapInfoReducer from '@boundlessgeo/sdk/reducers/mapinfo';
import * as MapActions from '@boundlessgeo/sdk/actions/map';
import * as MapboxActions from '@boundlessgeo/sdk/actions/mapbox';

configure({adapter: new Adapter()});

describe('tests for the geojson-type map sources', () => {
  let map;
  let store;
  let baseUrl;

  beforeEach(() => {
    store = createStore(combineReducers({
      map: MapReducer,
      mapbox: MapboxReducer,
      mapinfo: MapInfoReducer,
    }));

    baseUrl = 'http://example.com/base';
    store.dispatch(MapboxActions.configure({baseUrl}));
    const wrapper = mount(<SdkMap store={store} />);
    map = wrapper.instance().getWrappedInstance();
  });

  afterEach(() => {
    nock.cleanAll();
  });

  it('ensures map is not undefined', () => {
    expect(map).not.toBe(undefined);
  });

  function testGeojsonData(done, data, nFeatures, silence = false) {
    // when expecting console.errror to show something in the library,
    //  silence it from reporting.
    let error;
    if (silence) {
      error = global.console.error;
      global.console.error = () => {};
    }
    const src_name = 'test-source';
    store.dispatch(MapActions.addSource(src_name, {
      type: 'geojson',
      data,
    }));

    window.setTimeout(() => {
      if (silence) {
        global.console.error = error;
      }
      // check to see if the map source is now defined.
      expect(map.sources[src_name]).not.toBe(undefined);

      // check the feature count matches.
      setTimeout(() => {
        const src = map.sources[src_name];
        expect(src.getFeatures().length).toBe(nFeatures);
        done();
      }, 200);
    }, 0);
  }

  it('handles undefined data', (done) => {
    testGeojsonData(done, undefined, 0);
  });

  it('adds a geojson source with an empty object', (done) => {
    testGeojsonData(done, {}, 0);
  });

  it('adds a geojson source with a single feature', (done) => {
    testGeojsonData(done, {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [0, 0],
      },
      properties: {
        sample: 'value',
      },
    }, 1);
  });

  const feature_collection = {
    type: 'FeatureCollection',
    features: [{
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [0, 0],
      },
      properties: {
        sample: 'value',
      },
    }, {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [-45, 0],
      },
      properties: {
        sample: 'value2',
      },
    }],
  };

  it('adds a geojson feature collection with two features', (done) => {
    testGeojsonData(done, feature_collection, 2);
  });

  it('adds a geojson feature collection from a url', (done) => {
    // mock up the url to call
    nock('http://example.com')
      .get('/test.geojson')
      .reply(200, JSON.stringify(feature_collection));

    testGeojsonData(done, 'http://example.com/test.geojson', 2);
  });

  it('adds a geojson feature collection from a relative url', (done) => {
    // mock up the url to call
    nock('http://example.com')
      .get('/base/test.geojson')
      .reply(200, JSON.stringify(feature_collection));

    testGeojsonData(done, './test.geojson', 2);
  });

  it('adds a geojson feature collection with a BBOX', (done) => {
    // mock up the url to call
    nock('http://example.com')
      .get('/base/bbox.geojson?BBOX=-489196.98102512804,-489196.98102512874,489196.98102512804,489196.98102512734')
      .reply(200, JSON.stringify(feature_collection));

    testGeojsonData(done, '/bbox.geojson?BBOX={bbox-epsg-3857}', 2);
  });

  it('tries to fetch a geojson file that does not exist', (done) => {
    nock('http://example.com')
      .get('/no-where.geojson')
      .reply(404, 'alphabet soup');

    testGeojsonData(done, 'http://example.com/no-where.geojson', 0, true);
  });

  it('fetches a bad geojson file', (done) => {
    nock('http://example.com')
      .get('/bad.geojson')
      .reply(200, 'alphabet soup');

    testGeojsonData(done, 'http://example.com/bad.geojson', 0, true);
  });

  it('fetches by bbox then by relative url', (done) => {

    // mock up the url to call
    nock('http://example.com')
      .get('/base/bbox.geojson?BBOX=-489196.98102512804,-489196.98102512874,489196.98102512804,489196.98102512734')
      .reply(200, JSON.stringify(feature_collection));

    const next_fetch = () => {
      nock('http://example.com')
        .get('/base/test2.geojson')
        .reply(200, JSON.stringify(feature_collection));
      testGeojsonData(done, './test2.geojson', 2);
    };

    testGeojsonData(next_fetch, '/bbox.geojson?BBOX={bbox-epsg-3857}', 2);
  });

  it('fetches from a https location', (done) => {
    nock('https://foo.com')
      .get('/my.geojson')
      .reply(200, JSON.stringify(feature_collection));

    testGeojsonData(done, 'https://foo.com/my.geojson', 2);
  });

  it('dispatches an error', (done) => {
    nock('http://dummy')
      .get('/missing.geojson')
      .reply(404, '');

    const follow_up = () => {
      const errors = store.getState().mapinfo.sourceErrors;
      expect(errors['test-source']).toBe(true);
      done();
    };

    testGeojsonData(follow_up, 'http://dummy/missing.geojson', 0, true);
  });

  it('updates correctly', (done) => {
    const src_name = 'test-source';
    const data1 = {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [0, 0],
      },
      properties: {
        sample: 'value',
      },
    };
    const data2 = {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [0, 0],
      },
      properties: {
        sample: 'value2',
      },
    };
    store.dispatch(MapActions.addSource(src_name, {
      type: 'geojson',
      data: data1,
    }));
    window.setTimeout(() => {
      expect(map.sources[src_name].getFeatures()[0].get('sample')).toBe('value');
      store.dispatch(MapActions.removeFeatures(src_name));
      store.dispatch(MapActions.addFeatures(src_name, [data2]));
      window.setTimeout(() => {
        expect(map.sources[src_name].getFeatures()[0].get('sample')).toBe('value2');
        done();
      }, 200);
    }, 200);
  });

  it('updates correctly when empty from the start', (done) => {
    const src_name = 'test-source';
    const empty = {
      type: 'FeatureCollection',
      features: [],
    };
    const feature = {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [0, 0],
      },
      properties: {
        sample: 'value',
      },
    };
    store.dispatch(MapActions.addSource(src_name, {
      type: 'geojson',
      data: empty
    }));
    window.setTimeout(() => {
      expect(map.sources[src_name].getFeatures()).toHaveLength(0);
      store.dispatch(MapActions.addFeatures(src_name, [feature]));
      window.setTimeout(() => {
        expect(map.sources[src_name].getFeatures()[0].get('sample')).toBe('value');
        done();
      }, 200);
    }, 200);
  });

});
<|endoftext|>


<commit_before>/**
 * @preserve Copyright (c) 2011, Vladimir Agafonkin
 * SunCalc is a JavaScript library for calculating sun position and sunlight phases.
 * https://github.com/mourner/suncalc
 */

/*jslint browser: true, node: true, vars: true */

(function (global) {
	"use strict";

	// export either as a CommonJS module or a global variable

	var SunCalc;

	if (typeof exports !== 'undefined') {
		SunCalc = exports;
	} else {
		SunCalc = global.SunCalc = {};
	}

	// utility shortcuts

	var PI = Math.PI,
	    rad = PI / 180,
	    sin = Math.sin,
	    cos = Math.cos,
	    asin = Math.asin,
	    atan2 = Math.atan2;

	// date constants and conversions

	var dayMs = 1000 * 60 * 60 * 24,
	    J1970 = 2440588,
	    J2000 = 2451545;

	function toJulian(date) {
		return date.valueOf() / dayMs - 0.5 + J1970;
	}
	function fromJulian(j) {
		return new Date((j + 0.5 - J1970) * dayMs);
	}

	// constants for sun calculations

	var M0  = rad * 357.5291,
	    M1  = rad * 0.98560028,
	    J0  = 0.0009,
	    J1  = 0.0053,
	    J2  = -0.0069,
	    C1  = rad * 1.9148,
	    C2  = rad * 0.0200,
	    C3  = rad * 0.0003,
	    P   = rad * 102.9372,
	    e   = rad * 23.45,
	    th0 = rad * 280.1600,
	    th1 = rad * 360.9856235;

	// general sun calculations

	function getJulianCycle(J, lw) {
		return Math.round(J - J2000 - J0 - lw / (2 * PI));
	}
	function getSolarMeanAnomaly(Js) {
		return M0 + M1 * (Js - J2000);
	}
	function getEquationOfCenter(M) {
		return C1 * sin(M) + C2 * sin(2 * M) + C3 * sin(3 * M);
	}
	function getEclipticLongitude(M, C) {
		return M + P + C + PI;
	}
	function getSunDeclination(Ls) {
		return asin(sin(Ls) * sin(e));
	}

	// calculations for sun position

	function getRightAscension(Ls) {
		return atan2(sin(Ls) * cos(e), cos(Ls));
	}
	function getSiderealTime(J, lw) {
		return th0 + th1 * (J - J2000) - lw;
	}
	function getAzimuth(H, phi, d) {
		return atan2(sin(H), cos(H) * sin(phi) - Math.tan(d) * cos(phi));
	}
	function getAltitude(H, phi, d) {
		return asin(sin(phi) * sin(d) + cos(phi) * cos(d) * cos(H));
	}

	// calculations for sun times

	function getApproxTransit(Ht, lw, n) {
		return J2000 + J0 + (Ht + lw) / (2 * PI) + n;
	}
	function getSolarTransit(Js, M, Ls) {
		return Js + (J1 * sin(M)) + (J2 * sin(2 * Ls));
	}
	function getHourAngle(h, phi, d) {
		return Math.acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d)));
	}

	// calculates sun azimuth and altitude for a given date and latitude/longitude

	SunCalc.getPosition = function (date, lat, lng) {

		var lw  = rad * -lng,
		    phi = rad * lat,
		    J   = toJulian(date),

		    M  = getSolarMeanAnomaly(J),
		    C  = getEquationOfCenter(M),
		    Ls = getEclipticLongitude(M, C),
		    d  = getSunDeclination(Ls),
		    a  = getRightAscension(Ls),
		    th = getSiderealTime(J, lw),
		    H  = th - a;

		return {
			azimuth: getAzimuth(H, phi, d),
			altitude: getAltitude(H, phi, d)
		};
	};

	// times configuration (angle, morning name, evening name)

	var times = [
		[-0.83, 'sunrise',       'sunset'      ],
		[ -0.3, 'sunriseEnd',    'sunsetStart' ],
		[   -6, 'dawn',          'dusk'        ],
		[  -12, 'nauticalDawn',  'nauticalDusk'],
		[  -18, 'nightEnd',      'night'       ],
		[    6, 'goldenHourEnd', 'goldenHour'  ]
	];

	// adds a custom time to the times config

	SunCalc.addTime = function (angle, riseName, setName) {
		times.push([angle, riseName, setName]);
	};

	// calculates sun times for a given date and latitude/longitude

	SunCalc.getTimes = function (date, lat, lng) {

		var lw  = rad * -lng,
		    phi = rad * lat,
		    J   = toJulian(date),

		    n  = getJulianCycle(J, lw),
		    Js = getApproxTransit(0, lw, n),
		    M  = getSolarMeanAnomaly(Js),
		    C  = getEquationOfCenter(M),
		    Ls = getEclipticLongitude(M, C),
		    d  = getSunDeclination(Ls),

		    Jnoon = getSolarTransit(Js, M, Ls);

		function getSetJ(h) {
			var w = getHourAngle(h, phi, d),
			    a = getApproxTransit(w, lw, n);
			return getSolarTransit(a, M, Ls);
		}

		var result = {
			solarNoon: fromJulian(Jnoon),
			nadir: fromJulian(Jnoon - 0.5)
		};

		var i, len, time,
		    angle, morningName, eveningName,
		    Jset, Jrise;

		for (i = 0, len = times.length; i < len; i += 1) {

			time = times[i];

			angle = time[0];
			morningName = time[1];
			eveningName = time[2];

			Jset = getSetJ(angle * rad);
			Jrise = Jnoon - (Jset - Jnoon);

			result[morningName] = fromJulian(Jrise);
			result[eveningName] = fromJulian(Jset);
		}

		return result;
	};

}(this));
<commit_msg>add moon position calculation, fix #1<commit_after>/**
 * @preserve Copyright (c) 2011, Vladimir Agafonkin
 * SunCalc is a JavaScript library for calculating sun position and sunlight phases.
 * https://github.com/mourner/suncalc
 */

/*jslint browser: true, node: true, vars: true */

(function (global) {
	"use strict";

	// export either as a CommonJS module or a global variable

	var SunCalc;

	if (typeof exports !== 'undefined') {
		SunCalc = exports;
	} else {
		SunCalc = global.SunCalc = {};
	}

	// utility shortcuts

	var PI = Math.PI,
	    rad = PI / 180,
	    sin = Math.sin,
	    cos = Math.cos,
	    tan = Math.tan,
	    asin = Math.asin,
	    atan = Math.atan2;

	// date constants and conversions

	var dayMs = 1000 * 60 * 60 * 24,
	    J1970 = 2440588,
	    J2000 = 2451545;

	function toJulian(date) {
		return date.valueOf() / dayMs - 0.5 + J1970;
	}
	function fromJulian(j) {
		return new Date((j + 0.5 - J1970) * dayMs);
	}

	// constants for sun calculations

	var M0  = rad * 357.5291,
	    M1  = rad * 0.98560028,
	    J0  = 0.0009,
	    J1  = 0.0053,
	    J2  = -0.0069,
	    C1  = rad * 1.9148,
	    C2  = rad * 0.0200,
	    C3  = rad * 0.0003,
	    P   = rad * 102.9372,
	    e   = rad * 23.4397,
	    th0 = rad * 280.1600,
	    th1 = rad * 360.9856235;

	// general sun calculations

	function getSolarMeanAnomaly(Js) {
		return M0 + M1 * (Js - J2000);
	}
	function getEquationOfCenter(M) {
		return C1 * sin(M) + C2 * sin(2 * M) + C3 * sin(3 * M);
	}
	function getEclipticLongitude(M, C) {
		return M + P + C + PI;
	}
	function getSunDeclination(Ls) {
		return asin(sin(Ls) * sin(e));
	}
	function getRightAscension(Ls) {
		return atan(sin(Ls) * cos(e), cos(Ls));
	}

	// calculations for sun position

	function getSiderealTime(J, lw) {
		return th0 + th1 * (J - J2000) - lw;
	}
	function getAzimuth(H, phi, d) {
		return atan(sin(H), cos(H) * sin(phi) - tan(d) * cos(phi));
	}
	function getAltitude(H, phi, d) {
		return asin(sin(phi) * sin(d) + cos(phi) * cos(d) * cos(H));
	}

	// calculations for sun times

	function getJulianCycle(J, lw) {
		return Math.round(J - J2000 - J0 - lw / (2 * PI));
	}
	function getApproxTransit(Ht, lw, n) {
		return J2000 + J0 + (Ht + lw) / (2 * PI) + n;
	}
	function getSolarTransit(Js, M, Ls) {
		return Js + (J1 * sin(M)) + (J2 * sin(2 * Ls));
	}
	function getHourAngle(h, phi, d) {
		return Math.acos((sin(h) - sin(phi) * sin(d)) / (cos(phi) * cos(d)));
	}

	// calculates sun azimuth and altitude for a given date and latitude/longitude

	SunCalc.getPosition = function (date, lat, lng) {

		var lw  = rad * -lng,
		    phi = rad * lat,
		    J   = toJulian(date),

		    M  = getSolarMeanAnomaly(J),
		    C  = getEquationOfCenter(M),
		    Ls = getEclipticLongitude(M, C),
		    d  = getSunDeclination(Ls),
		    a  = getRightAscension(Ls),
		    th = getSiderealTime(J, lw),
		    H  = th - a;

		return {
			azimuth: getAzimuth(H, phi, d),
			altitude: getAltitude(H, phi, d)
		};
	};

	// times configuration (angle, morning name, evening name)

	var times = [
		[-0.83, 'sunrise',       'sunset'      ],
		[ -0.3, 'sunriseEnd',    'sunsetStart' ],
		[   -6, 'dawn',          'dusk'        ],
		[  -12, 'nauticalDawn',  'nauticalDusk'],
		[  -18, 'nightEnd',      'night'       ],
		[    6, 'goldenHourEnd', 'goldenHour'  ]
	];

	// adds a custom time to the times config

	SunCalc.addTime = function (angle, riseName, setName) {
		times.push([angle, riseName, setName]);
	};

	// calculates sun times for a given date and latitude/longitude

	SunCalc.getTimes = function (date, lat, lng) {

		var lw  = rad * -lng,
		    phi = rad * lat,
		    J   = toJulian(date),

		    n  = getJulianCycle(J, lw),
		    Js = getApproxTransit(0, lw, n),
		    M  = getSolarMeanAnomaly(Js),
		    C  = getEquationOfCenter(M),
		    Ls = getEclipticLongitude(M, C),
		    d  = getSunDeclination(Ls),

		    Jnoon = getSolarTransit(Js, M, Ls);

		function getSetJ(h) {
			var w = getHourAngle(h, phi, d),
			    a = getApproxTransit(w, lw, n);
			return getSolarTransit(a, M, Ls);
		}

		var result = {
			solarNoon: fromJulian(Jnoon),
			nadir: fromJulian(Jnoon - 0.5)
		};

		var i, len, time,
		    angle, morningName, eveningName,
		    Jset, Jrise;

		for (i = 0, len = times.length; i < len; i += 1) {

			time = times[i];

			angle = time[0];
			morningName = time[1];
			eveningName = time[2];

			Jset = getSetJ(angle * rad);
			Jrise = Jnoon - (Jset - Jnoon);

			result[morningName] = fromJulian(Jrise);
			result[eveningName] = fromJulian(Jset);
		}

		return result;
	};

	function getMoonRightAscension(l, b) {
		return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l));
	}

	function getMoonDeclination(l, b) {
		return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l));
	}
	function getRefractedAltitude(h) {
		return h + 0.017 * rad / tan(h + 10.26 * rad / (h + 5.10 * rad));
	}

	SunCalc.getMoonPosition = function (date, lat, lng) {

		var lw  = rad * -lng,
		    phi = rad * lat,

		    J  = toJulian(date),
		    Jd = J - J2000,

		    L = 218.316 + 13.176396 * Jd,
		    M = 134.963 + 13.064993 * Jd,
		    F = 93.272 + 13.229350 * Jd,
		    l = rad * (L + 6.289 * sin(rad * M)),
		    b = rad * 5.128 * sin(rad * F),
		    dt = 385001 - 20905 * cos(rad  * M),

		    a = getMoonRightAscension(l, b),
			d = getMoonDeclination(l, b),
		    th = getSiderealTime(J, lw),
		    H = th - a;

		return {
			azimuth: getAzimuth(H, phi, d),
			altitude: getRefractedAltitude(getAltitude(H, phi, d)),
			distance: dt
		};
	};

}(this));
<|endoftext|>


<commit_before>/**
 * @preserve Copyright (c) 2011, Vladimir Agafonkin
 * SunCalc is a JavaScript library for calculating sun position and sunlight phases.
 * https://github.com/mourner/suncalc
 */

/*jslint browser: true, node: true, vars: true */

(function (global) {
	"use strict";

	// export either as a CommonJS module or a global variable

	var SunCalc;

	if (typeof exports !== 'undefined') {
		SunCalc = exports;
	} else {
		SunCalc = global.SunCalc = {};
	}

	// utility shortcuts (for better compression)

	var m   = Math,
	    rad = m.PI / 180,
	    sin = m.sin,
        cos = m.cos;

	// constants for sun calculations

	var dayMs = 1000 * 60 * 60 * 24,
	    J1970 = 2440588,
	    J2000 = 2451545,
	    M0    = rad * 357.5291,
	    M1    = rad * 0.98560028,
	    J0    = 0.0009,
	    J1    = 0.0053,
	    J2    = -0.0069,
	    C1    = rad * 1.9148,
	    C2    = rad * 0.0200,
	    C3    = rad * 0.0003,
	    P     = rad * 102.9372,
	    e     = rad * 23.45,
	    th0   = rad * 280.1600,
	    th1   = rad * 360.9856235;

	// date conversions

	function dateToJulianDate(date) { return date.valueOf() / dayMs - 0.5 + J1970; }
	function julianDateToDate(j)    { return new Date((j + 0.5 - J1970) * dayMs);  }

	// general sun calculations

	function getJulianCycle(J, lw)      { return m.round(J - J2000 - J0 - lw / (2 * m.PI)); }
	function getSolarMeanAnomaly(Js)    { return M0 + M1 * (Js - J2000);                    }
	function getEquationOfCenter(M)     { return C1 * sin(M) + C2 * sin(2 * M) +
	                                                           C3 * sin(3 * M);             }
	function getEclipticLongitude(M, C) { return M + P + C + m.PI;                          }
	function getSunDeclination(Ls)      { return m.asin(sin(Ls) * sin(e));                  }

	// calculations for sun times

	function getApproxTransit(Ht, lw, n) { return J2000 + J0 + (Ht + lw) / (2 * m.PI) + n; }
	function getSolarTransit(Js, M, Ls)  { return Js + (J1 * sin(M)) + (J2 * sin(2 * Ls)); }
	function getHourAngle(h, phi, d)     { return m.acos((sin(h) - sin(phi) * sin(d)) /
	                                                     (cos(phi) * cos(d)));             }

	// calculations for sun position

	function getRightAscension(Ls)  { return m.atan2(sin(Ls) * cos(e), cos(Ls)); }
	function getSiderealTime(J, lw) { return th0 + th1 * (J - J2000) - lw;       }
	function getAzimuth(H, phi, d)  { return m.atan2(sin(H), cos(H) * sin(phi) -
	                                                 m.tan(d) * cos(phi));       }
	function getAltitude(H, phi, d) { return m.asin(sin(phi) * sin(d) +
	                                                cos(phi) * cos(d) * cos(H)); }

	// times configuration (angle, morning name, evening name)

	var times = [[-0.83, 'sunrise',       'sunset'      ],
	             [ -0.3, 'sunriseEnd',    'sunsetStart' ],
	             [   -6, 'dawn',          'dusk'        ],
	             [  -12, 'nauticalDawn',  'nauticalDusk'],
	             [  -18, 'night',         'nightEnd'    ],
	             [    6, 'goldenHourEnd', 'goldenHour'  ]];

	// adds a custom time to the times config

	SunCalc.addTime = function (angle, riseName, setName) {
		times.push([angle, riseName, setName]);
	};

	// calculates sun times for a given date and latitude/longitude

	SunCalc.getTimes = function (date, lat, lng) {
		var lw    = rad * -lng,
		    phi   = rad * lat,
		    J     = dateToJulianDate(date),
		    n     = getJulianCycle(J, lw),
		    Js    = getApproxTransit(0, lw, n),
		    M     = getSolarMeanAnomaly(Js),
		    C     = getEquationOfCenter(M),
		    Ls    = getEclipticLongitude(M, C),
		    d     = getSunDeclination(Ls),
		    Jnoon = getSolarTransit(Js, M, Ls);

		function getSetJ(h) {
			var w = getHourAngle(h, phi, d),
			    a = getApproxTransit(w, lw, n);
			return getSolarTransit(a, M, Ls);
		}

		var result = {solarNoon: julianDateToDate(Jnoon)};

		var i, len, time, angle, morningName, eveningName, Jset, Jrise;
		for (i = 0, len = times.length; i < len; i += 1) {
			time = times[i];

			angle       = time[0];
			morningName = time[1];
			eveningName = time[2];

			Jset  = getSetJ(angle * rad);
			Jrise = Jnoon - (Jset - Jnoon);

			result[morningName] = julianDateToDate(Jrise);
			result[eveningName] = julianDateToDate(Jset);
		}

		return result;
	};

	// calculates sun azimuth and altitude for a given date and latitude/longitude

	SunCalc.getPosition = function (date, lat, lng) {
		var lw  = rad * -lng,
		    phi = rad * lat,
		    J   = dateToJulianDate(date),
		    M   = getSolarMeanAnomaly(J),
		    C   = getEquationOfCenter(M),
		    Ls  = getEclipticLongitude(M, C),
		    d   = getSunDeclination(Ls),
		    a   = getRightAscension(Ls),
		    th  = getSiderealTime(J, lw),
		    H   = th - a;

		return {
			azimuth:  getAzimuth(H, phi, d),
			altitude: getAltitude(H, phi, d)
		};
	};

}(this));<commit_msg>whitespace fixes<commit_after>/**
 * @preserve Copyright (c) 2011, Vladimir Agafonkin
 * SunCalc is a JavaScript library for calculating sun position and sunlight phases.
 * https://github.com/mourner/suncalc
 */

/*jslint browser: true, node: true, vars: true */

(function (global) {
	"use strict";

	// export either as a CommonJS module or a global variable

	var SunCalc;

	if (typeof exports !== 'undefined') {
		SunCalc = exports;
	} else {
		SunCalc = global.SunCalc = {};
	}

	// utility shortcuts (for better compression)

	var m   = Math,
	    rad = m.PI / 180,
	    sin = m.sin,
	    cos = m.cos;

	// constants for sun calculations

	var dayMs = 1000 * 60 * 60 * 24,
	    J1970 = 2440588,
	    J2000 = 2451545,
	    M0    = rad * 357.5291,
	    M1    = rad * 0.98560028,
	    J0    = 0.0009,
	    J1    = 0.0053,
	    J2    = -0.0069,
	    C1    = rad * 1.9148,
	    C2    = rad * 0.0200,
	    C3    = rad * 0.0003,
	    P     = rad * 102.9372,
	    e     = rad * 23.45,
	    th0   = rad * 280.1600,
	    th1   = rad * 360.9856235;

	// date conversions

	function dateToJulianDate(date) { return date.valueOf() / dayMs - 0.5 + J1970; }
	function julianDateToDate(j)    { return new Date((j + 0.5 - J1970) * dayMs);  }

	// general sun calculations

	function getJulianCycle(J, lw)      { return m.round(J - J2000 - J0 - lw / (2 * m.PI)); }
	function getSolarMeanAnomaly(Js)    { return M0 + M1 * (Js - J2000);                    }
	function getEquationOfCenter(M)     { return C1 * sin(M) + C2 * sin(2 * M) +
	                                                           C3 * sin(3 * M);             }
	function getEclipticLongitude(M, C) { return M + P + C + m.PI;                          }
	function getSunDeclination(Ls)      { return m.asin(sin(Ls) * sin(e));                  }

	// calculations for sun times

	function getApproxTransit(Ht, lw, n) { return J2000 + J0 + (Ht + lw) / (2 * m.PI) + n; }
	function getSolarTransit(Js, M, Ls)  { return Js + (J1 * sin(M)) + (J2 * sin(2 * Ls)); }
	function getHourAngle(h, phi, d)     { return m.acos((sin(h) - sin(phi) * sin(d)) /
	                                                     (cos(phi) * cos(d)));             }

	// calculations for sun position

	function getRightAscension(Ls)  { return m.atan2(sin(Ls) * cos(e), cos(Ls)); }
	function getSiderealTime(J, lw) { return th0 + th1 * (J - J2000) - lw;       }
	function getAzimuth(H, phi, d)  { return m.atan2(sin(H), cos(H) * sin(phi) -
	                                                 m.tan(d) * cos(phi));       }
	function getAltitude(H, phi, d) { return m.asin(sin(phi) * sin(d) +
	                                                cos(phi) * cos(d) * cos(H)); }

	// times configuration (angle, morning name, evening name)

	var times = [[-0.83, 'sunrise',       'sunset'      ],
	             [ -0.3, 'sunriseEnd',    'sunsetStart' ],
	             [   -6, 'dawn',          'dusk'        ],
	             [  -12, 'nauticalDawn',  'nauticalDusk'],
	             [  -18, 'night',         'nightEnd'    ],
	             [    6, 'goldenHourEnd', 'goldenHour'  ]];

	// adds a custom time to the times config

	SunCalc.addTime = function (angle, riseName, setName) {
		times.push([angle, riseName, setName]);
	};

	// calculates sun times for a given date and latitude/longitude

	SunCalc.getTimes = function (date, lat, lng) {

		var lw    = rad * -lng,
		    phi   = rad * lat,
		    J     = dateToJulianDate(date),
		    n     = getJulianCycle(J, lw),
		    Js    = getApproxTransit(0, lw, n),
		    M     = getSolarMeanAnomaly(Js),
		    C     = getEquationOfCenter(M),
		    Ls    = getEclipticLongitude(M, C),
		    d     = getSunDeclination(Ls),
		    Jnoon = getSolarTransit(Js, M, Ls);

		function getSetJ(h) {
			var w = getHourAngle(h, phi, d),
			    a = getApproxTransit(w, lw, n);

			return getSolarTransit(a, M, Ls);
		}

		var result = {solarNoon: julianDateToDate(Jnoon)};

		var i, len, time, angle, morningName, eveningName, Jset, Jrise;
		for (i = 0, len = times.length; i < len; i += 1) {
			time = times[i];

			angle       = time[0];
			morningName = time[1];
			eveningName = time[2];

			Jset  = getSetJ(angle * rad);
			Jrise = Jnoon - (Jset - Jnoon);

			result[morningName] = julianDateToDate(Jrise);
			result[eveningName] = julianDateToDate(Jset);
		}

		return result;
	};

	// calculates sun azimuth and altitude for a given date and latitude/longitude

	SunCalc.getPosition = function (date, lat, lng) {

		var lw  = rad * -lng,
		    phi = rad * lat,
		    J   = dateToJulianDate(date),
		    M   = getSolarMeanAnomaly(J),
		    C   = getEquationOfCenter(M),
		    Ls  = getEclipticLongitude(M, C),
		    d   = getSunDeclination(Ls),
		    a   = getRightAscension(Ls),
		    th  = getSiderealTime(J, lw),
		    H   = th - a;

		return {
			azimuth:  getAzimuth(H, phi, d),
			altitude: getAltitude(H, phi, d)
		};
	};

}(this));<|endoftext|>