dispatch.to("Foundry/2.1 Core Plugins").at(function($, manifest) {

/**
 * jquery.require.
 * A dependency loader built on top of $.Deferred() backbone.
 * An alternative take on RequireJS.
 * https://github.com/jstonne/jquery.require
 *
 * Copyright (c) 2012 Jensen Tonne
 * www.jstonne.com
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

$.require = (function() {

	// internal function
	var getFolderPath = function(path) {
		return $.uri(path).setAnchor('').setQuery('').toPath('../').toString();
	};

	var self = function(options) {

		var batch = new self.batch(options);

		self.batches[batch.id] = batch;

		return batch;
	};

	// Require methods & properties

	$.extend(self, {

		defaultOptions: {

			// Path selection order:
			path: (function() {

				var path =

					$.scriptPath ||

					// By "require_path" attribute
					$('[require-path]').attr('require-path') ||

					// By last script tag's "src" attribute
					getFolderPath($('script:last').attr('src')) ||

					// By window location
					getFolderPath(window.location.href);

				if (/^(\/|\.)/.test(path)) {
					path = $.uri(window.location.href).toPath(path).toString();
				}

				return path;
			})(),

			timeout: 10000,

			retry: 3,

			verbose: ($.environment=="development")
		},

		setup: function(options) {

			$.extend(self.defaultOptions, options);
		},

		batches: {},

		batch: function(options) {

			var batch = this;

			batch.id = $.uid();

			// Batch manager tracks the state of tasks in batch.taskList and batch.tasks.
			batch.manager = $.Deferred();

			batch.taskList = [];

			batch.tasksFinalized = false;

			batch.options = $.extend({}, self.defaultOptions, options);
		},

		status: function() {
			$.each(self.batches, function(i, batch){
				console.info(batch.id, batch.state(), batch);

				$.each(batch.taskList, function(i, task){
					console.log('\t [' + task.name + ']', task.state());
				});
			});
		},

		loaders: {},

		addLoader: function(name, factory) {

			// Static call, e.g.
			// $.require.script.setup({});
			self[name] = factory;

			// Create proxy functions to require loaders,
			// assigning current batch to factory's "this".
			self.batch.prototype[name] = function() {

				var batch = this;

				factory.apply(batch, arguments);

				// Ensure require calls are chainable
				return batch;
			};

			self.loaders[name] = self[name] = factory;
		},

		removeLoader: function(name) {
			delete self.batch.prototype[name];
			delete self[name];
		}

	});

	// Batch class

	$.extend(self.batch.prototype, {

		addTask: function(task) {

			var batch = this;

			if (!$.isDeferred(task)) {
				return;
			};

			if (batch.taskFinalized) {

				if (batch.options.verbose) {
					console.warn('$.require: ' + task.name + ' ignored because tasks of this batch are finalized.', task);
				};

				return;
			};

			task.batch = batch;

			task.then(
				$.proxy(batch.taskDone, task),
				$.proxy(batch.taskFail, task),
				$.proxy(batch.taskProgress, task)
			);

			batch.taskList.push(task);
		},

		taskDone: function() {

			var task = this,
				batch = task.batch;

			batch.manager.notifyWith(batch, [task]);
		},

		taskFail: function() {

			var task = this,
				batch = task.batch;

			if (batch.options.verbose) {
				console.error('$.require: ' + task.name + ' failed to load.', task);
			};

			batch.manager.notifyWith(batch, [task]);
		},

		taskProgress: function() {

			var task = this,
				batch = task.batch;

			batch.manager.notifyWith(batch, [task]);
		},

		expand: function(args, opts) {

			var args = $.makeArray(args),
				options = opts || {},
				names = [];

            if ($.isPlainObject(args[0])) {
                options = $.extend(args[0], opts);
                names = args.slice(1);
            } else {
                names = args;
            }

            return {
            	options: options,
            	names: names
            }
		},

		// TODO: Statistics
		stat: function(){
		}
	});

	// Masquerade newly created batch instances as a pseudo-promise object
	// until one of those promise's method is called. This is to ensure that
	// no callbacks are fired too early until all loading tasks are finalized.

	$.each(['then','done','fail','always','pipe','progress'], function(i, func) {

		self.batch.prototype[func] = function() {

			var batch = this;

			// Finalize all tasks so no further tasks
			// can be added to the batch job.
			batch.taskFinalized = true;

			// Extend batch with batch manager's promise methods,
			// overriding original pseudo-promise methods.
			$.extend(batch, batch.manager.promise());

			// Create a master deferred object for all tasks
			batch.tasks = $.when.apply(null, batch.taskList);

			batch.tasks
				// Resolve batch if all tasks are done
				.done(function(){

					batch.manager.resolve();
				})

				// Reject batch if one of the task failed
				.fail(function(){

					if (batch.options.verbose) {
						console.info('$.require: Batch ' + batch.id + ' failed.', batch);
					};

					batch.manager.reject();
				});

			// Execute method that was originally called
			batch[func].apply(batch, arguments);

			return batch;
		}
	});

	return self;

})();
/**
 * jquery.require.script
 * Script loader plugin for $.require.
 *
 * Part of jquery.require family.
 * https://github.com/jstonne/jquery.require
 *
 * Copyright (c) 2012 Jensen Tonne
 * www.jstonne.com
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

$.require.addLoader('script', (function() {

	// IE & Opera thinks punycoded urls are cross-domain requests,
	// and rejects the ajax request because they think they don't have
	// the necesary transport to facilitate such requests.

	var ajaxHost = $.uri($.indexUrl).host(),
		documentHost = $.uri(document.location.href).host();

	if (ajaxHost!==documentHost && ajaxHost.match("xn--")) {
		$.support.cors = true;
	}

	var canAsync = document.createElement("script").async === true || "MozAppearance" in document.documentElement.style || window.opera;

	var self = function() {

		var batch = this,
			args = $.makeArray(arguments),
			options,
			names;

		// Expand arguments into its actual definition
		if ($.isPlainObject(args[0])) {
			options = args[0];
			names = args.slice(1);
		} else {
			names = args;
		}

		options = $.extend(
			{},
			self.defaultOptions,
			batch.options,
			options,
			{batch: batch}
		);

		// Create tasks and add it to the batch.
		var taskBefore;

		$.each(names, function(i, name) {

			var task = new self.task(name, options, taskBefore);

			batch.addTask(task);

			// Serial script loading
			if (options.serial && taskBefore!==undefined) {

				// Only start current task when the
				// task before is resolved/rejected.
				taskBefore.always(task.start);

			} else {

				task.start();
			}

			taskBefore = task;

		});

	};

	$.extend(self, {

		defaultOptions: {
			// Overrides require path.
			path: '',

			extension: 'js',

			// Serial script loading. Default: Parallel script loading.
			serial: false,

			// Asynchronous script execution. Default: Synchronous script execution.
			async: false,

			// Use XHR to load script. Default: Script injection.
			xhr: false,

			// Used in IE to prefetch scripts.
			prefetch: false
		},

		setup: function() {

			$.extend(self.defaultOptions, options);
		},

		scripts: {},

		task: function(name, options, taskBefore) {

			var task = $.extend(this, $.Deferred());

			task.name = name;

			task.options = options;

			task.taskBefore = taskBefore;

			// Module assignment or module url override
			if ($.isArray(name)) {

				task.name = name[0] + "@" + name[1];

				task.moduleName = name[0];

				var overrideModuleUrl = name[2];

				// Module assignment
				if (!overrideModuleUrl) {

					// Set module flag
					task.defineModule = true;

					// Raise a warning if the module already exist
					if ($.module.registry[task.moduleName]) {
						console.warn("$.require.script: " + task.moduleName + ' exists! Using existing module instead.');
					}

					// Use XHR for module assignments
					task.options.xhr = true;
				}

				// Assign path to be resolved
				name = name[1];

				task.module = $.module(task.moduleName);
			}

			// Resolve name to paths

			// Absolute path
			if ($.isUrl(name)) {

				task.url = name;

			// Relative path
			} else if (/^(\/|\.)/.test(name)) {

				task.url = $.uri(task.options.path)
							.toPath(name)
							.toString();

			// Module path
			} else {

				task.url = $.uri(task.options.path)
							.toPath('./' + name + '.' + task.options.extension)
							.toString();

				task.module = $.module(name);
			}
		}

	});

	$.extend(self.task.prototype, {

		start: function() {

			var task = this,
				taskBefore = task.taskBefore;

			// If we're loading a module,
			if (task.module) {

				var moduleState = task.module.state();

				// and the module has been resolved,
				if (moduleState=="resolved") {

					// then resolve task.
					task.resolve();
					return;
				}

				// and the module has been rejected,
				if (moduleState=="rejected") {

					// then reject task.
					task.rejected();
					return;
				}
			}

			// Load script
			// canAsync flag is used to determine whether or not we are on IE.
			if (canAsync || task.options.xhr) {

				task.load();

			// For IE, we will have to prefetch the script using text/cache hack,
			// then reload the script again using text/javascript.
			} else {

				// Load script straightaway if prefetch option is disabled.
				if (!task.options.prefetch) {
					task.load();
					return;
				}

				// Create a text/cache script instance.
				task.script = $.script({
					url: task.url,
					type: "text/cache"
				});

				// When script is prefetched,
				task.script
					.done(

						// IE may still execute script out of sync even though
						// the previous script is injected into the head first,
						(!taskBefore) ?

						function() {

							task.reload();
						}

						:

						// so we will inject our script when the task
						// only when the task before is resolved.
						function() {

							taskBefore.done(function(){

								task.reload();
							});
						}
					);
			}
		},

		reload: function() {

			var task = this;

			// Remove "text/cache" node.
			task.script.remove();

			// Reinsert with "text/javascript" node.
			task.load();
		},

		load: function() {

			var task = this,
				taskBefore = task.taskBefore,
				options = {};

			// Use previously created script instance if exists,
			// else create a new one.
			task.script = self.scripts[task.url] || (function() {

				var script = (task.options.xhr) ?

					// Load script via ajax.
					$.ajax({

						url: task.url,

						dataType: "text"

					}) :

					// Load script using script injection.
					$.script({

						url: task.url,

						type: "text/javascript",

						async: task.options.async,

						timeout: task.batch.options.timeout,

						retry: task.batch.options.retry,

						verbose: task.batch.options.verbose

					});

				return self.scripts[task.url] = script;

			})();

			// At this point, script may be loaded, BUT may yet
			// to be executed under the following conditions:
			// - Module loaded via script injection/xhr.
			// - Script loaded via via xhr.
			task.script
				.done(function(data) {

					var resolveTask = function() {

						// If task loads a module, resolve/reject task only when
						// the module is resolved/rejected as the module itself
						// may perform additional require tasks.
						if (task.module) {

							task.module
								.done(task.resolve)
								.fail(task.reject);

						} else {

							task.resolve();
						}
					};

					if (task.options.xhr) {

						if (task.defineModule) {

							// Create our own module factory
							task.module = $.module(task.moduleName, function() {

								var module = this;

								$.globalEval(data);

								module.resolveWith(data);
							});
						};

						// For XHR, if scripts needs to be executed synchronously
						// a.k.a. ordered script execution, then only eval it when
						// the task before it is resolved.
						if (!task.options.async || taskBefore) {

							taskBefore.done(function() {

								$.globalEval(data);

								resolveTask();

							});

							return;
						}

					};

					resolveTask();

				})
				.fail(function() {

					task.reject();
				});
		}
	});

	return self;

})()
);
/**
 * jquery.require.stylesheet
 * Stylesheet loader plugin for $.require.
 *
 * Part of jquery.require family.
 * https://github.com/jstonne/jquery.require
 *
 * Copyright (c) 2012 Jensen Tonne
 * www.jstonne.com
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

$.require.addLoader('stylesheet', (function() {

	var self = function() {

		var batch = this,
			args = $.makeArray(arguments),
			options,
			names;

		// Expand arguments into its actual definition
		if ($.isPlainObject(args[0])) {
			options = args[0];
			names = args.slice(1);
		} else {
			names = args;
		}

		options = $.extend(
			{},
			self.defaultOptions,
			batch.options,
			options,
			{batch: batch}
		);

		$.each(names, function(i, name) {

			var task = new self.task(name, options),
				existingTask = self.stylesheets[task.url];

			task = existingTask || task;

			batch.addTask(task);

			if (!existingTask) {
				self.stylesheets[task.url] = task;
				task.start();
			}
		});
	};

	$.extend(self, {

		defaultOptions: {
			// Overrides require path.
			path: '',

			extension: 'css',

			// @TODO: XHR loading.
			// Use XHR to load stylesheet. Default: Link injection. @import() for IE.
			xhr: false
		},

		setup: function() {

			$.extend(self.defaultOptions, options);
		},

		stylesheets: {},

		task: function(name, options) {

			var task = $.extend(this, $.Deferred());

			task.name = name;

			task.options = options;

			// Absolute path
			if ($.isUrl(name)) {

				task.url = name;

			// Relative path
			} else if (/^(\/|\.)/.test(name)) {

				task.url = $.uri(task.options.path)
							.toPath(name)
							.toString();

			// Module path
			} else {

				task.url = $.uri(task.options.path)
							.toPath('./' + name + '.' + task.options.extension)
							.toString();
			}

			// Remap task.url to task.options.url
			task.options.url = task.url;
		}

	});

	$.extend(self.task.prototype, {

		start: function() {

			var task = this;

			if ($.stylesheet(task.options)) {

				task.resolve();

			} else {

				task.reject();
			}
		}

	});

	return self;

})()
);
/**
 * jquery.require.template
 * Template loader plugin for $.require.
 *
 * Part of jquery.require family.
 * https://github.com/jstonne/jquery.require
 *
 * Copyright (c) 2012 Jensen Tonne
 * www.jstonne.com
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

$.require.addLoader('template', (function() {

	var self = function() {

		var batch = this,
			args = $.makeArray(arguments),
			options,
			names;

		// Expand arguments into its actual definition
		if ($.isPlainObject(args[0])) {
			options = args[0];
			names = args.slice(1);
		} else {
			names = args;
		}

		options = $.extend(
			{},
			self.defaultOptions,
			batch.options,
			options,
			{batch: batch}
		);

		$.each(names, function(i, name) {

			var task = new self.task(name, options);

			batch.addTask(task);

			task.start();
		});

	};

	$.extend(self, {

		defaultOptions: {
			// Overrides require path.
			path: '',

			extension: 'htm'
		},

		setup: function() {

			$.extend(self.defaultOptions, options);
		},

		loaders: {},

		task: function(name, options, taskBefore) {

			var task = $.extend(this, $.Deferred());

			task.name = name;

			task.options = options;

			// Template definition
			if ($.isArray(name)) {

				task.name = name[0];

				// Assign path to be resolved
				name = name[1];
			}

			// Absolute path
			if ($.isUrl(name)) {

				task.url = name;

			// Relative path
			} else if (/^(\/|\.)/.test(name)) {

				task.url = $.uri(task.options.path)
							.toPath(name)
							.toString();

			// Template module
			} else {

				task.url = $.uri(task.options.path)
							.toPath('./' + name + '.' + task.options.extension)
							.toString();
			}
		}

	});

	$.extend(self.task.prototype, {

		start: function() {

			var task = this,
				taskBefore = task.taskBefore;

			task.loader = self.loaders[task.url] || (function() {

				var loader = $.Ajax({

					url: task.url,

					dataType: "text"
				});

				return self.loaders[task.url] = loader;

			})();

			task.loader
				.done(function(content) {

					$.template(task.name, content);

					task.resolve();
				})
				.fail(function() {

					task.reject();

				});
		}
	});

	return self;

})()
);
/**
 * jquery.require.language
 * Language loader plugin for $.require.
 *
 * Part of foundry-module/require family.
 * https://github.com/foundry-modules/require
 *
 * Copyright (c) 2011 Jason Ramos
 * www.stackideas.com
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */


$.require.addLoader('language', (function() {

	var self = function() {

		var batch = this,
			args = $.makeArray(arguments),
			options,
			names;

		// Expand arguments into its actual definition
		if ($.isPlainObject(args[0])) {
			options = args[0];
			names = args.slice(1);
		} else {
			names = args;
		}

		options = $.extend(
			{},
			self.defaultOptions,
			batch.options,
			options,
			{batch: batch}
		);

		var task = new self.task(names, options);

		batch.addTask(task);

		// Prevent parallel ajax call when chained
		// with other ajax loaders.
		setTimeout(function(){
			task.start();
		}, 1000);

	};

	$.extend(self, {

		defaultOptions: {
			// Overrides require path.
			path: ''
		},

		setup: function() {

			$.extend(self.defaultOptions, options);
		},

		loaders: {},

		task: function(names, options) {

			var task = $.extend(this, $.Deferred());

			task.name = names.join(',');

			task.options = options;

			task.url = options.path;

			task.languages = names;
		}

	});

	$.extend(self.task.prototype, {

		start: function() {

			var task = this,
				taskBefore = task.taskBefore;

			task.loader = self.loaders[task.name] || (function() {

				var loader = $.Ajax({

					url: task.url,

					type: "POST",

					data: {
						languages: task.languages
					}
				});

				return self.loaders[task.name] = loader;

			})();

			task.loader
				.done(function(languages) {

					$.language.add(languages);

					task.resolve();
				})
				.fail(function() {

					task.reject();

				});
		}
	});

	return self;

})()
);
/**
 * jquery.require.library
 * Foundry script loader.
 *
 * Copyright (c) 2011 Jason Ramos
 * www.stackideas.com
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

$.require.addLoader('library', function() {

	var batch = this,
		args = $.makeArray(arguments),
		options = {},
		names;

	// Expand arguments into its actual definition
	if ($.isPlainObject(args[0])) {
		options = args[0];
		names = args.slice(1);
	} else {
		names = args;
	}

	$.extend(options, {
		path: $.scriptPath
	});

	return batch.script.apply(batch, [options].concat(names));

});
/**
 * jquery.require.stylesheet
 * Stylesheet loader plugin for $.require.
 *
 * Part of jquery.require family.
 * https://github.com/jstonne/jquery.require
 *
 * Copyright (c) 2012 Jensen Tonne
 * www.jstonne.com
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 */

$.require.addLoader('image', (function() {

	var self = function() {

		var batch = this,
			args = $.makeArray(arguments),
			options,
			names;

		// Expand arguments into its actual definition
		if ($.isPlainObject(args[0])) {
			options = args[0];
			names = args.slice(1);
		} else {
			names = args;
		}

		options = $.extend(
			{},
			self.defaultOptions,
			batch.options,
			options,
			{batch: batch}
		);

		$.each(names, function(i, name) {

			var task = new self.task(name, options),
				existingTask = self.images[task.url];

			task = existingTask || task;

			batch.addTask(task);

			if (!existingTask) {
				self.images[task.url] = task;
				task.start();
			}
		});
	};

	$.extend(self, {

		defaultOptions: {
			// Overrides require path.
			path: ''
		},

		setup: function() {

			$.extend(self.defaultOptions, options);
		},

		images: {},

		task: function(name, options) {

			var task = $.extend(this, $.Deferred());

			task.name = name;

			task.options = options;

			// Absolute path
			if ($.isUrl(name)) {

				task.url = name;

			// Relative path
			} else if (/^(\/|\.)/.test(name)) {

				task.url = $.uri(task.options.path)
							.toPath(name)
							.toString();

			// Module path
			} else {

				task.url = $.uri(task.options.path)
							.toPath('./' + name)
							.toString();
			}

			// Remap task.url to task.options.url
			task.options.url = task.url;
		}

	});

	$.extend(self.task.prototype, {

		start: function() {

			var task = this;

			task.image = $(new Image())
							.load(function(){
								task.resolve();
							})
							.error(function(){
								task.reject();
							})
							.attr("src", task.options.url);
		}

	});

	return self;

})()
);

}); // dispatch: end