From d202fa7c795c8d91015aff0101a5f4fb1513d2ec Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Sun, 5 Oct 2014 23:49:05 +0800 Subject: [PATCH] ember.js v1.8.0-beta.4 --- ajax/libs/ember.js/1.8.0-beta.4/ember.js | 49493 ++++++++++++++++ ajax/libs/ember.js/1.8.0-beta.4/ember.min.js | 12 + ajax/libs/ember.js/1.8.0-beta.4/ember.prod.js | 48944 +++++++++++++++ 3 files changed, 98449 insertions(+) create mode 100644 ajax/libs/ember.js/1.8.0-beta.4/ember.js create mode 100644 ajax/libs/ember.js/1.8.0-beta.4/ember.min.js create mode 100644 ajax/libs/ember.js/1.8.0-beta.4/ember.prod.js diff --git a/ajax/libs/ember.js/1.8.0-beta.4/ember.js b/ajax/libs/ember.js/1.8.0-beta.4/ember.js new file mode 100644 index 000000000..625b1f6bd --- /dev/null +++ b/ajax/libs/ember.js/1.8.0-beta.4/ember.js @@ -0,0 +1,49493 @@ +/*! + * @overview Ember - JavaScript Application Framework + * @copyright Copyright 2011-2014 Tilde Inc. and contributors + * Portions Copyright 2006-2011 Strobe Inc. + * Portions Copyright 2008-2011 Apple Inc. All rights reserved. + * @license Licensed under MIT license + * See https://raw.github.com/emberjs/ember.js/master/LICENSE + * @version 1.8.0-beta.4 + */ + +(function() { +var define, requireModule, require, requirejs, Ember; + +(function() { + Ember = this.Ember = this.Ember || {}; + if (typeof Ember === 'undefined') { Ember = {}; }; + + if (typeof Ember.__loader === 'undefined') { + var registry = {}, seen = {}; + + define = function(name, deps, callback) { + registry[name] = { deps: deps, callback: callback }; + }; + + requirejs = require = requireModule = function(name) { + if (seen.hasOwnProperty(name)) { return seen[name]; } + seen[name] = {}; + + if (!registry[name]) { + throw new Error("Could not find module " + name); + } + + var mod = registry[name]; + var deps = mod.deps; + var callback = mod.callback; + var reified = []; + var exports; + + for (var i=0, l=deps.length; i 3) { + args = new Array(length - 3); + for (var i = 3; i < length; i++) { + args[i-3] = arguments[i]; + } + } else { + args = undefined; + } + + if (!this.currentInstance) { createAutorun(this); } + return this.currentInstance.schedule(queueName, target, method, args, false, stack); + }, + + deferOnce: function(queueName, target, method /* , args */) { + if (!method) { + method = target; + target = null; + } + + if (isString(method)) { + method = target[method]; + } + + var stack = this.DEBUG ? new Error() : undefined; + var length = arguments.length; + var args; + + if (length > 3) { + args = new Array(length - 3); + for (var i = 3; i < length; i++) { + args[i-3] = arguments[i]; + } + } else { + args = undefined; + } + + if (!this.currentInstance) { + createAutorun(this); + } + return this.currentInstance.schedule(queueName, target, method, args, true, stack); + }, + + setTimeout: function() { + var l = arguments.length; + var args = new Array(l); + + for (var x = 0; x < l; x++) { + args[x] = arguments[x]; + } + + var length = args.length, + method, wait, target, + methodOrTarget, methodOrWait, methodOrArgs; + + if (length === 0) { + return; + } else if (length === 1) { + method = args.shift(); + wait = 0; + } else if (length === 2) { + methodOrTarget = args[0]; + methodOrWait = args[1]; + + if (isFunction(methodOrWait) || isFunction(methodOrTarget[methodOrWait])) { + target = args.shift(); + method = args.shift(); + wait = 0; + } else if (isCoercableNumber(methodOrWait)) { + method = args.shift(); + wait = args.shift(); + } else { + method = args.shift(); + wait = 0; + } + } else { + var last = args[args.length - 1]; + + if (isCoercableNumber(last)) { + wait = args.pop(); + } else { + wait = 0; + } + + methodOrTarget = args[0]; + methodOrArgs = args[1]; + + if (isFunction(methodOrArgs) || (isString(methodOrArgs) && + methodOrTarget !== null && + methodOrArgs in methodOrTarget)) { + target = args.shift(); + method = args.shift(); + } else { + method = args.shift(); + } + } + + var executeAt = now() + parseInt(wait, 10); + + if (isString(method)) { + method = target[method]; + } + + var onError = getOnError(this.options); + + function fn() { + if (onError) { + try { + method.apply(target, args); + } catch (e) { + onError(e); + } + } else { + method.apply(target, args); + } + } + + // find position to insert + var i = searchTimer(executeAt, this._timers); + + this._timers.splice(i, 0, executeAt, fn); + + updateLaterTimer(this, executeAt, wait); + + return fn; + }, + + throttle: function(target, method /* , args, wait, [immediate] */) { + var backburner = this; + var args = arguments; + var immediate = pop.call(args); + var wait, throttler, index, timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = true; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + + index = findThrottler(target, method, this._throttlers); + if (index > -1) { return this._throttlers[index]; } // throttled + + timer = global.setTimeout(function() { + if (!immediate) { + backburner.run.apply(backburner, args); + } + var index = findThrottler(target, method, backburner._throttlers); + if (index > -1) { + backburner._throttlers.splice(index, 1); + } + }, wait); + + if (immediate) { + this.run.apply(this, args); + } + + throttler = [target, method, timer]; + + this._throttlers.push(throttler); + + return throttler; + }, + + debounce: function(target, method /* , args, wait, [immediate] */) { + var backburner = this; + var args = arguments; + var immediate = pop.call(args); + var wait, index, debouncee, timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = false; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + // Remove debouncee + index = findDebouncee(target, method, this._debouncees); + + if (index > -1) { + debouncee = this._debouncees[index]; + this._debouncees.splice(index, 1); + clearTimeout(debouncee[2]); + } + + timer = global.setTimeout(function() { + if (!immediate) { + backburner.run.apply(backburner, args); + } + var index = findDebouncee(target, method, backburner._debouncees); + if (index > -1) { + backburner._debouncees.splice(index, 1); + } + }, wait); + + if (immediate && index === -1) { + backburner.run.apply(backburner, args); + } + + debouncee = [ + target, + method, + timer + ]; + + backburner._debouncees.push(debouncee); + + return debouncee; + }, + + cancelTimers: function() { + var clearItems = function(item) { + clearTimeout(item[2]); + }; + + each(this._throttlers, clearItems); + this._throttlers = []; + + each(this._debouncees, clearItems); + this._debouncees = []; + + if (this._laterTimer) { + clearTimeout(this._laterTimer); + this._laterTimer = null; + } + this._timers = []; + + if (this._autorun) { + clearTimeout(this._autorun); + this._autorun = null; + } + }, + + hasTimers: function() { + return !!this._timers.length || !!this._debouncees.length || !!this._throttlers.length || this._autorun; + }, + + cancel: function(timer) { + var timerType = typeof timer; + + if (timer && timerType === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce + return timer.queue.cancel(timer); + } else if (timerType === 'function') { // we're cancelling a setTimeout + for (var i = 0, l = this._timers.length; i < l; i += 2) { + if (this._timers[i + 1] === timer) { + this._timers.splice(i, 2); // remove the two elements + if (i === 0) { + if (this._laterTimer) { // Active timer? Then clear timer and reset for future timer + clearTimeout(this._laterTimer); + this._laterTimer = null; + } + if (this._timers.length > 0) { // Update to next available timer when available + updateLaterTimer(this, this._timers[0], this._timers[0] - now()); + } + } + return true; + } + } + } else if (Object.prototype.toString.call(timer) === "[object Array]"){ // we're cancelling a throttle or debounce + return this._cancelItem(findThrottler, this._throttlers, timer) || + this._cancelItem(findDebouncee, this._debouncees, timer); + } else { + return; // timer was null or not a timer + } + }, + + _cancelItem: function(findMethod, array, timer){ + var item, index; + + if (timer.length < 3) { return false; } + + index = findMethod(timer[0], timer[1], array); + + if (index > -1) { + + item = array[index]; + + if (item[2] === timer[2]) { + array.splice(index, 1); + clearTimeout(timer[2]); + return true; + } + } + + return false; + } + }; + + Backburner.prototype.schedule = Backburner.prototype.defer; + Backburner.prototype.scheduleOnce = Backburner.prototype.deferOnce; + Backburner.prototype.later = Backburner.prototype.setTimeout; + + if (needsIETryCatchFix) { + var originalRun = Backburner.prototype.run; + Backburner.prototype.run = wrapInTryCatch(originalRun); + + var originalEnd = Backburner.prototype.end; + Backburner.prototype.end = wrapInTryCatch(originalEnd); + } + + function getOnError(options) { + return options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + } + + function createAutorun(backburner) { + backburner.begin(); + backburner._autorun = global.setTimeout(function() { + backburner._autorun = null; + backburner.end(); + }); + } + + function updateLaterTimer(backburner, executeAt, wait) { + var n = now(); + if (!backburner._laterTimer || executeAt < backburner._laterTimerExpiresAt || backburner._laterTimerExpiresAt < n) { + + if (backburner._laterTimer) { + // Clear when: + // - Already expired + // - New timer is earlier + clearTimeout(backburner._laterTimer); + + if (backburner._laterTimerExpiresAt < n) { // If timer was never triggered + // Calculate the left-over wait-time + wait = Math.max(0, executeAt - n); + } + } + + backburner._laterTimer = global.setTimeout(function() { + backburner._laterTimer = null; + backburner._laterTimerExpiresAt = null; + executeTimers(backburner); + }, wait); + + backburner._laterTimerExpiresAt = n + wait; + } + } + + function executeTimers(backburner) { + var n = now(); + var fns, i, l; + + backburner.run(function() { + i = searchTimer(n, backburner._timers); + + fns = backburner._timers.splice(0, i); + + for (i = 1, l = fns.length; i < l; i += 2) { + backburner.schedule(backburner.options.defaultQueue, null, fns[i]); + } + }); + + if (backburner._timers.length) { + updateLaterTimer(backburner, backburner._timers[0], backburner._timers[0] - n); + } + } + + function findDebouncee(target, method, debouncees) { + return findItem(target, method, debouncees); + } + + function findThrottler(target, method, throttlers) { + return findItem(target, method, throttlers); + } + + function findItem(target, method, collection) { + var item; + var index = -1; + + for (var i = 0, l = collection.length; i < l; i++) { + item = collection[i]; + if (item[0] === target && item[1] === method) { + index = i; + break; + } + } + + return index; + } + + __exports__["default"] = Backburner; + }); +define("backburner.umd", + ["./backburner"], + function(__dependency1__) { + "use strict"; + var Backburner = __dependency1__["default"]; + + /* global define:true module:true window: true */ + if (typeof define === 'function' && define.amd) { + define(function() { return Backburner; }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = Backburner; + } else if (typeof this !== 'undefined') { + this['Backburner'] = Backburner; + } + }); +define("backburner/binary-search", + ["exports"], + function(__exports__) { + "use strict"; + __exports__["default"] = function binarySearch(time, timers) { + var start = 0; + var end = timers.length - 2; + var middle, l; + + while (start < end) { + // since timers is an array of pairs 'l' will always + // be an integer + l = (end - start) / 2; + + // compensate for the index in case even number + // of pairs inside timers + middle = start + l - (l % 2); + + if (time >= timers[middle]) { + start = middle + 2; + } else { + end = middle; + } + } + + return (time >= timers[start]) ? start + 2 : start; + } + }); +define("backburner/deferred-action-queues", + ["./utils","./queue","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var each = __dependency1__.each; + var isString = __dependency1__.isString; + var Queue = __dependency2__["default"]; + + function DeferredActionQueues(queueNames, options) { + var queues = this.queues = {}; + this.queueNames = queueNames = queueNames || []; + + this.options = options; + + each(queueNames, function(queueName) { + queues[queueName] = new Queue(queueName, options[queueName], options); + }); + } + + function noSuchQueue(name) { + throw new Error("You attempted to schedule an action in a queue (" + name + ") that doesn't exist"); + } + + DeferredActionQueues.prototype = { + schedule: function(name, target, method, args, onceFlag, stack) { + var queues = this.queues; + var queue = queues[name]; + + if (!queue) { noSuchQueue(name); } + + if (onceFlag) { + return queue.pushUnique(target, method, args, stack); + } else { + return queue.push(target, method, args, stack); + } + }, + + invoke: function(target, method, args, _, _errorRecordedForStack) { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + }, + + invokeWithOnError: function(target, method, args, onError, errorRecordedForStack) { + try { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + } catch(error) { + onError(error, errorRecordedForStack); + } + }, + + flush: function() { + var queues = this.queues; + var queueNames = this.queueNames; + var queueName, queue, queueItems, priorQueueNameIndex; + var queueNameIndex = 0; + var numberOfQueues = queueNames.length; + var options = this.options; + var onError = options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + var invoke = onError ? this.invokeWithOnError : this.invoke; + + while (queueNameIndex < numberOfQueues) { + queueName = queueNames[queueNameIndex]; + queue = queues[queueName]; + queueItems = queue._queueBeingFlushed = queue._queue.slice(); + queue._queue = []; + queue.targetQueues = Object.create(null); + + var queueOptions = queue.options; // TODO: write a test for this + var before = queueOptions && queueOptions.before; + var after = queueOptions && queueOptions.after; + var target, method, args, errorRecordedForStack; + var queueIndex = 0; + var numberOfQueueItems = queueItems.length; + + if (numberOfQueueItems && before) { + before(); + } + + while (queueIndex < numberOfQueueItems) { + target = queueItems[queueIndex]; + method = queueItems[queueIndex+1]; + args = queueItems[queueIndex+2]; + errorRecordedForStack = queueItems[queueIndex+3]; // Debugging assistance + + // + + if (isString(method)) { + method = target[method]; + } + + // method could have been nullified / canceled during flush + if (method) { + // + // ** Attention intrepid developer ** + // + // To find out the stack of this task when it was scheduled onto + // the run loop, add the following to your app.js: + // + // Ember.run.backburner.DEBUG = true; // NOTE: This slows your app, don't leave it on in production. + // + // Once that is in place, when you are at a breakpoint and navigate + // here in the stack explorer, you can look at `errorRecordedForStack.stack`, + // which will be the captured stack when this job was scheduled. + // + invoke(target, method, args, onError, errorRecordedForStack); + } + + queueIndex += 4; + } + + queue._queueBeingFlushed = null; + if (numberOfQueueItems && after) { + after(); + } + + if ((priorQueueNameIndex = indexOfPriorQueueWithActions(this, queueNameIndex)) !== -1) { + queueNameIndex = priorQueueNameIndex; + } else { + queueNameIndex++; + } + } + } + }; + + function indexOfPriorQueueWithActions(daq, currentQueueIndex) { + var queueName, queue; + + for (var i = 0, l = currentQueueIndex; i <= l; i++) { + queueName = daq.queueNames[i]; + queue = daq.queues[queueName]; + if (queue._queue.length) { return i; } + } + + return -1; + } + + __exports__["default"] = DeferredActionQueues; + }); +define("backburner/platform", + ["exports"], + function(__exports__) { + "use strict"; + // In IE 6-8, try/finally doesn't work without a catch. + // Unfortunately, this is impossible to test for since wrapping it in a parent try/catch doesn't trigger the bug. + // This tests for another broken try/catch behavior that only exhibits in the same versions of IE. + var needsIETryCatchFix = (function(e,x){ + try{ x(); } + catch(e) { } // jshint ignore:line + return !!e; + })(); + __exports__.needsIETryCatchFix = needsIETryCatchFix; + }); +define("backburner/queue", + ["exports"], + function(__exports__) { + "use strict"; + function Queue(name, options, globalOptions) { + this.name = name; + this.globalOptions = globalOptions || {}; + this.options = options; + this._queue = []; + this.targetQueues = Object.create(null); + this._queueBeingFlushed = undefined; + } + + Queue.prototype = { + push: function(target, method, args, stack) { + var queue = this._queue; + queue.push(target, method, args, stack); + + return { + queue: this, + target: target, + method: method + }; + }, + + pushUniqueWithoutGuid: function(target, method, args, stack) { + var queue = this._queue; + + for (var i = 0, l = queue.length; i < l; i += 4) { + var currentTarget = queue[i]; + var currentMethod = queue[i+1]; + + if (currentTarget === target && currentMethod === method) { + queue[i+2] = args; // replace args + queue[i+3] = stack; // replace stack + return; + } + } + + queue.push(target, method, args, stack); + }, + + targetQueue: function(targetQueue, target, method, args, stack) { + var queue = this._queue; + + for (var i = 0, l = targetQueue.length; i < l; i += 4) { + var currentMethod = targetQueue[i]; + var currentIndex = targetQueue[i + 1]; + + if (currentMethod === method) { + queue[currentIndex + 2] = args; // replace args + queue[currentIndex + 3] = stack; // replace stack + return; + } + } + + targetQueue.push( + method, + queue.push(target, method, args, stack) - 4 + ); + }, + + pushUniqueWithGuid: function(guid, target, method, args, stack) { + var hasLocalQueue = this.targetQueues[guid]; + + if (hasLocalQueue) { + this.targetQueue(hasLocalQueue, target, method, args, stack); + } else { + this.targetQueues[guid] = [ + method, + this._queue.push(target, method, args, stack) - 4 + ]; + } + + return { + queue: this, + target: target, + method: method + }; + }, + + pushUnique: function(target, method, args, stack) { + var queue = this._queue, currentTarget, currentMethod, i, l; + var KEY = this.globalOptions.GUID_KEY; + + if (target && KEY) { + var guid = target[KEY]; + if (guid) { + return this.pushUniqueWithGuid(guid, target, method, args, stack); + } + } + + this.pushUniqueWithoutGuid(target, method, args, stack); + + return { + queue: this, + target: target, + method: method + }; + }, + + // TODO: remove me, only being used for Ember.run.sync + flush: function() { + var queue = this._queue; + var globalOptions = this.globalOptions; + var options = this.options; + var before = options && options.before; + var after = options && options.after; + var onError = globalOptions.onError || (globalOptions.onErrorTarget && globalOptions.onErrorTarget[globalOptions.onErrorMethod]); + var target, method, args, stack, i, l = queue.length; + + this.targetQueues = Object.create(null); + + if (l && before) { before(); } + for (i = 0; i < l; i += 4) { + target = queue[i]; + method = queue[i+1]; + args = queue[i+2]; + stack = queue[i+3]; // Debugging assistance + + // TODO: error handling + if (args && args.length > 0) { + if (onError) { + try { + method.apply(target, args); + } catch (e) { + onError(e); + } + } else { + method.apply(target, args); + } + } else { + if (onError) { + try { + method.call(target); + } catch(e) { + onError(e); + } + } else { + method.call(target); + } + } + } + if (l && after) { after(); } + + // check if new items have been added + if (queue.length > l) { + this._queue = queue.slice(l); + this.flush(); + } else { + this._queue.length = 0; + } + }, + + cancel: function(actionToCancel) { + var queue = this._queue, currentTarget, currentMethod, i, l; + var target = actionToCancel.target; + var method = actionToCancel.method; + var GUID_KEY = this.globalOptions.GUID_KEY; + + if (GUID_KEY && this.targetQueues && target) { + var targetQueue = this.targetQueues[target[GUID_KEY]]; + + if (targetQueue) { + for (i = 0, l = targetQueue.length; i < l; i++) { + if (targetQueue[i] === method) { + targetQueue.splice(i, 1); + } + } + } + } + + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && + currentMethod === method) { + queue.splice(i, 4); + return true; + } + } + + // if not found in current queue + // could be in the queue that is being flushed + queue = this._queueBeingFlushed; + if (!queue) { + return; + } + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && + currentMethod === method) { + // don't mess with array during flush + // just nullify the method + queue[i+1] = null; + return true; + } + } + } + }; + + __exports__["default"] = Queue; + }); +define("backburner/utils", + ["exports"], + function(__exports__) { + "use strict"; + var NUMBER = /\d+/; + + function each(collection, callback) { + for (var i = 0; i < collection.length; i++) { + callback(collection[i]); + } + } + + __exports__.each = each;// Date.now is not available in browsers < IE9 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility + var now = Date.now || function() { return new Date().getTime(); }; + __exports__.now = now; + function isString(suspect) { + return typeof suspect === 'string'; + } + + __exports__.isString = isString;function isFunction(suspect) { + return typeof suspect === 'function'; + } + + __exports__.isFunction = isFunction;function isNumber(suspect) { + return typeof suspect === 'number'; + } + + __exports__.isNumber = isNumber;function isCoercableNumber(number) { + return isNumber(number) || NUMBER.test(number); + } + + __exports__.isCoercableNumber = isCoercableNumber;function wrapInTryCatch(func) { + return function () { + try { + return func.apply(this, arguments); + } catch (e) { + throw e; + } + }; + } + + __exports__.wrapInTryCatch = wrapInTryCatch; + }); +define("calculateVersion", + [], + function() { + "use strict"; + 'use strict'; + + var fs = require('fs'); + var path = require('path'); + + module.exports = function () { + var packageVersion = require('../package.json').version; + var output = [packageVersion]; + var gitPath = path.join(__dirname,'..','.git'); + var headFilePath = path.join(gitPath, 'HEAD'); + + if (packageVersion.indexOf('+') > -1) { + try { + if (fs.existsSync(headFilePath)) { + var headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'}); + var branchName = headFile.split('/').slice(-1)[0].trim(); + var refPath = headFile.split(' ')[1]; + var branchSHA; + + if (refPath) { + var branchPath = path.join(gitPath, refPath.trim()); + branchSHA = fs.readFileSync(branchPath); + } else { + branchSHA = branchName; + } + + output.push(branchSHA.slice(0,10)); + } + } catch (err) { + console.error(err.stack); + } + return output.join('.'); + } else { + return packageVersion; + } + }; + }); +define("container", + ["container/container","exports"], + function(__dependency1__, __exports__) { + "use strict"; + /* + Public api for the container is still in flux. + The public api, specified on the application namespace should be considered the stable api. + // @module container + @private + */ + + /* + Flag to enable/disable model factory injections (disabled by default) + If model factory injections are enabled, models should not be + accessed globally (only through `container.lookupFactory('model:modelName'))`); + */ + Ember.MODEL_FACTORY_INJECTIONS = false; + + if (Ember.ENV && typeof Ember.ENV.MODEL_FACTORY_INJECTIONS !== 'undefined') { + Ember.MODEL_FACTORY_INJECTIONS = !!Ember.ENV.MODEL_FACTORY_INJECTIONS; + } + + + var Container = __dependency1__["default"]; + + __exports__["default"] = Container; + }); +define("container/container", + ["ember-metal/core","ember-metal/keys","ember-metal/dictionary","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var emberKeys = __dependency2__["default"]; + var dictionary = __dependency3__["default"]; + + // A lightweight container that helps to assemble and decouple components. + // Public api for the container is still in flux. + // The public api, specified on the application namespace should be considered the stable api. + function Container(parent) { + this.parent = parent; + this.children = []; + + this.resolver = parent && parent.resolver || function() {}; + + this.registry = dictionary(parent ? parent.registry : null); + this.cache = dictionary(parent ? parent.cache : null); + this.factoryCache = dictionary(parent ? parent.factoryCache : null); + this.resolveCache = dictionary(parent ? parent.resolveCache : null); + this.typeInjections = dictionary(parent ? parent.typeInjections : null); + this.injections = dictionary(null); + this.normalizeCache = dictionary(null); + + this.factoryTypeInjections = dictionary(parent ? parent.factoryTypeInjections : null); + this.factoryInjections = dictionary(null); + + this._options = dictionary(parent ? parent._options : null); + this._typeOptions = dictionary(parent ? parent._typeOptions : null); + } + + Container.prototype = { + + /** + @property parent + @type Container + @default null + */ + parent: null, + + /** + @property children + @type Array + @default [] + */ + children: null, + + /** + @property resolver + @type function + */ + resolver: null, + + /** + @property registry + @type InheritingDict + */ + registry: null, + + /** + @property cache + @type InheritingDict + */ + cache: null, + + /** + @property typeInjections + @type InheritingDict + */ + typeInjections: null, + + /** + @property injections + @type Object + @default {} + */ + injections: null, + + /** + @private + + @property _options + @type InheritingDict + @default null + */ + _options: null, + + /** + @private + + @property _typeOptions + @type InheritingDict + */ + _typeOptions: null, + + /** + Returns a new child of the current container. These children are configured + to correctly inherit from the current container. + + @method child + @return {Container} + */ + child: function() { + var container = new Container(this); + this.children.push(container); + return container; + }, + + /** + Sets a key-value pair on the current container. If a parent container, + has the same key, once set on a child, the parent and child will diverge + as expected. + + @method set + @param {Object} object + @param {String} key + @param {any} value + */ + set: function(object, key, value) { + object[key] = value; + }, + + /** + Registers a factory for later injection. + + Example: + + ```javascript + var container = new Container(); + + container.register('model:user', Person, {singleton: false }); + container.register('fruit:favorite', Orange); + container.register('communication:main', Email, {singleton: false}); + ``` + + @method register + @param {String} fullName + @param {Function} factory + @param {Object} options + */ + register: function(fullName, factory, options) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + + if (factory === undefined) { + throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`'); + } + + var normalizedName = this.normalize(fullName); + + if (normalizedName in this.cache) { + throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.'); + } + + this.registry[normalizedName] = factory; + this._options[normalizedName] = (options || {}); + }, + + /** + Unregister a fullName + + ```javascript + var container = new Container(); + container.register('model:user', User); + + container.lookup('model:user') instanceof User //=> true + + container.unregister('model:user') + container.lookup('model:user') === undefined //=> true + ``` + + @method unregister + @param {String} fullName + */ + unregister: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + + var normalizedName = this.normalize(fullName); + + delete this.registry[normalizedName]; + delete this.cache[normalizedName]; + delete this.factoryCache[normalizedName]; + delete this.resolveCache[normalizedName]; + delete this._options[normalizedName]; + }, + + /** + Given a fullName return the corresponding factory. + + By default `resolve` will retrieve the factory from + its container's registry. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + container.resolve('api:twitter') // => Twitter + ``` + + Optionally the container can be provided with a custom resolver. + If provided, `resolve` will first provide the custom resolver + the opportunity to resolve the fullName, otherwise it will fallback + to the registry. + + ```javascript + var container = new Container(); + container.resolver = function(fullName) { + // lookup via the module system of choice + }; + + // the twitter factory is added to the module system + container.resolve('api:twitter') // => Twitter + ``` + + @method resolve + @param {String} fullName + @return {Function} fullName's factory + */ + resolve: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return resolve(this, this.normalize(fullName)); + }, + + /** + A hook that can be used to describe how the resolver will + attempt to find the factory. + + For example, the default Ember `.describe` returns the full + class name (including namespace) where Ember's resolver expects + to find the `fullName`. + + @method describe + @param {String} fullName + @return {string} described fullName + */ + describe: function(fullName) { + return fullName; + }, + + /** + A hook to enable custom fullName normalization behaviour + + @method normalizeFullName + @param {String} fullName + @return {string} normalized fullName + */ + normalizeFullName: function(fullName) { + return fullName; + }, + + /** + normalize a fullName based on the applications conventions + + @method normalize + @param {String} fullName + @return {string} normalized fullName + */ + normalize: function(fullName) { + return this.normalizeCache[fullName] || ( + this.normalizeCache[fullName] = this.normalizeFullName(fullName) + ); + }, + + /** + @method makeToString + + @param {any} factory + @param {string} fullName + @return {function} toString function + */ + makeToString: function(factory, fullName) { + return factory.toString(); + }, + + /** + Given a fullName return a corresponding instance. + + The default behaviour is for lookup to return a singleton instance. + The singleton is scoped to the container, allowing multiple containers + to all have their own locally scoped singletons. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter'); + + twitter instanceof Twitter; // => true + + // by default the container will return singletons + var twitter2 = container.lookup('api:twitter'); + twitter2 instanceof Twitter; // => true + + twitter === twitter2; //=> true + ``` + + If singletons are not wanted an optional flag can be provided at lookup. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter', { singleton: false }); + var twitter2 = container.lookup('api:twitter', { singleton: false }); + + twitter === twitter2; //=> false + ``` + + @method lookup + @param {String} fullName + @param {Object} options + @return {any} + */ + lookup: function(fullName, options) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return lookup(this, this.normalize(fullName), options); + }, + + /** + Given a fullName return the corresponding factory. + + @method lookupFactory + @param {String} fullName + @return {any} + */ + lookupFactory: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return factoryFor(this, this.normalize(fullName)); + }, + + /** + Given a fullName check if the container is aware of its factory + or singleton instance. + + @method has + @param {String} fullName + @return {Boolean} + */ + has: function(fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + return has(this, this.normalize(fullName)); + }, + + /** + Allow registering options for all factories of a type. + + ```javascript + var container = new Container(); + + // if all of type `connection` must not be singletons + container.optionsForType('connection', { singleton: false }); + + container.register('connection:twitter', TwitterConnection); + container.register('connection:facebook', FacebookConnection); + + var twitter = container.lookup('connection:twitter'); + var twitter2 = container.lookup('connection:twitter'); + + twitter === twitter2; // => false + + var facebook = container.lookup('connection:facebook'); + var facebook2 = container.lookup('connection:facebook'); + + facebook === facebook2; // => false + ``` + + @method optionsForType + @param {String} type + @param {Object} options + */ + optionsForType: function(type, options) { + if (this.parent) { illegalChildOperation('optionsForType'); } + + this._typeOptions[type] = options; + }, + + /** + @method options + @param {String} type + @param {Object} options + */ + options: function(type, options) { + this.optionsForType(type, options); + }, + + /** + Used only via `injection`. + + Provides a specialized form of injection, specifically enabling + all objects of one type to be injected with a reference to another + object. + + For example, provided each object of type `controller` needed a `router`. + one would do the following: + + ```javascript + var container = new Container(); + + container.register('router:main', Router); + container.register('controller:user', UserController); + container.register('controller:post', PostController); + + container.typeInjection('controller', 'router', 'router:main'); + + var user = container.lookup('controller:user'); + var post = container.lookup('controller:post'); + + user.router instanceof Router; //=> true + post.router instanceof Router; //=> true + + // both controllers share the same router + user.router === post.router; //=> true + ``` + + @private + @method typeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + typeInjection: function(type, property, fullName) { + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + + if (this.parent) { illegalChildOperation('typeInjection'); } + + var fullNameType = fullName.split(':')[0]; + if (fullNameType === type) { + throw new Error('Cannot inject a `' + fullName + '` on other ' + type + '(s). Register the `' + fullName + '` as a different type and perform the typeInjection.'); + } + + addTypeInjection(this.typeInjections, type, property, fullName); + }, + + /** + Defines injection rules. + + These rules are used to inject dependencies onto objects when they + are instantiated. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('source:main', Source); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another fullName + // eg. each user model gets a post model + container.injection('model:user', 'post', 'model:post'); + + // injecting one fullName on another type + container.injection('model', 'source', 'source:main'); + + var user = container.lookup('model:user'); + var post = container.lookup('model:post'); + + user.source instanceof Source; //=> true + post.source instanceof Source; //=> true + + user.post instanceof Post; //=> true + + // and both models share the same source + user.source === post.source; //=> true + ``` + + @method injection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + injection: function(fullName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + validateFullName(injectionName); + var normalizedInjectionName = this.normalize(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.typeInjection(fullName, property, normalizedInjectionName); + } + + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + var normalizedName = this.normalize(fullName); + + if (this.cache[normalizedName]) { + throw new Error("Attempted to register an injection for a type that has already been looked up. ('" + normalizedName + "', '" + property + "', '" + injectionName + "')"); + } + addInjection(this.injections, normalizedName, property, normalizedInjectionName); + }, + + + /** + Used only via `factoryInjection`. + + Provides a specialized form of injection, specifically enabling + all factory of one type to be injected with a reference to another + object. + + For example, provided each factory of type `model` needed a `store`. + one would do the following: + + ```javascript + var container = new Container(); + + container.register('store:main', SomeStore); + + container.factoryTypeInjection('model', 'store', 'store:main'); + + var store = container.lookup('store:main'); + var UserFactory = container.lookupFactory('model:user'); + + UserFactory.store instanceof SomeStore; //=> true + ``` + + @private + @method factoryTypeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + factoryTypeInjection: function(type, property, fullName) { + if (this.parent) { illegalChildOperation('factoryTypeInjection'); } + + addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName)); + }, + + /** + Defines factory injection rules. + + Similar to regular injection rules, but are run against factories, via + `Container#lookupFactory`. + + These rules are used to inject objects onto factories when they + are looked up. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('store:main', Store); + container.register('store:secondary', OtherStore); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another type + container.factoryInjection('model', 'store', 'store:main'); + + // injecting one fullName on another fullName + container.factoryInjection('model:post', 'secondaryStore', 'store:secondary'); + + var UserFactory = container.lookupFactory('model:user'); + var PostFactory = container.lookupFactory('model:post'); + var store = container.lookup('store:main'); + + UserFactory.store instanceof Store; //=> true + UserFactory.secondaryStore instanceof OtherStore; //=> false + + PostFactory.store instanceof Store; //=> true + PostFactory.secondaryStore instanceof OtherStore; //=> true + + // and both models share the same source instance + UserFactory.store === PostFactory.store; //=> true + ``` + + @method factoryInjection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + factoryInjection: function(fullName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + var normalizedName = this.normalize(fullName); + var normalizedInjectionName = this.normalize(injectionName); + + validateFullName(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName); + } + + Ember.assert('fullName must be a proper full name', validateFullName(fullName)); + + if (this.factoryCache[normalizedName]) { + throw new Error('Attempted to register a factoryInjection for a type that has already ' + + 'been looked up. (\'' + normalizedName + '\', \'' + property + '\', \'' + injectionName + '\')'); + } + + addInjection(this.factoryInjections, normalizedName, property, normalizedInjectionName); + }, + + /** + A depth first traversal, destroying the container, its descendant containers and all + their managed objects. + + @method destroy + */ + destroy: function() { + for (var i = 0, length = this.children.length; i < length; i++) { + this.children[i].destroy(); + } + + this.children = []; + + eachDestroyable(this, function(item) { + item.destroy(); + }); + + this.parent = undefined; + this.isDestroyed = true; + }, + + /** + @method reset + */ + reset: function() { + for (var i = 0, length = this.children.length; i < length; i++) { + resetCache(this.children[i]); + } + + resetCache(this); + } + }; + + function resolve(container, normalizedName) { + var cached = container.resolveCache[normalizedName]; + if (cached) { return cached; } + + var resolved = container.resolver(normalizedName) || container.registry[normalizedName]; + container.resolveCache[normalizedName] = resolved; + + return resolved; + } + + function has(container, fullName){ + if (container.cache[fullName]) { + return true; + } + + return !!container.resolve(fullName); + } + + function lookup(container, fullName, options) { + options = options || {}; + + if (container.cache[fullName] && options.singleton !== false) { + return container.cache[fullName]; + } + + var value = instantiate(container, fullName); + + if (value === undefined) { return; } + + if (isSingleton(container, fullName) && options.singleton !== false) { + container.cache[fullName] = value; + } + + return value; + } + + function illegalChildOperation(operation) { + throw new Error(operation + ' is not currently supported on child containers'); + } + + function isSingleton(container, fullName) { + var singleton = option(container, fullName, 'singleton'); + + return singleton !== false; + } + + function buildInjections(container, injections) { + var hash = {}; + + if (!injections) { return hash; } + + var injection, injectable; + + for (var i = 0, length = injections.length; i < length; i++) { + injection = injections[i]; + injectable = lookup(container, injection.fullName); + + if (injectable !== undefined) { + hash[injection.property] = injectable; + } else { + throw new Error('Attempting to inject an unknown injection: `' + injection.fullName + '`'); + } + } + + return hash; + } + + function option(container, fullName, optionName) { + var options = container._options[fullName]; + + if (options && options[optionName] !== undefined) { + return options[optionName]; + } + + var type = fullName.split(':')[0]; + options = container._typeOptions[type]; + + if (options) { + return options[optionName]; + } + } + + function factoryFor(container, fullName) { + var cache = container.factoryCache; + if (cache[fullName]) { + return cache[fullName]; + } + var factory = container.resolve(fullName); + if (factory === undefined) { return; } + + var type = fullName.split(':')[0]; + if (!factory || typeof factory.extend !== 'function' || (!Ember.MODEL_FACTORY_INJECTIONS && type === 'model')) { + // TODO: think about a 'safe' merge style extension + // for now just fallback to create time injection + cache[fullName] = factory; + return factory; + } else { + var injections = injectionsFor(container, fullName); + var factoryInjections = factoryInjectionsFor(container, fullName); + + factoryInjections._toString = container.makeToString(factory, fullName); + + var injectedFactory = factory.extend(injections); + injectedFactory.reopenClass(factoryInjections); + + cache[fullName] = injectedFactory; + + return injectedFactory; + } + } + + function injectionsFor(container, fullName) { + var splitName = fullName.split(':'); + var type = splitName[0]; + var injections = []; + + injections = injections.concat(container.typeInjections[type] || []); + injections = injections.concat(container.injections[fullName] || []); + + injections = buildInjections(container, injections); + injections._debugContainerKey = fullName; + injections.container = container; + + return injections; + } + + function factoryInjectionsFor(container, fullName) { + var splitName = fullName.split(':'); + var type = splitName[0]; + var factoryInjections = []; + + factoryInjections = factoryInjections.concat(container.factoryTypeInjections[type] || []); + factoryInjections = factoryInjections.concat(container.factoryInjections[fullName] || []); + + factoryInjections = buildInjections(container, factoryInjections); + factoryInjections._debugContainerKey = fullName; + + return factoryInjections; + } + + function instantiate(container, fullName) { + var factory = factoryFor(container, fullName); + + if (option(container, fullName, 'instantiate') === false) { + return factory; + } + + if (factory) { + if (typeof factory.create !== 'function') { + throw new Error('Failed to create an instance of \'' + fullName + '\'. ' + + 'Most likely an improperly defined class or an invalid module export.'); + } + + if (typeof factory.extend === 'function') { + // assume the factory was extendable and is already injected + return factory.create(); + } else { + // assume the factory was extendable + // to create time injections + // TODO: support new'ing for instantiation and merge injections for pure JS Functions + return factory.create(injectionsFor(container, fullName)); + } + } + } + + function eachDestroyable(container, callback) { + var cache = container.cache; + var keys = emberKeys(cache); + var key, value; + + for (var i = 0, l = keys.length; i < l; i++) { + key = keys[i]; + value = cache[key]; + + if (option(container, key, 'instantiate') !== false) { + callback(value); + } + } + } + + function resetCache(container) { + eachDestroyable(container, function(value) { + value.destroy(); + }); + + container.cache.dict = dictionary(null); + } + + function addTypeInjection(rules, type, property, fullName) { + var injections = rules[type]; + + if (!injections) { + injections = []; + rules[type] = injections; + } + + injections.push({ + property: property, + fullName: fullName + }); + } + + var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/; + function validateFullName(fullName) { + if (!VALID_FULL_NAME_REGEXP.test(fullName)) { + throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName); + } + return true; + } + + function addInjection(rules, factoryName, property, injectionName) { + var injections = rules[factoryName] = rules[factoryName] || []; + injections.push({ + property: property, + fullName: injectionName + }); + } + + __exports__["default"] = Container; + }); +define("ember-application", + ["ember-metal/core","ember-runtime/system/lazy_load","ember-application/system/dag","ember-application/system/resolver","ember-application/system/application","ember-application/ext/controller"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__) { + "use strict"; + var Ember = __dependency1__["default"]; + var runLoadHooks = __dependency2__.runLoadHooks; + + /** + Ember Application + + @module ember + @submodule ember-application + @requires ember-views, ember-routing + */ + + var DAG = __dependency3__["default"]; + var Resolver = __dependency4__.Resolver; + var DefaultResolver = __dependency4__["default"]; + var Application = __dependency5__["default"]; + // side effect of extending ControllerMixin + + Ember.Application = Application; + Ember.DAG = DAG; + Ember.Resolver = Resolver; + Ember.DefaultResolver = DefaultResolver; + + runLoadHooks('Ember.Application', Application); + }); +define("ember-application/ext/controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/error","ember-metal/utils","ember-metal/computed","ember-runtime/mixins/controller","ember-routing/system/controller_for","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var EmberError = __dependency4__["default"]; + var inspect = __dependency5__.inspect; + var computed = __dependency6__.computed; + var ControllerMixin = __dependency7__["default"]; + var meta = __dependency5__.meta; + var controllerFor = __dependency8__["default"]; + + function verifyNeedsDependencies(controller, container, needs) { + var dependency, i, l; + var missing = []; + + for (i=0, l=needs.length; i 1 ? 'they' : 'it') + " could not be found"); + } + } + + var defaultControllersComputedProperty = computed(function() { + var controller = this; + + return { + needs: get(controller, 'needs'), + container: get(controller, 'container'), + unknownProperty: function(controllerName) { + var needs = this.needs; + var dependency, i, l; + + for (i=0, l=needs.length; i 0) { + Ember.assert(' `' + inspect(this) + ' specifies `needs`, but does ' + + "not have a container. Please ensure this controller was " + + "instantiated with a container.", + this.container || meta(this, false).descs.controllers !== defaultControllersComputedProperty); + + if (this.container) { + verifyNeedsDependencies(this, this.container, needs); + } + + // if needs then initialize controllers proxy + get(this, 'controllers'); + } + + this._super.apply(this, arguments); + }, + + /** + @method controllerFor + @see {Ember.Route#controllerFor} + @deprecated Use `needs` instead + */ + controllerFor: function(controllerName) { + Ember.deprecate("Controller#controllerFor is deprecated, please use Controller#needs instead"); + return controllerFor(get(this, 'container'), controllerName); + }, + + /** + Stores the instances of other controllers available from within + this controller. Any controller listed by name in the `needs` + property will be accessible by name through this property. + + ```javascript + App.CommentsController = Ember.ArrayController.extend({ + needs: ['post'], + postTitle: function(){ + var currentPost = this.get('controllers.post'); // instance of App.PostController + return currentPost.get('title'); + }.property('controllers.post.title') + }); + ``` + + @see {Ember.ControllerMixin#needs} + @property {Object} controllers + @default null + */ + controllers: defaultControllersComputedProperty + }); + + __exports__["default"] = ControllerMixin; + }); +define("ember-application/system/application", + ["ember-metal","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-application/system/dag","ember-runtime/system/namespace","ember-runtime/mixins/deferred","ember-application/system/resolver","ember-metal/platform","ember-metal/run_loop","ember-metal/utils","container/container","ember-runtime/controllers/controller","ember-metal/enumerable_utils","ember-runtime/controllers/object_controller","ember-runtime/controllers/array_controller","ember-handlebars/controls/select","ember-views/system/event_dispatcher","ember-views/system/jquery","ember-routing/system/route","ember-routing/system/router","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/location/none_location","ember-routing/system/cache","ember-metal/core","ember-handlebars-compiler","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __dependency27__, __dependency28__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.deprecate, Ember.assert, Ember.libraries, LOG_VERSION, Namespace, BOOTED + var get = __dependency2__.get; + var set = __dependency3__.set; + var runLoadHooks = __dependency4__.runLoadHooks; + var DAG = __dependency5__["default"]; + var Namespace = __dependency6__["default"]; + var DeferredMixin = __dependency7__["default"]; + var DefaultResolver = __dependency8__["default"]; + var create = __dependency9__.create; + var run = __dependency10__["default"]; + var canInvoke = __dependency11__.canInvoke; + var Container = __dependency12__["default"]; + var Controller = __dependency13__["default"]; + var EnumerableUtils = __dependency14__["default"]; + var ObjectController = __dependency15__["default"]; + var ArrayController = __dependency16__["default"]; + var SelectView = __dependency17__["default"]; + var EventDispatcher = __dependency18__["default"]; + //import ContainerDebugAdapter from "ember-extension-support/container_debug_adapter"; + var jQuery = __dependency19__["default"]; + var Route = __dependency20__["default"]; + var Router = __dependency21__["default"]; + var HashLocation = __dependency22__["default"]; + var HistoryLocation = __dependency23__["default"]; + var AutoLocation = __dependency24__["default"]; + var NoneLocation = __dependency25__["default"]; + var BucketCache = __dependency26__["default"]; + + var K = __dependency27__.K; + var EmberHandlebars = __dependency28__["default"]; + + var ContainerDebugAdapter; + function props(obj) { + var properties = []; + + for (var key in obj) { + properties.push(key); + } + + return properties; + } + + /** + An instance of `Ember.Application` is the starting point for every Ember + application. It helps to instantiate, initialize and coordinate the many + objects that make up your app. + + Each Ember app has one and only one `Ember.Application` object. In fact, the + very first thing you should do in your application is create the instance: + + ```javascript + window.App = Ember.Application.create(); + ``` + + Typically, the application object is the only global variable. All other + classes in your app should be properties on the `Ember.Application` instance, + which highlights its first role: a global namespace. + + For example, if you define a view class, it might look like this: + + ```javascript + App.MyView = Ember.View.extend(); + ``` + + By default, calling `Ember.Application.create()` will automatically initialize + your application by calling the `Ember.Application.initialize()` method. If + you need to delay initialization, you can call your app's `deferReadiness()` + method. When you are ready for your app to be initialized, call its + `advanceReadiness()` method. + + You can define a `ready` method on the `Ember.Application` instance, which + will be run by Ember when the application is initialized. + + Because `Ember.Application` inherits from `Ember.Namespace`, any classes + you create will have useful string representations when calling `toString()`. + See the `Ember.Namespace` documentation for more information. + + While you can think of your `Ember.Application` as a container that holds the + other classes in your application, there are several other responsibilities + going on under-the-hood that you may want to understand. + + ### Event Delegation + + Ember uses a technique called _event delegation_. This allows the framework + to set up a global, shared event listener instead of requiring each view to + do it manually. For example, instead of each view registering its own + `mousedown` listener on its associated element, Ember sets up a `mousedown` + listener on the `body`. + + If a `mousedown` event occurs, Ember will look at the target of the event and + start walking up the DOM node tree, finding corresponding views and invoking + their `mouseDown` method as it goes. + + `Ember.Application` has a number of default events that it listens for, as + well as a mapping from lowercase events to camel-cased view method names. For + example, the `keypress` event causes the `keyPress` method on the view to be + called, the `dblclick` event causes `doubleClick` to be called, and so on. + + If there is a bubbling browser event that Ember does not listen for by + default, you can specify custom events and their corresponding view method + names by setting the application's `customEvents` property: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + paste: "paste" + } + }); + ``` + + By default, the application sets up these event listeners on the document + body. However, in cases where you are embedding an Ember application inside + an existing page, you may want it to set up the listeners on an element + inside the body. + + For example, if only events inside a DOM element with the ID of `ember-app` + should be delegated, set your application's `rootElement` property: + + ```javascript + window.App = Ember.Application.create({ + rootElement: '#ember-app' + }); + ``` + + The `rootElement` can be either a DOM element or a jQuery-compatible selector + string. Note that *views appended to the DOM outside the root element will + not receive events.* If you specify a custom root element, make sure you only + append views inside it! + + To learn more about the advantages of event delegation and the Ember view + layer, and a list of the event listeners that are setup by default, visit the + [Ember View Layer guide](http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_event-delegation). + + ### Initializers + + Libraries on top of Ember can add initializers, like so: + + ```javascript + Ember.Application.initializer({ + name: 'api-adapter', + + initialize: function(container, application) { + application.register('api-adapter:main', ApiAdapter); + } + }); + ``` + + Initializers provide an opportunity to access the container, which + organizes the different components of an Ember application. Additionally + they provide a chance to access the instantiated application. Beyond + being used for libraries, initializers are also a great way to organize + dependency injection or setup in your own application. + + ### Routing + + In addition to creating your application's router, `Ember.Application` is + also responsible for telling the router when to start routing. Transitions + between routes can be logged with the `LOG_TRANSITIONS` flag, and more + detailed intra-transition logging can be logged with + the `LOG_TRANSITIONS_INTERNAL` flag: + + ```javascript + window.App = Ember.Application.create({ + LOG_TRANSITIONS: true, // basic logging of successful transitions + LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps + }); + ``` + + By default, the router will begin trying to translate the current URL into + application state once the browser emits the `DOMContentReady` event. If you + need to defer routing, you can call the application's `deferReadiness()` + method. Once routing can begin, call the `advanceReadiness()` method. + + If there is any setup required before routing begins, you can implement a + `ready()` method on your app that will be invoked immediately before routing + begins. + ``` + + @class Application + @namespace Ember + @extends Ember.Namespace + */ + + var Application = Namespace.extend(DeferredMixin, { + _suppressDeferredDeprecation: true, + + /** + The root DOM element of the Application. This can be specified as an + element or a + [jQuery-compatible selector string](http://api.jquery.com/category/selectors/). + + This is the element that will be passed to the Application's, + `eventDispatcher`, which sets up the listeners for event delegation. Every + view in your application should be a child of the element you specify here. + + @property rootElement + @type DOMElement + @default 'body' + */ + rootElement: 'body', + + /** + The `Ember.EventDispatcher` responsible for delegating events to this + application's views. + + The event dispatcher is created by the application at initialization time + and sets up event listeners on the DOM element described by the + application's `rootElement` property. + + See the documentation for `Ember.EventDispatcher` for more information. + + @property eventDispatcher + @type Ember.EventDispatcher + @default null + */ + eventDispatcher: null, + + /** + The DOM events for which the event dispatcher should listen. + + By default, the application's `Ember.EventDispatcher` listens + for a set of standard DOM events, such as `mousedown` and + `keyup`, and delegates them to your application's `Ember.View` + instances. + + If you would like additional bubbling events to be delegated to your + views, set your `Ember.Application`'s `customEvents` property + to a hash containing the DOM event name as the key and the + corresponding view method name as the value. For example: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + paste: "paste" + } + }); + ``` + + @property customEvents + @type Object + @default null + */ + customEvents: null, + + // Start off the number of deferrals at 1. This will be + // decremented by the Application's own `initialize` method. + _readinessDeferrals: 1, + + init: function() { + if (!this.$) { this.$ = jQuery; } + this.__container__ = this.buildContainer(); + + this.Router = this.defaultRouter(); + + this._super(); + + this.scheduleInitialize(); + + Ember.libraries.registerCoreLibrary('Handlebars' + (EmberHandlebars.compile ? '' : '-runtime'), EmberHandlebars.VERSION); + Ember.libraries.registerCoreLibrary('jQuery', jQuery().jquery); + + if ( Ember.LOG_VERSION ) { + Ember.LOG_VERSION = false; // we only need to see this once per Application#init + + var nameLengths = EnumerableUtils.map(Ember.libraries, function(item) { + return get(item, "name.length"); + }); + + var maxNameLength = Math.max.apply(this, nameLengths); + + Ember.debug('-------------------------------'); + Ember.libraries.each(function(name, version) { + var spaces = new Array(maxNameLength - name.length + 1).join(" "); + Ember.debug([name, spaces, ' : ', version].join("")); + }); + Ember.debug('-------------------------------'); + } + }, + + /** + Build the container for the current application. + + Also register a default application view in case the application + itself does not. + + @private + @method buildContainer + @return {Ember.Container} the configured container + */ + buildContainer: function() { + var container = this.__container__ = Application.buildContainer(this); + + return container; + }, + + /** + If the application has not opted out of routing and has not explicitly + defined a router, supply a default router for the application author + to configure. + + This allows application developers to do: + + ```javascript + var App = Ember.Application.create(); + + App.Router.map(function() { + this.resource('posts'); + }); + ``` + + @private + @method defaultRouter + @return {Ember.Router} the default router + */ + + defaultRouter: function() { + if (this.Router === false) { return; } + var container = this.__container__; + + if (this.Router) { + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + return container.lookupFactory('router:main'); + }, + + /** + Automatically initialize the application once the DOM has + become ready. + + The initialization itself is scheduled on the actions queue + which ensures that application loading finishes before + booting. + + If you are asynchronously loading code, you should call + `deferReadiness()` to defer booting, and then call + `advanceReadiness()` once all of your code has finished + loading. + + @private + @method scheduleInitialize + */ + scheduleInitialize: function() { + var self = this; + + if (!this.$ || this.$.isReady) { + run.schedule('actions', self, '_initialize'); + } else { + this.$().ready(function runInitialize() { + run(self, '_initialize'); + }); + } + }, + + /** + Use this to defer readiness until some condition is true. + + Example: + + ```javascript + App = Ember.Application.create(); + App.deferReadiness(); + + jQuery.getJSON("/auth-token", function(token) { + App.token = token; + App.advanceReadiness(); + }); + ``` + + This allows you to perform asynchronous setup logic and defer + booting your application until the setup has finished. + + However, if the setup requires a loading UI, it might be better + to use the router for this purpose. + + @method deferReadiness + */ + deferReadiness: function() { + Ember.assert("You must call deferReadiness on an instance of Ember.Application", this instanceof Application); + Ember.assert("You cannot defer readiness since the `ready()` hook has already been called.", this._readinessDeferrals > 0); + this._readinessDeferrals++; + }, + + /** + Call `advanceReadiness` after any asynchronous setup logic has completed. + Each call to `deferReadiness` must be matched by a call to `advanceReadiness` + or the application will never become ready and routing will not begin. + + @method advanceReadiness + @see {Ember.Application#deferReadiness} + */ + advanceReadiness: function() { + Ember.assert("You must call advanceReadiness on an instance of Ember.Application", this instanceof Application); + this._readinessDeferrals--; + + if (this._readinessDeferrals === 0) { + run.once(this, this.didBecomeReady); + } + }, + + /** + Registers a factory that can be used for dependency injection (with + `App.inject`) or for service lookup. Each factory is registered with + a full name including two parts: `type:name`. + + A simple example: + + ```javascript + var App = Ember.Application.create(); + App.Orange = Ember.Object.extend(); + App.register('fruit:favorite', App.Orange); + ``` + + Ember will resolve factories from the `App` namespace automatically. + For example `App.CarsController` will be discovered and returned if + an application requests `controller:cars`. + + An example of registering a controller with a non-standard name: + + ```javascript + var App = Ember.Application.create(), + Session = Ember.Controller.extend(); + + App.register('controller:session', Session); + + // The Session controller can now be treated like a normal controller, + // despite its non-standard name. + App.ApplicationController = Ember.Controller.extend({ + needs: ['session'] + }); + ``` + + Registered factories are **instantiated** by having `create` + called on them. Additionally they are **singletons**, each time + they are looked up they return the same instance. + + Some examples modifying that default behavior: + + ```javascript + var App = Ember.Application.create(); + + App.Person = Ember.Object.extend(); + App.Orange = Ember.Object.extend(); + App.Email = Ember.Object.extend(); + App.session = Ember.Object.create(); + + App.register('model:user', App.Person, {singleton: false }); + App.register('fruit:favorite', App.Orange); + App.register('communication:main', App.Email, {singleton: false}); + App.register('session', App.session, {instantiate: false}); + ``` + + @method register + @param fullName {String} type:name (e.g., 'model:user') + @param factory {Function} (e.g., App.Person) + @param options {Object} (optional) disable instantiation or singleton usage + **/ + register: function() { + var container = this.__container__; + container.register.apply(container, arguments); + }, + + /** + Define a dependency injection onto a specific factory or all factories + of a type. + + When Ember instantiates a controller, view, or other framework component + it can attach a dependency to that component. This is often used to + provide services to a set of framework components. + + An example of providing a session object to all controllers: + + ```javascript + var App = Ember.Application.create(), + Session = Ember.Object.extend({ isAuthenticated: false }); + + // A factory must be registered before it can be injected + App.register('session:main', Session); + + // Inject 'session:main' onto all factories of the type 'controller' + // with the name 'session' + App.inject('controller', 'session', 'session:main'); + + App.IndexController = Ember.Controller.extend({ + isLoggedIn: Ember.computed.alias('session.isAuthenticated') + }); + ``` + + Injections can also be performed on specific factories. + + ```javascript + App.inject(, , ) + App.inject('route', 'source', 'source:main') + App.inject('route:application', 'email', 'model:email') + ``` + + It is important to note that injections can only be performed on + classes that are instantiated by Ember itself. Instantiating a class + directly (via `create` or `new`) bypasses the dependency injection + system. + + Ember-Data instantiates its models in a unique manner, and consequently + injections onto models (or all models) will not work as expected. Injections + on models can be enabled by setting `Ember.MODEL_FACTORY_INJECTIONS` + to `true`. + + @method inject + @param factoryNameOrType {String} + @param property {String} + @param injectionName {String} + **/ + inject: function() { + var container = this.__container__; + container.injection.apply(container, arguments); + }, + + /** + Calling initialize manually is not supported. + + Please see Ember.Application#advanceReadiness and + Ember.Application#deferReadiness. + + @private + @deprecated + @method initialize + **/ + initialize: function() { + Ember.deprecate('Calling initialize manually is not supported. Please see Ember.Application#advanceReadiness and Ember.Application#deferReadiness'); + }, + + /** + Initialize the application. This happens automatically. + + Run any initializers and run the application load hook. These hooks may + choose to defer readiness. For example, an authentication hook might want + to defer readiness until the auth token has been retrieved. + + @private + @method _initialize + */ + _initialize: function() { + if (this.isDestroyed) { return; } + + // At this point, the App.Router must already be assigned + if (this.Router) { + var container = this.__container__; + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + this.runInitializers(); + runLoadHooks('application', this); + + // At this point, any initializers or load hooks that would have wanted + // to defer readiness have fired. In general, advancing readiness here + // will proceed to didBecomeReady. + this.advanceReadiness(); + + return this; + }, + + /** + Reset the application. This is typically used only in tests. It cleans up + the application in the following order: + + 1. Deactivate existing routes + 2. Destroy all objects in the container + 3. Create a new application container + 4. Re-route to the existing url + + Typical Example: + + ```javascript + + var App; + + run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + App.reset(); + } + }); + + test("first test", function() { + // App is freshly reset + }); + + test("first test", function() { + // App is again freshly reset + }); + ``` + + Advanced Example: + + Occasionally you may want to prevent the app from initializing during + setup. This could enable extra configuration, or enable asserting prior + to the app becoming ready. + + ```javascript + + var App; + + run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + run(function() { + App.reset(); + App.deferReadiness(); + }); + } + }); + + test("first test", function() { + ok(true, 'something before app is initialized'); + + run(function() { + App.advanceReadiness(); + }); + ok(true, 'something after app is initialized'); + }); + ``` + + @method reset + **/ + reset: function() { + this._readinessDeferrals = 1; + + function handleReset() { + var router = this.__container__.lookup('router:main'); + router.reset(); + + run(this.__container__, 'destroy'); + + this.buildContainer(); + + run.schedule('actions', this, function() { + this._initialize(); + }); + } + + run.join(this, handleReset); + }, + + /** + @private + @method runInitializers + */ + runInitializers: function() { + var initializersByName = get(this.constructor, 'initializers'); + var initializers = props(initializersByName); + var container = this.__container__; + var graph = new DAG(); + var namespace = this; + var name, initializer; + + for (var i = 0; i < initializers.length; i++) { + initializer = initializersByName[initializers[i]]; + graph.addEdges(initializer.name, initializer.initialize, initializer.before, initializer.after); + } + + graph.topsort(function (vertex) { + var initializer = vertex.value; + Ember.assert("No application initializer named '" + vertex.name + "'", initializer); + initializer(container, namespace); + }); + }, + + /** + @private + @method didBecomeReady + */ + didBecomeReady: function() { + this.setupEventDispatcher(); + this.ready(); // user hook + this.startRouting(); + + if (!Ember.testing) { + // Eagerly name all classes that are already loaded + Ember.Namespace.processAll(); + Ember.BOOTED = true; + } + + this.resolve(this); + }, + + /** + Setup up the event dispatcher to receive events on the + application's `rootElement` with any registered + `customEvents`. + + @private + @method setupEventDispatcher + */ + setupEventDispatcher: function() { + var customEvents = get(this, 'customEvents'); + var rootElement = get(this, 'rootElement'); + var dispatcher = this.__container__.lookup('event_dispatcher:main'); + + set(this, 'eventDispatcher', dispatcher); + dispatcher.setup(customEvents, rootElement); + }, + + /** + If the application has a router, use it to route to the current URL, and + trigger a new call to `route` whenever the URL changes. + + @private + @method startRouting + @property router {Ember.Router} + */ + startRouting: function() { + var router = this.__container__.lookup('router:main'); + if (!router) { return; } + + router.startRouting(); + }, + + handleURL: function(url) { + var router = this.__container__.lookup('router:main'); + + router.handleURL(url); + }, + + /** + Called when the Application has become ready. + The call will be delayed until the DOM has become ready. + + @event ready + */ + ready: K, + + /** + @deprecated Use 'Resolver' instead + Set this to provide an alternate class to `Ember.DefaultResolver` + + + @property resolver + */ + resolver: null, + + /** + Set this to provide an alternate class to `Ember.DefaultResolver` + + @property resolver + */ + Resolver: null, + + willDestroy: function() { + Ember.BOOTED = false; + // Ensure deactivation of routes before objects are destroyed + this.__container__.lookup('router:main').reset(); + + this.__container__.destroy(); + }, + + initializer: function(options) { + this.constructor.initializer(options); + }, + + /** + @method then + @private + @deprecated + */ + then: function() { + Ember.deprecate('Do not use `.then` on an instance of Ember.Application. Please use the `.ready` hook instead.'); + + this._super.apply(this, arguments); + } + }); + + Application.reopenClass({ + initializers: Object.create(null), + + /** + Initializer receives an object which has the following attributes: + `name`, `before`, `after`, `initialize`. The only required attribute is + `initialize, all others are optional. + + * `name` allows you to specify under which name the initializer is registered. + This must be a unique name, as trying to register two initializers with the + same name will result in an error. + + ```javascript + Ember.Application.initializer({ + name: 'namedInitializer', + initialize: function(container, application) { + Ember.debug("Running namedInitializer!"); + } + }); + ``` + + * `before` and `after` are used to ensure that this initializer is ran prior + or after the one identified by the value. This value can be a single string + or an array of strings, referencing the `name` of other initializers. + + An example of ordering initializers, we create an initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'first', + initialize: function(container, application) { + Ember.debug("First initializer!"); + } + }); + + // DEBUG: First initializer! + ``` + + We add another initializer named `second`, specifying that it should run + after the initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'second', + after: 'first', + + initialize: function(container, application) { + Ember.debug("Second initializer!"); + } + }); + + // DEBUG: First initializer! + // DEBUG: Second initializer! + ``` + + Afterwards we add a further initializer named `pre`, this time specifying + that it should run before the initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'pre', + before: 'first', + + initialize: function(container, application) { + Ember.debug("Pre initializer!"); + } + }); + + // DEBUG: Pre initializer! + // DEBUG: First initializer! + // DEBUG: Second initializer! + ``` + + Finally we add an initializer named `post`, specifying it should run after + both the `first` and the `second` initializers: + + ```javascript + Ember.Application.initializer({ + name: 'post', + after: ['first', 'second'], + + initialize: function(container, application) { + Ember.debug("Post initializer!"); + } + }); + + // DEBUG: Pre initializer! + // DEBUG: First initializer! + // DEBUG: Second initializer! + // DEBUG: Post initializer! + ``` + + * `initialize` is a callback function that receives two arguments, `container` + and `application` on which you can operate. + + Example of using `container` to preload data into the store: + + ```javascript + Ember.Application.initializer({ + name: "preload-data", + + initialize: function(container, application) { + var store = container.lookup('store:main'); + store.pushPayload(preloadedData); + } + }); + ``` + + Example of using `application` to register an adapter: + + ```javascript + Ember.Application.initializer({ + name: 'api-adapter', + + initialize: function(container, application) { + application.register('api-adapter:main', ApiAdapter); + } + }); + ``` + + @method initializer + @param initializer {Object} + */ + initializer: function(initializer) { + // If this is the first initializer being added to a subclass, we are going to reopen the class + // to make sure we have a new `initializers` object, which extends from the parent class' using + // prototypal inheritance. Without this, attempting to add initializers to the subclass would + // pollute the parent class as well as other subclasses. + if (this.superclass.initializers !== undefined && this.superclass.initializers === this.initializers) { + this.reopenClass({ + initializers: create(this.initializers) + }); + } + + Ember.assert("The initializer '" + initializer.name + "' has already been registered", !this.initializers[initializer.name]); + Ember.assert("An initializer cannot be registered without an initialize function", canInvoke(initializer, 'initialize')); + + this.initializers[initializer.name] = initializer; + }, + + /** + This creates a container with the default Ember naming conventions. + + It also configures the container: + + * registered views are created every time they are looked up (they are + not singletons) + * registered templates are not factories; the registered value is + returned directly. + * the router receives the application as its `namespace` property + * all controllers receive the router as their `target` and `controllers` + properties + * all controllers receive the application as their `namespace` property + * the application view receives the application controller as its + `controller` property + * the application view receives the application template as its + `defaultTemplate` property + + @private + @method buildContainer + @static + @param {Ember.Application} namespace the application to build the + container for. + @return {Ember.Container} the built container + */ + buildContainer: function(namespace) { + var container = new Container(); + + container.set = set; + container.resolver = resolverFor(namespace); + container.normalizeFullName = container.resolver.normalize; + container.describe = container.resolver.describe; + container.makeToString = container.resolver.makeToString; + + container.optionsForType('component', { singleton: false }); + container.optionsForType('view', { singleton: false }); + container.optionsForType('template', { instantiate: false }); + container.optionsForType('helper', { instantiate: false }); + + container.register('application:main', namespace, { instantiate: false }); + + container.register('controller:basic', Controller, { instantiate: false }); + container.register('controller:object', ObjectController, { instantiate: false }); + container.register('controller:array', ArrayController, { instantiate: false }); + + container.register('view:select', SelectView); + + container.register('route:basic', Route, { instantiate: false }); + container.register('event_dispatcher:main', EventDispatcher); + + container.register('router:main', Router); + container.injection('router:main', 'namespace', 'application:main'); + + container.register('location:auto', AutoLocation); + container.register('location:hash', HashLocation); + container.register('location:history', HistoryLocation); + container.register('location:none', NoneLocation); + + container.injection('controller', 'target', 'router:main'); + container.injection('controller', 'namespace', 'application:main'); + + container.register('-bucket-cache:main', BucketCache); + container.injection('router', '_bucketCache', '-bucket-cache:main'); + container.injection('route', '_bucketCache', '-bucket-cache:main'); + container.injection('controller', '_bucketCache', '-bucket-cache:main'); + + container.injection('route', 'router', 'router:main'); + container.injection('location', 'rootURL', '-location-setting:root-url'); + + // DEBUGGING + container.register('resolver-for-debugging:main', container.resolver.__resolver__, { instantiate: false }); + container.injection('container-debug-adapter:main', 'resolver', 'resolver-for-debugging:main'); + container.injection('data-adapter:main', 'containerDebugAdapter', 'container-debug-adapter:main'); + // Custom resolver authors may want to register their own ContainerDebugAdapter with this key + + // ES6TODO: resolve this via import once ember-application package is ES6'ed + if (!ContainerDebugAdapter) { ContainerDebugAdapter = requireModule('ember-extension-support/container_debug_adapter')['default']; } + container.register('container-debug-adapter:main', ContainerDebugAdapter); + + return container; + } + }); + + /** + This function defines the default lookup rules for container lookups: + + * templates are looked up on `Ember.TEMPLATES` + * other names are looked up on the application after classifying the name. + For example, `controller:post` looks up `App.PostController` by default. + * if the default lookup fails, look for registered classes on the container + + This allows the application to register default injections in the container + that could be overridden by the normal naming convention. + + @private + @method resolverFor + @param {Ember.Namespace} namespace the namespace to look for classes + @return {*} the resolved value for a given lookup + */ + function resolverFor(namespace) { + if (namespace.get('resolver')) { + Ember.deprecate('Application.resolver is deprecated in favor of Application.Resolver', false); + } + + var ResolverClass = namespace.get('resolver') || namespace.get('Resolver') || DefaultResolver; + var resolver = ResolverClass.create({ + namespace: namespace + }); + + function resolve(fullName) { + return resolver.resolve(fullName); + } + + resolve.describe = function(fullName) { + return resolver.lookupDescription(fullName); + }; + + resolve.makeToString = function(factory, fullName) { + return resolver.makeToString(factory, fullName); + }; + + resolve.normalize = function(fullName) { + if (resolver.normalize) { + return resolver.normalize(fullName); + } else { + Ember.deprecate('The Resolver should now provide a \'normalize\' function', false); + return fullName; + } + }; + + resolve.__resolver__ = resolver; + + return resolve; + } + + __exports__["default"] = Application; + }); +define("ember-application/system/dag", + ["ember-metal/error","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberError = __dependency1__["default"]; + + function visit(vertex, fn, visited, path) { + var name = vertex.name; + var vertices = vertex.incoming; + var names = vertex.incomingNames; + var len = names.length; + var i; + + if (!visited) { + visited = {}; + } + if (!path) { + path = []; + } + if (visited.hasOwnProperty(name)) { + return; + } + path.push(name); + visited[name] = true; + for (i = 0; i < len; i++) { + visit(vertices[names[i]], fn, visited, path); + } + fn(vertex, path); + path.pop(); + } + + + /** + * DAG stands for Directed acyclic graph. + * + * It is used to build a graph of dependencies checking that there isn't circular + * dependencies. p.e Registering initializers with a certain precedence order. + * + * @class DAG + * @constructor + */ + function DAG() { + this.names = []; + this.vertices = Object.create(null); + } + + /** + * DAG Vertex + * + * @class Vertex + * @constructor + */ + + function Vertex(name) { + this.name = name; + this.incoming = {}; + this.incomingNames = []; + this.hasOutgoing = false; + this.value = null; + } + + /** + * Adds a vertex entry to the graph unless it is already added. + * + * @private + * @method add + * @param {String} name The name of the vertex to add + */ + DAG.prototype.add = function(name) { + if (!name) { + throw new Error("Can't add Vertex without name"); + } + if (this.vertices[name] !== undefined) { + return this.vertices[name]; + } + var vertex = new Vertex(name); + this.vertices[name] = vertex; + this.names.push(name); + return vertex; + }; + + /** + * Adds a vertex to the graph and sets its value. + * + * @private + * @method map + * @param {String} name The name of the vertex. + * @param value The value to put in the vertex. + */ + DAG.prototype.map = function(name, value) { + this.add(name).value = value; + }; + + /** + * Connects the vertices with the given names, adding them to the graph if + * necessary, only if this does not produce is any circular dependency. + * + * @private + * @method addEdge + * @param {String} fromName The name the vertex where the edge starts. + * @param {String} toName The name the vertex where the edge ends. + */ + DAG.prototype.addEdge = function(fromName, toName) { + if (!fromName || !toName || fromName === toName) { + return; + } + var from = this.add(fromName); + var to = this.add(toName); + if (to.incoming.hasOwnProperty(fromName)) { + return; + } + function checkCycle(vertex, path) { + if (vertex.name === toName) { + throw new EmberError("cycle detected: " + toName + " <- " + path.join(" <- ")); + } + } + visit(from, checkCycle); + from.hasOutgoing = true; + to.incoming[fromName] = from; + to.incomingNames.push(fromName); + }; + + /** + * Visits all the vertex of the graph calling the given function with each one, + * ensuring that the vertices are visited respecting their precedence. + * + * @method topsort + * @param {Function} fn The function to be invoked on each vertex. + */ + DAG.prototype.topsort = function(fn) { + var visited = {}; + var vertices = this.vertices; + var names = this.names; + var len = names.length; + var i, vertex; + + for (i = 0; i < len; i++) { + vertex = vertices[names[i]]; + if (!vertex.hasOutgoing) { + visit(vertex, fn, visited); + } + } + }; + + /** + * Adds a vertex with the given name and value to the graph and joins it with the + * vertices referenced in _before_ and _after_. If there isn't vertices with those + * names, they are added too. + * + * If either _before_ or _after_ are falsy/empty, the added vertex will not have + * an incoming/outgoing edge. + * + * @method addEdges + * @param {String} name The name of the vertex to be added. + * @param value The value of that vertex. + * @param before An string or array of strings with the names of the vertices before + * which this vertex must be visited. + * @param after An string or array of strings with the names of the vertex after + * which this vertex must be visited. + * + */ + DAG.prototype.addEdges = function(name, value, before, after) { + var i; + this.map(name, value); + if (before) { + if (typeof before === 'string') { + this.addEdge(name, before); + } else { + for (i = 0; i < before.length; i++) { + this.addEdge(name, before[i]); + } + } + } + if (after) { + if (typeof after === 'string') { + this.addEdge(after, name); + } else { + for (i = 0; i < after.length; i++) { + this.addEdge(after[i], name); + } + } + } + }; + + __exports__["default"] = DAG; + }); +define("ember-application/system/resolver", + ["ember-metal/core","ember-metal/property_get","ember-metal/logger","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/system/namespace","ember-handlebars","ember-metal/dictionary","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.TEMPLATES, Ember.assert + var get = __dependency2__.get; + var Logger = __dependency3__["default"]; + var classify = __dependency4__.classify; + var capitalize = __dependency4__.capitalize; + var decamelize = __dependency4__.decamelize; + var EmberObject = __dependency5__["default"]; + var Namespace = __dependency6__["default"]; + var EmberHandlebars = __dependency7__["default"]; + + var Resolver = EmberObject.extend({ + /** + This will be set to the Application instance when it is + created. + + @property namespace + */ + namespace: null, + normalize: Ember.required(Function), + resolve: Ember.required(Function), + parseName: Ember.required(Function), + lookupDescription: Ember.required(Function), + makeToString: Ember.required(Function), + resolveOther: Ember.required(Function), + _logLookup: Ember.required(Function) + }); + __exports__.Resolver = Resolver; + /** + The DefaultResolver defines the default lookup rules to resolve + container lookups before consulting the container for registered + items: + + * templates are looked up on `Ember.TEMPLATES` + * other names are looked up on the application after converting + the name. For example, `controller:post` looks up + `App.PostController` by default. + * there are some nuances (see examples below) + + ### How Resolving Works + + The container calls this object's `resolve` method with the + `fullName` argument. + + It first parses the fullName into an object using `parseName`. + + Then it checks for the presence of a type-specific instance + method of the form `resolve[Type]` and calls it if it exists. + For example if it was resolving 'template:post', it would call + the `resolveTemplate` method. + + Its last resort is to call the `resolveOther` method. + + The methods of this object are designed to be easy to override + in a subclass. For example, you could enhance how a template + is resolved like so: + + ```javascript + App = Ember.Application.create({ + Resolver: Ember.DefaultResolver.extend({ + resolveTemplate: function(parsedName) { + var resolvedTemplate = this._super(parsedName); + if (resolvedTemplate) { return resolvedTemplate; } + return Ember.TEMPLATES['not_found']; + } + }) + }); + ``` + + Some examples of how names are resolved: + + ``` + 'template:post' //=> Ember.TEMPLATES['post'] + 'template:posts/byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:posts.byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:blogPost' //=> Ember.TEMPLATES['blogPost'] + // OR + // Ember.TEMPLATES['blog_post'] + 'controller:post' //=> App.PostController + 'controller:posts.index' //=> App.PostsIndexController + 'controller:blog/post' //=> Blog.PostController + 'controller:basic' //=> Ember.Controller + 'route:post' //=> App.PostRoute + 'route:posts.index' //=> App.PostsIndexRoute + 'route:blog/post' //=> Blog.PostRoute + 'route:basic' //=> Ember.Route + 'view:post' //=> App.PostView + 'view:posts.index' //=> App.PostsIndexView + 'view:blog/post' //=> Blog.PostView + 'view:basic' //=> Ember.View + 'foo:post' //=> App.PostFoo + 'model:post' //=> App.Post + ``` + + @class DefaultResolver + @namespace Ember + @extends Ember.Object + */ + var dictionary = __dependency8__["default"]; + + __exports__["default"] = EmberObject.extend({ + /** + This will be set to the Application instance when it is + created. + + @property namespace + */ + namespace: null, + + init: function() { + this._parseNameCache = dictionary(null); + }, + normalize: function(fullName) { + var split = fullName.split(':', 2); + var type = split[0]; + var name = split[1]; + + Ember.assert("Tried to normalize a container name without a colon (:) in it. You probably tried to lookup a name that did not contain a type, a colon, and a name. A proper lookup name would be `view:post`.", split.length === 2); + + if (type !== 'template') { + var result = name; + + if (result.indexOf('.') > -1) { + result = result.replace(/\.(.)/g, function(m) { + return m.charAt(1).toUpperCase(); + }); + } + + if (name.indexOf('_') > -1) { + result = result.replace(/_(.)/g, function(m) { + return m.charAt(1).toUpperCase(); + }); + } + + return type + ':' + result; + } else { + return fullName; + } + }, + + + /** + This method is called via the container's resolver method. + It parses the provided `fullName` and then looks up and + returns the appropriate template or class. + + @method resolve + @param {String} fullName the lookup string + @return {Object} the resolved factory + */ + resolve: function(fullName) { + var parsedName = this.parseName(fullName); + var resolveMethodName = parsedName.resolveMethodName; + var resolved; + + if (!(parsedName.name && parsedName.type)) { + throw new TypeError('Invalid fullName: `' + fullName + '`, must be of the form `type:name` '); + } + + if (this[resolveMethodName]) { + resolved = this[resolveMethodName](parsedName); + } + + if (!resolved) { + resolved = this.resolveOther(parsedName); + } + + if (parsedName.root && parsedName.root.LOG_RESOLVER) { + this._logLookup(resolved, parsedName); + } + + return resolved; + }, + /** + Convert the string name of the form 'type:name' to + a Javascript object with the parsed aspects of the name + broken out. + + @protected + @param {String} fullName the lookup string + @method parseName + */ + + parseName: function(fullName) { + return this._parseNameCache[fullName] || ( + this._parseNameCache[fullName] = this._parseName(fullName) + ); + }, + + _parseName: function(fullName) { + var nameParts = fullName.split(':'); + var type = nameParts[0], fullNameWithoutType = nameParts[1]; + var name = fullNameWithoutType; + var namespace = get(this, 'namespace'); + var root = namespace; + + if (type !== 'template' && name.indexOf('/') !== -1) { + var parts = name.split('/'); + name = parts[parts.length - 1]; + var namespaceName = capitalize(parts.slice(0, -1).join('.')); + root = Namespace.byName(namespaceName); + + Ember.assert('You are looking for a ' + name + ' ' + type + ' in the ' + namespaceName + ' namespace, but the namespace could not be found', root); + } + + return { + fullName: fullName, + type: type, + fullNameWithoutType: fullNameWithoutType, + name: name, + root: root, + resolveMethodName: 'resolve' + classify(type) + }; + }, + + /** + Returns a human-readable description for a fullName. Used by the + Application namespace in assertions to describe the + precise name of the class that Ember is looking for, rather than + container keys. + + @protected + @param {String} fullName the lookup string + @method lookupDescription + */ + lookupDescription: function(fullName) { + var parsedName = this.parseName(fullName); + + if (parsedName.type === 'template') { + return 'template at ' + parsedName.fullNameWithoutType.replace(/\./g, '/'); + } + + var description = parsedName.root + '.' + classify(parsedName.name); + + if (parsedName.type !== 'model') { + description += classify(parsedName.type); + } + + return description; + }, + + makeToString: function(factory, fullName) { + return factory.toString(); + }, + /** + Given a parseName object (output from `parseName`), apply + the conventions expected by `Ember.Router` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method useRouterNaming + */ + useRouterNaming: function(parsedName) { + parsedName.name = parsedName.name.replace(/\./g, '_'); + if (parsedName.name === 'basic') { + parsedName.name = ''; + } + }, + /** + Look up the template in Ember.TEMPLATES + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveTemplate + */ + resolveTemplate: function(parsedName) { + var templateName = parsedName.fullNameWithoutType.replace(/\./g, '/'); + + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + + templateName = decamelize(templateName); + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + }, + + /** + Lookup the view using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveView + */ + resolveView: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + + /** + Lookup the controller using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveController + */ + resolveController: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + /** + Lookup the route using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveRoute + */ + resolveRoute: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + + /** + Lookup the model on the Application namespace + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveModel + */ + resolveModel: function(parsedName) { + var className = classify(parsedName.name); + var factory = get(parsedName.root, className); + + if (factory) { return factory; } + }, + /** + Look up the specified object (from parsedName) on the appropriate + namespace (usually on the Application) + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveHelper + */ + resolveHelper: function(parsedName) { + return this.resolveOther(parsedName) || EmberHandlebars.helpers[parsedName.fullNameWithoutType]; + }, + /** + Look up the specified object (from parsedName) on the appropriate + namespace (usually on the Application) + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveOther + */ + resolveOther: function(parsedName) { + var className = classify(parsedName.name) + classify(parsedName.type); + var factory = get(parsedName.root, className); + if (factory) { return factory; } + }, + + /** + @method _logLookup + @param {Boolean} found + @param {Object} parsedName + @private + */ + _logLookup: function(found, parsedName) { + var symbol, padding; + + if (found) { symbol = '[✓]'; } + else { symbol = '[ ]'; } + + if (parsedName.fullName.length > 60) { + padding = '.'; + } else { + padding = new Array(60 - parsedName.fullName.length).join('.'); + } + + Logger.info(symbol, parsedName.fullName, padding, this.lookupDescription(parsedName.fullName)); + } + }); + }); +define("ember-debug", + ["ember-metal/core","ember-metal/error","ember-metal/logger"], + function(__dependency1__, __dependency2__, __dependency3__) { + "use strict"; + /*global __fail__*/ + + var Ember = __dependency1__["default"]; + var EmberError = __dependency2__["default"]; + var Logger = __dependency3__["default"]; + + /** + Ember Debug + + @module ember + @submodule ember-debug + */ + + /** + @class Ember + */ + + /** + Define an assertion that will throw an exception if the condition is not + met. Ember build tools will remove any calls to `Ember.assert()` when + doing a production build. Example: + + ```javascript + // Test for truthiness + Ember.assert('Must pass a valid object', obj); + + // Fail unconditionally + Ember.assert('This code path should never be run'); + ``` + + @method assert + @param {String} desc A description of the assertion. This will become + the text of the Error thrown if the assertion fails. + @param {Boolean} test Must be truthy for the assertion to pass. If + falsy, an exception will be thrown. + */ + Ember.assert = function(desc, test) { + if (!test) { + throw new EmberError("Assertion Failed: " + desc); + } + }; + + + /** + Display a warning with the provided message. Ember build tools will + remove any calls to `Ember.warn()` when doing a production build. + + @method warn + @param {String} message A warning to display. + @param {Boolean} test An optional boolean. If falsy, the warning + will be displayed. + */ + Ember.warn = function(message, test) { + if (!test) { + Logger.warn("WARNING: "+message); + if ('trace' in Logger) Logger.trace(); + } + }; + + /** + Display a debug notice. Ember build tools will remove any calls to + `Ember.debug()` when doing a production build. + + ```javascript + Ember.debug('I\'m a debug notice!'); + ``` + + @method debug + @param {String} message A debug message to display. + */ + Ember.debug = function(message) { + Logger.debug("DEBUG: "+message); + }; + + /** + Display a deprecation warning with the provided message and a stack trace + (Chrome and Firefox only). Ember build tools will remove any calls to + `Ember.deprecate()` when doing a production build. + + @method deprecate + @param {String} message A description of the deprecation. + @param {Boolean} test An optional boolean. If falsy, the deprecation + will be displayed. + */ + Ember.deprecate = function(message, test) { + if (test) { return; } + + if (Ember.ENV.RAISE_ON_DEPRECATION) { throw new EmberError(message); } + + var error; + + // When using new Error, we can't do the arguments check for Chrome. Alternatives are welcome + try { __fail__.fail(); } catch (e) { error = e; } + + if (Ember.LOG_STACKTRACE_ON_DEPRECATION && error.stack) { + var stack; + var stackStr = ''; + + if (error['arguments']) { + // Chrome + stack = error.stack.replace(/^\s+at\s+/gm, ''). + replace(/^([^\(]+?)([\n$])/gm, '{anonymous}($1)$2'). + replace(/^Object.\s*\(([^\)]+)\)/gm, '{anonymous}($1)').split('\n'); + stack.shift(); + } else { + // Firefox + stack = error.stack.replace(/(?:\n@:0)?\s+$/m, ''). + replace(/^\(/gm, '{anonymous}(').split('\n'); + } + + stackStr = "\n " + stack.slice(2).join("\n "); + message = message + stackStr; + } + + Logger.warn("DEPRECATION: "+message); + }; + + + + /** + Alias an old, deprecated method with its new counterpart. + + Display a deprecation warning with the provided message and a stack trace + (Chrome and Firefox only) when the assigned method is called. + + Ember build tools will not remove calls to `Ember.deprecateFunc()`, though + no warnings will be shown in production. + + ```javascript + Ember.oldMethod = Ember.deprecateFunc('Please use the new, updated method', Ember.newMethod); + ``` + + @method deprecateFunc + @param {String} message A description of the deprecation. + @param {Function} func The new function called to replace its deprecated counterpart. + @return {Function} a new function that wrapped the original function with a deprecation warning + */ + Ember.deprecateFunc = function(message, func) { + return function() { + Ember.deprecate(message); + return func.apply(this, arguments); + }; + }; + + + /** + Run a function meant for debugging. Ember build tools will remove any calls to + `Ember.runInDebug()` when doing a production build. + + ```javascript + Ember.runInDebug(function() { + Ember.Handlebars.EachView.reopen({ + didInsertElement: function() { + console.log('I\'m happy'); + } + }); + }); + ``` + + @method runInDebug + @param {Function} func The function to be executed. + @since 1.5.0 + */ + Ember.runInDebug = function(func) { + func(); + }; + + // Inform the developer about the Ember Inspector if not installed. + if (!Ember.testing) { + var isFirefox = typeof InstallTrigger !== 'undefined'; + var isChrome = !!window.chrome && !window.opera; + + if (typeof window !== 'undefined' && (isFirefox || isChrome) && window.addEventListener) { + window.addEventListener("load", function() { + if (document.documentElement && document.documentElement.dataset && !document.documentElement.dataset.emberExtension) { + var downloadURL; + + if(isChrome) { + downloadURL = 'https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi'; + } else if(isFirefox) { + downloadURL = 'https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/'; + } + + Ember.debug('For more advanced debugging, install the Ember Inspector from ' + downloadURL); + } + }, false); + } + } + }); +define("ember-extension-support", + ["ember-metal/core","ember-extension-support/data_adapter","ember-extension-support/container_debug_adapter"], + function(__dependency1__, __dependency2__, __dependency3__) { + "use strict"; + /** + Ember Extension Support + + @module ember + @submodule ember-extension-support + @requires ember-application + */ + + var Ember = __dependency1__["default"]; + var DataAdapter = __dependency2__["default"]; + var ContainerDebugAdapter = __dependency3__["default"]; + + Ember.DataAdapter = DataAdapter; + Ember.ContainerDebugAdapter = ContainerDebugAdapter; + }); +define("ember-extension-support/container_debug_adapter", + ["ember-metal/core","ember-runtime/system/native_array","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var emberA = __dependency2__.A; + var typeOf = __dependency3__.typeOf; + var dasherize = __dependency4__.dasherize; + var classify = __dependency4__.classify; + var Namespace = __dependency5__["default"]; + var EmberObject = __dependency6__["default"]; + + /** + @module ember + @submodule ember-extension-support + */ + + /** + The `ContainerDebugAdapter` helps the container and resolver interface + with tools that debug Ember such as the + [Ember Extension](https://github.com/tildeio/ember-extension) + for Chrome and Firefox. + + This class can be extended by a custom resolver implementer + to override some of the methods with library-specific code. + + The methods likely to be overridden are: + + * `canCatalogEntriesByType` + * `catalogEntriesByType` + + The adapter will need to be registered + in the application's container as `container-debug-adapter:main` + + Example: + + ```javascript + Application.initializer({ + name: "containerDebugAdapter", + + initialize: function(container, application) { + application.register('container-debug-adapter:main', require('app/container-debug-adapter')); + } + }); + ``` + + @class ContainerDebugAdapter + @namespace Ember + @extends EmberObject + @since 1.5.0 + */ + __exports__["default"] = EmberObject.extend({ + /** + The container of the application being debugged. + This property will be injected + on creation. + + @property container + @default null + */ + container: null, + + /** + The resolver instance of the application + being debugged. This property will be injected + on creation. + + @property resolver + @default null + */ + resolver: null, + + /** + Returns true if it is possible to catalog a list of available + classes in the resolver for a given type. + + @method canCatalogEntriesByType + @param {String} type The type. e.g. "model", "controller", "route" + @return {boolean} whether a list is available for this type. + */ + canCatalogEntriesByType: function(type) { + if (type === 'model' || type === 'template') return false; + return true; + }, + + /** + Returns the available classes a given type. + + @method catalogEntriesByType + @param {String} type The type. e.g. "model", "controller", "route" + @return {Array} An array of strings. + */ + catalogEntriesByType: function(type) { + var namespaces = emberA(Namespace.NAMESPACES), types = emberA(), self = this; + var typeSuffixRegex = new RegExp(classify(type) + "$"); + + namespaces.forEach(function(namespace) { + if (namespace !== Ember) { + for (var key in namespace) { + if (!namespace.hasOwnProperty(key)) { continue; } + if (typeSuffixRegex.test(key)) { + var klass = namespace[key]; + if (typeOf(klass) === 'class') { + types.push(dasherize(key.replace(typeSuffixRegex, ''))); + } + } + } + } + }); + return types; + } + }); + }); +define("ember-extension-support/data_adapter", + ["ember-metal/core","ember-metal/property_get","ember-metal/run_loop","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/native_array","ember-application/system/application","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var run = __dependency3__["default"]; + var dasherize = __dependency4__.dasherize; + var Namespace = __dependency5__["default"]; + var EmberObject = __dependency6__["default"]; + var emberA = __dependency7__.A; + var Application = __dependency8__["default"]; + + /** + @module ember + @submodule ember-extension-support + */ + + /** + The `DataAdapter` helps a data persistence library + interface with tools that debug Ember such + as the [Ember Extension](https://github.com/tildeio/ember-extension) + for Chrome and Firefox. + + This class will be extended by a persistence library + which will override some of the methods with + library-specific code. + + The methods likely to be overridden are: + + * `getFilters` + * `detect` + * `columnsForType` + * `getRecords` + * `getRecordColumnValues` + * `getRecordKeywords` + * `getRecordFilterValues` + * `getRecordColor` + * `observeRecord` + + The adapter will need to be registered + in the application's container as `dataAdapter:main` + + Example: + + ```javascript + Application.initializer({ + name: "data-adapter", + + initialize: function(container, application) { + application.register('data-adapter:main', DS.DataAdapter); + } + }); + ``` + + @class DataAdapter + @namespace Ember + @extends EmberObject + */ + __exports__["default"] = EmberObject.extend({ + init: function() { + this._super(); + this.releaseMethods = emberA(); + }, + + /** + The container of the application being debugged. + This property will be injected + on creation. + + @property container + @default null + @since 1.3.0 + */ + container: null, + + + /** + The container-debug-adapter which is used + to list all models. + + @property containerDebugAdapter + @default undefined + @since 1.5.0 + **/ + containerDebugAdapter: undefined, + + /** + Number of attributes to send + as columns. (Enough to make the record + identifiable). + + @private + @property attributeLimit + @default 3 + @since 1.3.0 + */ + attributeLimit: 3, + + /** + Stores all methods that clear observers. + These methods will be called on destruction. + + @private + @property releaseMethods + @since 1.3.0 + */ + releaseMethods: emberA(), + + /** + Specifies how records can be filtered. + Records returned will need to have a `filterValues` + property with a key for every name in the returned array. + + @public + @method getFilters + @return {Array} List of objects defining filters. + The object should have a `name` and `desc` property. + */ + getFilters: function() { + return emberA(); + }, + + /** + Fetch the model types and observe them for changes. + + @public + @method watchModelTypes + + @param {Function} typesAdded Callback to call to add types. + Takes an array of objects containing wrapped types (returned from `wrapModelType`). + + @param {Function} typesUpdated Callback to call when a type has changed. + Takes an array of objects containing wrapped types. + + @return {Function} Method to call to remove all observers + */ + watchModelTypes: function(typesAdded, typesUpdated) { + var modelTypes = this.getModelTypes(); + var self = this; + var releaseMethods = emberA(); + var typesToSend; + + typesToSend = modelTypes.map(function(type) { + var klass = type.klass; + var wrapped = self.wrapModelType(klass, type.name); + releaseMethods.push(self.observeModelType(klass, typesUpdated)); + return wrapped; + }); + + typesAdded(typesToSend); + + var release = function() { + releaseMethods.forEach(function(fn) { fn(); }); + self.releaseMethods.removeObject(release); + }; + this.releaseMethods.pushObject(release); + return release; + }, + + _nameToClass: function(type) { + if (typeof type === 'string') { + type = this.container.lookupFactory('model:' + type); + } + return type; + }, + + /** + Fetch the records of a given type and observe them for changes. + + @public + @method watchRecords + + @param {Function} recordsAdded Callback to call to add records. + Takes an array of objects containing wrapped records. + The object should have the following properties: + columnValues: {Object} key and value of a table cell + object: {Object} the actual record object + + @param {Function} recordsUpdated Callback to call when a record has changed. + Takes an array of objects containing wrapped records. + + @param {Function} recordsRemoved Callback to call when a record has removed. + Takes the following parameters: + index: the array index where the records were removed + count: the number of records removed + + @return {Function} Method to call to remove all observers + */ + watchRecords: function(type, recordsAdded, recordsUpdated, recordsRemoved) { + var self = this, releaseMethods = emberA(), records = this.getRecords(type), release; + + var recordUpdated = function(updatedRecord) { + recordsUpdated([updatedRecord]); + }; + + var recordsToSend = records.map(function(record) { + releaseMethods.push(self.observeRecord(record, recordUpdated)); + return self.wrapRecord(record); + }); + + + var contentDidChange = function(array, idx, removedCount, addedCount) { + for (var i = idx; i < idx + addedCount; i++) { + var record = array.objectAt(i); + var wrapped = self.wrapRecord(record); + releaseMethods.push(self.observeRecord(record, recordUpdated)); + recordsAdded([wrapped]); + } + + if (removedCount) { + recordsRemoved(idx, removedCount); + } + }; + + var observer = { didChange: contentDidChange, willChange: Ember.K }; + records.addArrayObserver(self, observer); + + release = function() { + releaseMethods.forEach(function(fn) { fn(); }); + records.removeArrayObserver(self, observer); + self.releaseMethods.removeObject(release); + }; + + recordsAdded(recordsToSend); + + this.releaseMethods.pushObject(release); + return release; + }, + + /** + Clear all observers before destruction + @private + @method willDestroy + */ + willDestroy: function() { + this._super(); + this.releaseMethods.forEach(function(fn) { + fn(); + }); + }, + + /** + Detect whether a class is a model. + + Test that against the model class + of your persistence library + + @private + @method detect + @param {Class} klass The class to test + @return boolean Whether the class is a model class or not + */ + detect: function(klass) { + return false; + }, + + /** + Get the columns for a given model type. + + @private + @method columnsForType + @param {Class} type The model type + @return {Array} An array of columns of the following format: + name: {String} name of the column + desc: {String} Humanized description (what would show in a table column name) + */ + columnsForType: function(type) { + return emberA(); + }, + + /** + Adds observers to a model type class. + + @private + @method observeModelType + @param {Class} type The model type class + @param {Function} typesUpdated Called when a type is modified. + @return {Function} The function to call to remove observers + */ + + observeModelType: function(type, typesUpdated) { + var self = this; + var records = this.getRecords(type); + + var onChange = function() { + typesUpdated([self.wrapModelType(type)]); + }; + var observer = { + didChange: function() { + run.scheduleOnce('actions', this, onChange); + }, + willChange: Ember.K + }; + + records.addArrayObserver(this, observer); + + var release = function() { + records.removeArrayObserver(self, observer); + }; + + return release; + }, + + + /** + Wraps a given model type and observes changes to it. + + @private + @method wrapModelType + @param {Class} type A model class + @param {String} Optional name of the class + @return {Object} contains the wrapped type and the function to remove observers + Format: + type: {Object} the wrapped type + The wrapped type has the following format: + name: {String} name of the type + count: {Integer} number of records available + columns: {Columns} array of columns to describe the record + object: {Class} the actual Model type class + release: {Function} The function to remove observers + */ + wrapModelType: function(type, name) { + var records = this.getRecords(type); + var self = this; + var release, typeToSend; + + typeToSend = { + name: name || type.toString(), + count: get(records, 'length'), + columns: this.columnsForType(type), + object: type + }; + + + return typeToSend; + }, + + + /** + Fetches all models defined in the application. + + @private + @method getModelTypes + @return {Array} Array of model types + */ + getModelTypes: function() { + var self = this; + var containerDebugAdapter = this.get('containerDebugAdapter'); + var types; + + if (containerDebugAdapter.canCatalogEntriesByType('model')) { + types = containerDebugAdapter.catalogEntriesByType('model'); + } else { + types = this._getObjectsOnNamespaces(); + } + + // New adapters return strings instead of classes + types = emberA(types).map(function(name) { + return { + klass: self._nameToClass(name), + name: name + }; + }); + types = emberA(types).filter(function(type) { + return self.detect(type.klass); + }); + + return emberA(types); + }, + + /** + Loops over all namespaces and all objects + attached to them + + @private + @method _getObjectsOnNamespaces + @return {Array} Array of model type strings + */ + _getObjectsOnNamespaces: function() { + var namespaces = emberA(Namespace.NAMESPACES); + var types = emberA(); + var self = this; + + namespaces.forEach(function(namespace) { + for (var key in namespace) { + if (!namespace.hasOwnProperty(key)) { continue; } + // Even though we will filter again in `getModelTypes`, + // we should not call `lookupContainer` on non-models + // (especially when `Ember.MODEL_FACTORY_INJECTIONS` is `true`) + if (!self.detect(namespace[key])) { continue; } + var name = dasherize(key); + if (!(namespace instanceof Application) && namespace.toString()) { + name = namespace + '/' + name; + } + types.push(name); + } + }); + return types; + }, + + /** + Fetches all loaded records for a given type. + + @private + @method getRecords + @return {Array} An array of records. + This array will be observed for changes, + so it should update when new records are added/removed. + */ + getRecords: function(type) { + return emberA(); + }, + + /** + Wraps a record and observers changes to it. + + @private + @method wrapRecord + @param {Object} record The record instance. + @return {Object} The wrapped record. Format: + columnValues: {Array} + searchKeywords: {Array} + */ + wrapRecord: function(record) { + var recordToSend = { object: record }; + var columnValues = {}; + var self = this; + + recordToSend.columnValues = this.getRecordColumnValues(record); + recordToSend.searchKeywords = this.getRecordKeywords(record); + recordToSend.filterValues = this.getRecordFilterValues(record); + recordToSend.color = this.getRecordColor(record); + + return recordToSend; + }, + + /** + Gets the values for each column. + + @private + @method getRecordColumnValues + @return {Object} Keys should match column names defined + by the model type. + */ + getRecordColumnValues: function(record) { + return {}; + }, + + /** + Returns keywords to match when searching records. + + @private + @method getRecordKeywords + @return {Array} Relevant keywords for search. + */ + getRecordKeywords: function(record) { + return emberA(); + }, + + /** + Returns the values of filters defined by `getFilters`. + + @private + @method getRecordFilterValues + @param {Object} record The record instance + @return {Object} The filter values + */ + getRecordFilterValues: function(record) { + return {}; + }, + + /** + Each record can have a color that represents its state. + + @private + @method getRecordColor + @param {Object} record The record instance + @return {String} The record's color + Possible options: black, red, blue, green + */ + getRecordColor: function(record) { + return null; + }, + + /** + Observes all relevant properties and re-sends the wrapped record + when a change occurs. + + @private + @method observerRecord + @param {Object} record The record instance + @param {Function} recordUpdated The callback to call when a record is updated. + @return {Function} The function to call to remove all observers. + */ + observeRecord: function(record, recordUpdated) { + return function(){}; + } + }); + }); +define("ember-extension-support/initializers", + [], + function() { + "use strict"; + + }); +define("ember-handlebars-compiler", + ["ember-metal/core","exports"], + function(__dependency1__, __exports__) { + "use strict"; + /* global Handlebars:true */ + + /** + @module ember + @submodule ember-handlebars-compiler + */ + + var Ember = __dependency1__["default"]; + + // ES6Todo: you'll need to import debugger once debugger is es6'd. + if (typeof Ember.assert === 'undefined') { Ember.assert = function(){}; } + if (typeof Ember.FEATURES === 'undefined') { Ember.FEATURES = { isEnabled: function(){} }; } + + var objectCreate = Object.create || function(parent) { + function F() {} + F.prototype = parent; + return new F(); + }; + + // set up for circular references later + var View, Component; + + // ES6Todo: when ember-debug is es6'ed import this. + // var emberAssert = Ember.assert; + var Handlebars = (Ember.imports && Ember.imports.Handlebars) || (this && this.Handlebars); + if (!Handlebars && typeof require === 'function') { + Handlebars = require('handlebars'); + } + + Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1. Include " + + "a SCRIPT tag in the HTML HEAD linking to the Handlebars file " + + "before you link to Ember.", Handlebars); + + Ember.assert("Ember Handlebars requires Handlebars version 1.0 or 1.1, " + + "COMPILER_REVISION expected: 4, got: " + Handlebars.COMPILER_REVISION + + " - Please note: Builds of master may have other COMPILER_REVISION values.", + Handlebars.COMPILER_REVISION === 4); + + /** + Prepares the Handlebars templating library for use inside Ember's view + system. + + The `Ember.Handlebars` object is the standard Handlebars library, extended to + use Ember's `get()` method instead of direct property access, which allows + computed properties to be used inside templates. + + To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`. + This will return a function that can be used by `Ember.View` for rendering. + + @class Handlebars + @namespace Ember + */ + var EmberHandlebars = Ember.Handlebars = objectCreate(Handlebars); + + /** + Register a bound helper or custom view helper. + + ## Simple bound helper example + + ```javascript + Ember.Handlebars.helper('capitalize', function(value) { + return value.toUpperCase(); + }); + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{capitalize name}} + ``` + + In this case, when the `name` property of the template's context changes, + the rendered value of the helper will update to reflect this change. + + For more examples of bound helpers, see documentation for + `Ember.Handlebars.registerBoundHelper`. + + ## Custom view helper example + + Assuming a view subclass named `App.CalendarView` were defined, a helper + for rendering instances of this view could be registered as follows: + + ```javascript + Ember.Handlebars.helper('calendar', App.CalendarView): + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{calendar}} + ``` + + Which is functionally equivalent to: + + ```handlebars + {{view 'calendar'}} + ``` + + Options in the helper will be passed to the view in exactly the same + manner as with the `view` helper. + + @method helper + @for Ember.Handlebars + @param {String} name + @param {Function|Ember.View} function or view class constructor + @param {String} dependentKeys* + */ + EmberHandlebars.helper = function(name, value) { + if (!View) { View = requireModule('ember-views/views/view')['default']; } // ES6TODO: stupid circular dep + if (!Component) { Component = requireModule('ember-views/views/component')['default']; } // ES6TODO: stupid circular dep + + Ember.assert("You tried to register a component named '" + name + "', but component names must include a '-'", !Component.detect(value) || name.match(/-/)); + + if (View.detect(value)) { + EmberHandlebars.registerHelper(name, EmberHandlebars.makeViewHelper(value)); + } else { + EmberHandlebars.registerBoundHelper.apply(null, arguments); + } + }; + + /** + Returns a helper function that renders the provided ViewClass. + + Used internally by Ember.Handlebars.helper and other methods + involving helper/component registration. + + @private + @method makeViewHelper + @for Ember.Handlebars + @param {Function} ViewClass view class constructor + @since 1.2.0 + */ + EmberHandlebars.makeViewHelper = function(ViewClass) { + return function(options) { + Ember.assert("You can only pass attributes (such as name=value) not bare values to a helper for a View found in '" + ViewClass.toString() + "'", arguments.length < 2); + return EmberHandlebars.helpers.view.call(this, ViewClass, options); + }; + }; + + /** + @class helpers + @namespace Ember.Handlebars + */ + EmberHandlebars.helpers = objectCreate(Handlebars.helpers); + + /** + Override the the opcode compiler and JavaScript compiler for Handlebars. + + @class Compiler + @namespace Ember.Handlebars + @private + @constructor + */ + EmberHandlebars.Compiler = function() {}; + + // Handlebars.Compiler doesn't exist in runtime-only + if (Handlebars.Compiler) { + EmberHandlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype); + } + + EmberHandlebars.Compiler.prototype.compiler = EmberHandlebars.Compiler; + + /** + @class JavaScriptCompiler + @namespace Ember.Handlebars + @private + @constructor + */ + EmberHandlebars.JavaScriptCompiler = function() {}; + + // Handlebars.JavaScriptCompiler doesn't exist in runtime-only + if (Handlebars.JavaScriptCompiler) { + EmberHandlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype); + EmberHandlebars.JavaScriptCompiler.prototype.compiler = EmberHandlebars.JavaScriptCompiler; + } + + + EmberHandlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars"; + + EmberHandlebars.JavaScriptCompiler.prototype.initializeBuffer = function() { + return "''"; + }; + + /** + Override the default buffer for Ember Handlebars. By default, Handlebars + creates an empty String at the beginning of each invocation and appends to + it. Ember's Handlebars overrides this to append to a single shared buffer. + + @private + @method appendToBuffer + @param string {String} + */ + EmberHandlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) { + return "data.buffer.push("+string+");"; + }; + + // Hacks ahead: + // Handlebars presently has a bug where the `blockHelperMissing` hook + // doesn't get passed the name of the missing helper name, but rather + // gets passed the value of that missing helper evaluated on the current + // context, which is most likely `undefined` and totally useless. + // + // So we alter the compiled template function to pass the name of the helper + // instead, as expected. + // + // This can go away once the following is closed: + // https://github.com/wycats/handlebars.js/issues/634 + + var DOT_LOOKUP_REGEX = /helpers\.(.*?)\)/; + var BRACKET_STRING_LOOKUP_REGEX = /helpers\['(.*?)'/; + var INVOCATION_SPLITTING_REGEX = /(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/; + + EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation = function(source) { + var helperInvocation = source[source.length - 1]; + var helperName = (DOT_LOOKUP_REGEX.exec(helperInvocation) || BRACKET_STRING_LOOKUP_REGEX.exec(helperInvocation))[1]; + var matches = INVOCATION_SPLITTING_REGEX.exec(helperInvocation); + + source[source.length - 1] = matches[1] + "'" + helperName + "'" + matches[3]; + }; + + var stringifyBlockHelperMissing = EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation; + + var originalBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.blockValue; + EmberHandlebars.JavaScriptCompiler.prototype.blockValue = function() { + originalBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); + }; + + var originalAmbiguousBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue; + EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue = function() { + originalAmbiguousBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); + }; + + /** + Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that + all simple mustaches in Ember's Handlebars will also set up an observer to + keep the DOM up to date when the underlying property changes. + + @private + @method mustache + @for Ember.Handlebars.Compiler + @param mustache + */ + EmberHandlebars.Compiler.prototype.mustache = function(mustache) { + if (!(mustache.params.length || mustache.hash)) { + var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]); + + // Update the mustache node to include a hash value indicating whether the original node + // was escaped. This will allow us to properly escape values when the underlying value + // changes and we need to re-render the value. + if (!mustache.escaped) { + mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]); + mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]); + } + mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped); + } + + return Handlebars.Compiler.prototype.mustache.call(this, mustache); + }; + + /** + Used for precompilation of Ember Handlebars templates. This will not be used + during normal app execution. + + @method precompile + @for Ember.Handlebars + @static + @param {String|Object} value The template to precompile or an Handlebars AST + @param {Boolean} asObject optional parameter, defaulting to true, of whether or not the + compiled template should be returned as an Object or a String + */ + EmberHandlebars.precompile = function(value, asObject) { + var ast = Handlebars.parse(value); + + var options = { + knownHelpers: { + action: true, + unbound: true, + 'bind-attr': true, + template: true, + view: true, + _triageMustache: true + }, + data: true, + stringParams: true + }; + + asObject = asObject === undefined ? true : asObject; + + var environment = new EmberHandlebars.Compiler().compile(ast, options); + return new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, asObject); + }; + + // We don't support this for Handlebars runtime-only + if (Handlebars.compile) { + /** + The entry point for Ember Handlebars. This replaces the default + `Handlebars.compile` and turns on template-local data and String + parameters. + + @method compile + @for Ember.Handlebars + @static + @param {String} string The template to compile + @return {Function} + */ + EmberHandlebars.compile = function(string) { + var ast = Handlebars.parse(string); + var options = { data: true, stringParams: true }; + var environment = new EmberHandlebars.Compiler().compile(ast, options); + var templateSpec = new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, true); + + var template = EmberHandlebars.template(templateSpec); + template.isMethod = false; //Make sure we don't wrap templates with ._super + + return template; + }; + } + + __exports__["default"] = EmberHandlebars; + }); +define("ember-handlebars", + ["ember-handlebars-compiler","ember-metal/core","ember-runtime/system/lazy_load","ember-handlebars/loader","ember-handlebars/ext","ember-handlebars/string","ember-handlebars/helpers/shared","ember-handlebars/helpers/binding","ember-handlebars/helpers/collection","ember-handlebars/helpers/view","ember-handlebars/helpers/unbound","ember-handlebars/helpers/debug","ember-handlebars/helpers/each","ember-handlebars/helpers/template","ember-handlebars/helpers/partial","ember-handlebars/helpers/yield","ember-handlebars/helpers/loc","ember-handlebars/controls/checkbox","ember-handlebars/controls/select","ember-handlebars/controls/text_area","ember-handlebars/controls/text_field","ember-handlebars/controls/text_support","ember-handlebars/controls","ember-handlebars/component_lookup","ember-handlebars/views/handlebars_bound_view","ember-handlebars/views/metamorph_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __exports__) { + "use strict"; + var EmberHandlebars = __dependency1__["default"]; + var Ember = __dependency2__["default"]; + // to add to globals + + var runLoadHooks = __dependency3__.runLoadHooks; + var bootstrap = __dependency4__["default"]; + + var normalizePath = __dependency5__.normalizePath; + var template = __dependency5__.template; + var makeBoundHelper = __dependency5__.makeBoundHelper; + var registerBoundHelper = __dependency5__.registerBoundHelper; + var resolveHash = __dependency5__.resolveHash; + var resolveParams = __dependency5__.resolveParams; + var getEscaped = __dependency5__.getEscaped; + var handlebarsGet = __dependency5__.handlebarsGet; + var evaluateUnboundHelper = __dependency5__.evaluateUnboundHelper; + var helperMissingHelper = __dependency5__.helperMissingHelper; + var blockHelperMissingHelper = __dependency5__.blockHelperMissingHelper; + + + // side effect of extending StringUtils of htmlSafe + + var resolvePaths = __dependency7__["default"]; + var bind = __dependency8__.bind; + var _triageMustacheHelper = __dependency8__._triageMustacheHelper; + var resolveHelper = __dependency8__.resolveHelper; + var bindHelper = __dependency8__.bindHelper; + var boundIfHelper = __dependency8__.boundIfHelper; + var unboundIfHelper = __dependency8__.unboundIfHelper; + var withHelper = __dependency8__.withHelper; + var ifHelper = __dependency8__.ifHelper; + var unlessHelper = __dependency8__.unlessHelper; + var bindAttrHelper = __dependency8__.bindAttrHelper; + var bindAttrHelperDeprecated = __dependency8__.bindAttrHelperDeprecated; + var bindClasses = __dependency8__.bindClasses; + + var collectionHelper = __dependency9__["default"]; + var ViewHelper = __dependency10__.ViewHelper; + var viewHelper = __dependency10__.viewHelper; + var unboundHelper = __dependency11__["default"]; + var logHelper = __dependency12__.logHelper; + var debuggerHelper = __dependency12__.debuggerHelper; + var EachView = __dependency13__.EachView; + var GroupedEach = __dependency13__.GroupedEach; + var eachHelper = __dependency13__.eachHelper; + var templateHelper = __dependency14__["default"]; + var partialHelper = __dependency15__["default"]; + var yieldHelper = __dependency16__["default"]; + var locHelper = __dependency17__["default"]; + + + var Checkbox = __dependency18__["default"]; + var Select = __dependency19__.Select; + var SelectOption = __dependency19__.SelectOption; + var SelectOptgroup = __dependency19__.SelectOptgroup; + var TextArea = __dependency20__["default"]; + var TextField = __dependency21__["default"]; + var TextSupport = __dependency22__["default"]; + var inputHelper = __dependency23__.inputHelper; + var textareaHelper = __dependency23__.textareaHelper; + + + var ComponentLookup = __dependency24__["default"]; + var _HandlebarsBoundView = __dependency25__._HandlebarsBoundView; + var SimpleHandlebarsView = __dependency25__.SimpleHandlebarsView; + var _wrapMap = __dependency26__._wrapMap; + var _SimpleMetamorphView = __dependency26__._SimpleMetamorphView; + var _MetamorphView = __dependency26__._MetamorphView; + var _Metamorph = __dependency26__._Metamorph; + + + /** + Ember Handlebars + + @module ember + @submodule ember-handlebars + @requires ember-views + */ + + // Ember.Handlebars.Globals + EmberHandlebars.bootstrap = bootstrap; + EmberHandlebars.template = template; + EmberHandlebars.makeBoundHelper = makeBoundHelper; + EmberHandlebars.registerBoundHelper = registerBoundHelper; + EmberHandlebars.resolveHash = resolveHash; + EmberHandlebars.resolveParams = resolveParams; + EmberHandlebars.resolveHelper = resolveHelper; + EmberHandlebars.get = handlebarsGet; + EmberHandlebars.getEscaped = getEscaped; + EmberHandlebars.evaluateUnboundHelper = evaluateUnboundHelper; + EmberHandlebars.bind = bind; + EmberHandlebars.bindClasses = bindClasses; + EmberHandlebars.EachView = EachView; + EmberHandlebars.GroupedEach = GroupedEach; + EmberHandlebars.resolvePaths = resolvePaths; + EmberHandlebars.ViewHelper = ViewHelper; + EmberHandlebars.normalizePath = normalizePath; + + + // Ember Globals + Ember.Handlebars = EmberHandlebars; + Ember.ComponentLookup = ComponentLookup; + Ember._SimpleHandlebarsView = SimpleHandlebarsView; + Ember._HandlebarsBoundView = _HandlebarsBoundView; + Ember._SimpleMetamorphView = _SimpleMetamorphView; + Ember._MetamorphView = _MetamorphView; + Ember._Metamorph = _Metamorph; + Ember._metamorphWrapMap = _wrapMap; + Ember.TextSupport = TextSupport; + Ember.Checkbox = Checkbox; + Ember.Select = Select; + Ember.SelectOption = SelectOption; + Ember.SelectOptgroup = SelectOptgroup; + Ember.TextArea = TextArea; + Ember.TextField = TextField; + Ember.TextSupport = TextSupport; + + // register helpers + EmberHandlebars.registerHelper('helperMissing', helperMissingHelper); + EmberHandlebars.registerHelper('blockHelperMissing', blockHelperMissingHelper); + EmberHandlebars.registerHelper('bind', bindHelper); + EmberHandlebars.registerHelper('boundIf', boundIfHelper); + EmberHandlebars.registerHelper('_triageMustache', _triageMustacheHelper); + EmberHandlebars.registerHelper('unboundIf', unboundIfHelper); + EmberHandlebars.registerHelper('with', withHelper); + EmberHandlebars.registerHelper('if', ifHelper); + EmberHandlebars.registerHelper('unless', unlessHelper); + EmberHandlebars.registerHelper('bind-attr', bindAttrHelper); + EmberHandlebars.registerHelper('bindAttr', bindAttrHelperDeprecated); + EmberHandlebars.registerHelper('collection', collectionHelper); + EmberHandlebars.registerHelper("log", logHelper); + EmberHandlebars.registerHelper("debugger", debuggerHelper); + EmberHandlebars.registerHelper("each", eachHelper); + EmberHandlebars.registerHelper("loc", locHelper); + EmberHandlebars.registerHelper("partial", partialHelper); + EmberHandlebars.registerHelper("template", templateHelper); + EmberHandlebars.registerHelper("yield", yieldHelper); + EmberHandlebars.registerHelper("view", viewHelper); + EmberHandlebars.registerHelper("unbound", unboundHelper); + EmberHandlebars.registerHelper("input", inputHelper); + EmberHandlebars.registerHelper("textarea", textareaHelper); + + // run load hooks + runLoadHooks('Ember.Handlebars', EmberHandlebars); + + __exports__["default"] = EmberHandlebars; + }); +define("ember-handlebars/component_lookup", + ["ember-runtime/system/object","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + + var ComponentLookup = EmberObject.extend({ + lookupFactory: function(name, container) { + + container = container || this.container; + + var fullName = 'component:' + name; + var templateFullName = 'template:components/' + name; + var templateRegistered = container && container.has(templateFullName); + + if (templateRegistered) { + container.injection(fullName, 'layout', templateFullName); + } + + var Component = container.lookupFactory(fullName); + + // Only treat as a component if either the component + // or a template has been registered. + if (templateRegistered || Component) { + if (!Component) { + container.register(fullName, Ember.Component); + Component = container.lookupFactory(fullName); + } + return Component; + } + } + }); + + __exports__["default"] = ComponentLookup; + }); +define("ember-handlebars/controls", + ["ember-handlebars/controls/checkbox","ember-handlebars/controls/text_field","ember-handlebars/controls/text_area","ember-metal/core","ember-handlebars-compiler","ember-handlebars/ext","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Checkbox = __dependency1__["default"]; + var TextField = __dependency2__["default"]; + var TextArea = __dependency3__["default"]; + + var Ember = __dependency4__["default"]; + // Ember.assert + // var emberAssert = Ember.assert; + + var EmberHandlebars = __dependency5__["default"]; + var handlebarsGet = __dependency6__.handlebarsGet; + var helpers = EmberHandlebars.helpers; + /** + @module ember + @submodule ember-handlebars-compiler + */ + + function _resolveOption(context, options, key) { + if (options.hashTypes[key] === "ID") { + return handlebarsGet(context, options.hash[key], options); + } else { + return options.hash[key]; + } + } + + /** + + The `{{input}}` helper inserts an HTML `` tag into the template, + with a `type` value of either `text` or `checkbox`. If no `type` is provided, + `text` will be the default value applied. The attributes of `{{input}}` + match those of the native HTML tag as closely as possible for these two types. + + ## Use as text field + An `{{input}}` with no `type` or a `type` of `text` will render an HTML text input. + The following HTML attributes can be set via the helper: + + + + + + + + + + + + +
`readonly``required``autofocus`
`value``placeholder``disabled`
`size``tabindex``maxlength`
`name``min``max`
`pattern``accept``autocomplete`
`autosave``formaction``formenctype`
`formmethod``formnovalidate``formtarget`
`height``inputmode``multiple`
`step``width``form`
`selectionDirection``spellcheck` 
+ + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input value="http://www.facebook.com"}} + ``` + + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + firstName: "Stanley", + entryNotAllowed: true + }); + ``` + + + ```handlebars + {{input type="text" value=firstName disabled=entryNotAllowed size="50"}} + ``` + + + ```html + + ``` + + ## Actions + + The helper can send multiple actions based on user events. + + The action property defines the action which is send when + the user presses the return key. + + ```handlebars + {{input action="submit"}} + ``` + + The helper allows some user events to send actions. + + * `enter` + * `insert-newline` + * `escape-press` + * `focus-in` + * `focus-out` + * `key-press` + + For example, if you desire an action to be sent when the input is blurred, + you only need to setup the action name to the event name property. + + ```handlebars + {{input focus-in="alertMessage"}} + ``` + + See more about [Text Support Actions](/api/classes/Ember.TextField.html) + + ## Extension + + Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing + arguments from the helper to `Ember.TextField`'s `create` method. You can extend the + capabilities of text inputs in your applications by reopening this class. For example, + if you are building a Bootstrap project where `data-*` attributes are used, you + can add one to the `TextField`'s `attributeBindings` property: + + + ```javascript + Ember.TextField.reopen({ + attributeBindings: ['data-error'] + }); + ``` + + Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](/api/classes/Ember.Component.html) + + + ## Use as checkbox + + An `{{input}}` with a `type` of `checkbox` will render an HTML checkbox input. + The following HTML attributes can be set via the helper: + + * `checked` + * `disabled` + * `tabindex` + * `indeterminate` + * `name` + * `autofocus` + * `form` + + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input type="checkbox" name="isAdmin"}} + ``` + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + isAdmin: true + }); + ``` + + + ```handlebars + {{input type="checkbox" checked=isAdmin }} + ``` + + + ```html + + ``` + + ## Extension + + Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing + arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the + capablilties of checkbox inputs in your applications by reopening this class. For example, + if you wanted to add a css class to all checkboxes in your application: + + + ```javascript + Ember.Checkbox.reopen({ + classNames: ['my-app-checkbox'] + }); + ``` + + + @method input + @for Ember.Handlebars.helpers + @param {Hash} options + */ + function inputHelper(options) { + Ember.assert('You can only pass attributes to the `input` helper, not arguments', arguments.length < 2); + + var hash = options.hash; + var types = options.hashTypes; + var inputType = _resolveOption(this, options, 'type'); + var onEvent = hash.on; + + if (inputType === 'checkbox') { + delete hash.type; + delete types.type; + + Ember.assert("{{input type='checkbox'}} does not support setting `value=someBooleanValue`; you must use `checked=someBooleanValue` instead.", options.hashTypes.value !== 'ID'); + + return helpers.view.call(this, Checkbox, options); + } else { + delete hash.on; + + hash.onEvent = onEvent || 'enter'; + return helpers.view.call(this, TextField, options); + } + } + + __exports__.inputHelper = inputHelper;/** + `{{textarea}}` inserts a new instance of ` + ``` + + Bound: + + In the following example, the `writtenWords` property on `App.ApplicationController` + will be updated live as the user types 'Lots of text that IS bound' into + the text area of their browser's window. + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound" + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + ``` + + Would result in the following HTML: + + ```html + + ``` + + If you wanted a one way binding between the text area and a div tag + somewhere else on your screen, you could use `Ember.computed.oneWay`: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + outputWrittenWords: Ember.computed.oneWay("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + +
+ {{outputWrittenWords}} +
+ ``` + + Would result in the following HTML: + + ```html + + + <-- the following div will be updated in real time as you type --> + +
+ Lots of text that IS bound +
+ ``` + + Finally, this example really shows the power and ease of Ember when two + properties are bound to eachother via `Ember.computed.alias`. Type into + either text area box and they'll both stay in sync. Note that + `Ember.computed.alias` costs more in terms of performance, so only use it when + your really binding in both directions: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + twoWayWrittenWords: Ember.computed.alias("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + {{textarea value=twoWayWrittenWords}} + ``` + + ```html + + + <-- both updated in real time --> + + + ``` + + ## Actions + + The helper can send multiple actions based on user events. + + The action property defines the action which is send when + the user presses the return key. + + ```handlebars + {{input action="submit"}} + ``` + + The helper allows some user events to send actions. + + * `enter` + * `insert-newline` + * `escape-press` + * `focus-in` + * `focus-out` + * `key-press` + + For example, if you desire an action to be sent when the input is blurred, + you only need to setup the action name to the event name property. + + ```handlebars + {{textarea focus-in="alertMessage"}} + ``` + + See more about [Text Support Actions](/api/classes/Ember.TextArea.html) + + ## Extension + + Internally, `{{textarea}}` creates an instance of `Ember.TextArea`, passing + arguments from the helper to `Ember.TextArea`'s `create` method. You can + extend the capabilities of text areas in your application by reopening this + class. For example, if you are building a Bootstrap project where `data-*` + attributes are used, you can globally add support for a `data-*` attribute + on all `{{textarea}}`s' in your app by reopening `Ember.TextArea` or + `Ember.TextSupport` and adding it to the `attributeBindings` concatenated + property: + + ```javascript + Ember.TextArea.reopen({ + attributeBindings: ['data-error'] + }); + ``` + + Keep in mind when writing `Ember.TextArea` subclasses that `Ember.TextArea` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](/api/classes/Ember.Component.html) + + @method textarea + @for Ember.Handlebars.helpers + @param {Hash} options + */ + function textareaHelper(options) { + Ember.assert('You can only pass attributes to the `textarea` helper, not arguments', arguments.length < 2); + + var hash = options.hash; + var types = options.hashTypes; + + return helpers.view.call(this, TextArea, options); + } + + __exports__.textareaHelper = textareaHelper; + }); +define("ember-handlebars/controls/checkbox", + ["ember-metal/property_get","ember-metal/property_set","ember-views/views/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var View = __dependency3__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `checkbox`. + + See [handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. + + ## Direct manipulation of `checked` + + The `checked` attribute of an `Ember.Checkbox` object should always be set + through the Ember object or by interacting with its rendered element + representation via the mouse, keyboard, or touch. Updating the value of the + checkbox via jQuery will result in the checked value of the object and its + element losing synchronization. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class Checkbox + @namespace Ember + @extends Ember.View + */ + __exports__["default"] = View.extend({ + instrumentDisplay: '{{input type="checkbox"}}', + + classNames: ['ember-checkbox'], + + tagName: 'input', + + attributeBindings: [ + 'type', + 'checked', + 'indeterminate', + 'disabled', + 'tabindex', + 'name', + 'autofocus', + 'required', + 'form' + ], + + type: 'checkbox', + checked: false, + disabled: false, + indeterminate: false, + + init: function() { + this._super(); + this.on('change', this, this._updateElementValue); + }, + + didInsertElement: function() { + this._super(); + get(this, 'element').indeterminate = !!get(this, 'indeterminate'); + }, + + _updateElementValue: function() { + set(this, 'checked', this.$().prop('checked')); + } + }); + }); +define("ember-handlebars/controls/select", + ["ember-handlebars-compiler","ember-metal/enumerable_utils","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/collection_view","ember-metal/utils","ember-metal/is_none","ember-metal/computed","ember-runtime/system/native_array","ember-metal/mixin","ember-metal/properties","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var EmberHandlebars = __dependency1__["default"]; + + var forEach = __dependency2__.forEach; + var indexOf = __dependency2__.indexOf; + var indexesOf = __dependency2__.indexesOf; + var replace = __dependency2__.replace; + + var get = __dependency3__.get; + var set = __dependency4__.set; + var View = __dependency5__["default"]; + var CollectionView = __dependency6__["default"]; + var isArray = __dependency7__.isArray; + var isNone = __dependency8__["default"]; + var computed = __dependency9__.computed; + var emberA = __dependency10__.A; + var observer = __dependency11__.observer; + var defineProperty = __dependency12__.defineProperty; + + var precompileTemplate = EmberHandlebars.compile; + + var SelectOption = View.extend({ + instrumentDisplay: 'Ember.SelectOption', + + tagName: 'option', + attributeBindings: ['value', 'selected'], + + defaultTemplate: function(context, options) { + options = { data: options.data, hash: {} }; + EmberHandlebars.helpers.bind.call(context, "view.label", options); + }, + + init: function() { + this.labelPathDidChange(); + this.valuePathDidChange(); + + this._super(); + }, + + selected: computed(function() { + var content = get(this, 'content'); + var selection = get(this, 'parentView.selection'); + if (get(this, 'parentView.multiple')) { + return selection && indexOf(selection, content.valueOf()) > -1; + } else { + // Primitives get passed through bindings as objects... since + // `new Number(4) !== 4`, we use `==` below + return content == selection; // jshint ignore:line + } + }).property('content', 'parentView.selection'), + + labelPathDidChange: observer('parentView.optionLabelPath', function() { + var labelPath = get(this, 'parentView.optionLabelPath'); + + if (!labelPath) { return; } + + defineProperty(this, 'label', computed(function() { + return get(this, labelPath); + }).property(labelPath)); + }), + + valuePathDidChange: observer('parentView.optionValuePath', function() { + var valuePath = get(this, 'parentView.optionValuePath'); + + if (!valuePath) { return; } + + defineProperty(this, 'value', computed(function() { + return get(this, valuePath); + }).property(valuePath)); + }) + }); + + var SelectOptgroup = CollectionView.extend({ + instrumentDisplay: 'Ember.SelectOptgroup', + + tagName: 'optgroup', + attributeBindings: ['label'], + + selectionBinding: 'parentView.selection', + multipleBinding: 'parentView.multiple', + optionLabelPathBinding: 'parentView.optionLabelPath', + optionValuePathBinding: 'parentView.optionValuePath', + + itemViewClassBinding: 'parentView.optionView' + }); + + /** + The `Ember.Select` view class renders a + [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element, + allowing the user to choose from a list of options. + + The text and `value` property of each ` + + + ``` + + The `value` attribute of the selected `"); + return buffer; + } + + function program3(depth0,data) { + + var stack1; + stack1 = helpers.each.call(depth0, "view.groupedContent", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(4, program4, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } + function program4(depth0,data) { + + + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {hash:{ + 'content': ("content"), + 'label': ("label") + },hashTypes:{'content': "ID",'label': "ID"},hashContexts:{'content': depth0,'label': depth0},contexts:[depth0],types:["ID"],data:data}))); + } + + function program6(depth0,data) { + + var stack1; + stack1 = helpers.each.call(depth0, "view.content", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(7, program7, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } + function program7(depth0,data) { + + + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {hash:{ + 'content': ("") + },hashTypes:{'content': "ID"},hashContexts:{'content': depth0},contexts:[depth0],types:["ID"],data:data}))); + } + + stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + stack1 = helpers['if'].call(depth0, "view.optionGroupPath", {hash:{},hashTypes:{},hashContexts:{},inverse:self.program(6, program6, data),fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + return buffer; + + }), + attributeBindings: ['multiple', 'disabled', 'tabindex', 'name', 'required', 'autofocus', + 'form', 'size'], + + /** + The `multiple` attribute of the select element. Indicates whether multiple + options can be selected. + + @property multiple + @type Boolean + @default false + */ + multiple: false, + + /** + The `disabled` attribute of the select element. Indicates whether + the element is disabled from interactions. + + @property disabled + @type Boolean + @default false + */ + disabled: false, + + /** + The `required` attribute of the select element. Indicates whether + a selected option is required for form validation. + + @property required + @type Boolean + @default false + @since 1.5.0 + */ + required: false, + + /** + The list of options. + + If `optionLabelPath` and `optionValuePath` are not overridden, this should + be a list of strings, which will serve simultaneously as labels and values. + + Otherwise, this should be a list of objects. For instance: + + ```javascript + var App = Ember.Application.create(); + var App.MySelect = Ember.Select.extend({ + content: Ember.A([ + { id: 1, firstName: 'Yehuda' }, + { id: 2, firstName: 'Tom' } + ]), + optionLabelPath: 'content.firstName', + optionValuePath: 'content.id' + }); + ``` + + @property content + @type Array + @default null + */ + content: null, + + /** + When `multiple` is `false`, the element of `content` that is currently + selected, if any. + + When `multiple` is `true`, an array of such elements. + + @property selection + @type Object or Array + @default null + */ + selection: null, + + /** + In single selection mode (when `multiple` is `false`), value can be used to + get the current selection's value or set the selection by it's value. + + It is not currently supported in multiple selection mode. + + @property value + @type String + @default null + */ + value: computed(function(key, value) { + if (arguments.length === 2) { return value; } + var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); + return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection'); + }).property('selection'), + + /** + If given, a top-most dummy option will be rendered to serve as a user + prompt. + + @property prompt + @type String + @default null + */ + prompt: null, + + /** + The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionLabelPath + @type String + @default 'content' + */ + optionLabelPath: 'content', + + /** + The path of the option values. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionValuePath + @type String + @default 'content' + */ + optionValuePath: 'content', + + /** + The path of the option group. + When this property is used, `content` should be sorted by `optionGroupPath`. + + @property optionGroupPath + @type String + @default null + */ + optionGroupPath: null, + + /** + The view class for optgroup. + + @property groupView + @type Ember.View + @default Ember.SelectOptgroup + */ + groupView: SelectOptgroup, + + groupedContent: computed(function() { + var groupPath = get(this, 'optionGroupPath'); + var groupedContent = emberA(); + var content = get(this, 'content') || []; + + forEach(content, function(item) { + var label = get(item, groupPath); + + if (get(groupedContent, 'lastObject.label') !== label) { + groupedContent.pushObject({ + label: label, + content: emberA() + }); + } + + get(groupedContent, 'lastObject.content').push(item); + }); + + return groupedContent; + }).property('optionGroupPath', 'content.@each'), + + /** + The view class for option. + + @property optionView + @type Ember.View + @default Ember.SelectOption + */ + optionView: SelectOption, + + _change: function() { + if (get(this, 'multiple')) { + this._changeMultiple(); + } else { + this._changeSingle(); + } + }, + + selectionDidChange: observer('selection.@each', function() { + var selection = get(this, 'selection'); + if (get(this, 'multiple')) { + if (!isArray(selection)) { + set(this, 'selection', emberA([selection])); + return; + } + this._selectionDidChangeMultiple(); + } else { + this._selectionDidChangeSingle(); + } + }), + + valueDidChange: observer('value', function() { + var content = get(this, 'content'); + var value = get(this, 'value'); + var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); + var selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')); + var selection; + + if (value !== selectedValue) { + selection = content ? content.find(function(obj) { + return value === (valuePath ? get(obj, valuePath) : obj); + }) : null; + + this.set('selection', selection); + } + }), + + + _triggerChange: function() { + var selection = get(this, 'selection'); + var value = get(this, 'value'); + + if (!isNone(selection)) { this.selectionDidChange(); } + if (!isNone(value)) { this.valueDidChange(); } + + this._change(); + }, + + _changeSingle: function() { + var selectedIndex = this.$()[0].selectedIndex; + var content = get(this, 'content'); + var prompt = get(this, 'prompt'); + + if (!content || !get(content, 'length')) { return; } + if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; } + + if (prompt) { selectedIndex -= 1; } + set(this, 'selection', content.objectAt(selectedIndex)); + }, + + + _changeMultiple: function() { + var options = this.$('option:selected'); + var prompt = get(this, 'prompt'); + var offset = prompt ? 1 : 0; + var content = get(this, 'content'); + var selection = get(this, 'selection'); + + if (!content) { return; } + if (options) { + var selectedIndexes = options.map(function() { + return this.index - offset; + }).toArray(); + var newSelection = content.objectsAt(selectedIndexes); + + if (isArray(selection)) { + replace(selection, 0, get(selection, 'length'), newSelection); + } else { + set(this, 'selection', newSelection); + } + } + }, + + _selectionDidChangeSingle: function() { + var el = this.get('element'); + if (!el) { return; } + + var content = get(this, 'content'); + var selection = get(this, 'selection'); + var selectionIndex = content ? indexOf(content, selection) : -1; + var prompt = get(this, 'prompt'); + + if (prompt) { selectionIndex += 1; } + if (el) { el.selectedIndex = selectionIndex; } + }, + + _selectionDidChangeMultiple: function() { + var content = get(this, 'content'); + var selection = get(this, 'selection'); + var selectedIndexes = content ? indexesOf(content, selection) : [-1]; + var prompt = get(this, 'prompt'); + var offset = prompt ? 1 : 0; + var options = this.$('option'); + var adjusted; + + if (options) { + options.each(function() { + adjusted = this.index > -1 ? this.index - offset : -1; + this.selected = indexOf(selectedIndexes, adjusted) > -1; + }); + } + }, + + init: function() { + this._super(); + this.on("didInsertElement", this, this._triggerChange); + this.on("change", this, this._change); + } + }); + + __exports__["default"] = Select; + __exports__.Select = Select; + __exports__.SelectOption = SelectOption; + __exports__.SelectOptgroup = SelectOptgroup; + }); +define("ember-handlebars/controls/text_area", + ["ember-metal/property_get","ember-views/views/component","ember-handlebars/controls/text_support","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-handlebars + */ + var get = __dependency1__.get; + var Component = __dependency2__["default"]; + var TextSupport = __dependency3__["default"]; + var observer = __dependency4__.observer; + + /** + The internal class used to create textarea element when the `{{textarea}}` + helper is used. + + See [handlebars.helpers.textarea](/api/classes/Ember.Handlebars.helpers.html#method_textarea) for usage details. + + ## Layout and LayoutName properties + + Because HTML `textarea` elements do not contain inner HTML the `layout` and + `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextArea + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport + */ + __exports__["default"] = Component.extend(TextSupport, { + instrumentDisplay: '{{textarea}}', + + classNames: ['ember-text-area'], + + tagName: "textarea", + attributeBindings: ['rows', 'cols', 'name', 'selectionEnd', 'selectionStart', 'wrap', 'lang', 'dir'], + rows: null, + cols: null, + + _updateElementValue: observer('value', function() { + // We do this check so cursor position doesn't get affected in IE + var value = get(this, 'value'); + var $el = this.$(); + if ($el && value !== $el.val()) { + $el.val(value); + } + }), + + init: function() { + this._super(); + this.on("didInsertElement", this, this._updateElementValue); + } + }); + }); +define("ember-handlebars/controls/text_field", + ["ember-metal/property_get","ember-metal/property_set","ember-views/views/component","ember-handlebars/controls/text_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var get = __dependency1__.get; + var set = __dependency2__.set; + var Component = __dependency3__["default"]; + var TextSupport = __dependency4__["default"]; + + /** + + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `text`. + + See [Handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextField + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport + */ + __exports__["default"] = Component.extend(TextSupport, { + instrumentDisplay: '{{input type="text"}}', + + classNames: ['ember-text-field'], + tagName: "input", + attributeBindings: ['type', 'value', 'size', 'pattern', 'name', 'min', 'max', + 'accept', 'autocomplete', 'autosave', 'formaction', + 'formenctype', 'formmethod', 'formnovalidate', 'formtarget', + 'height', 'inputmode', 'list', 'multiple', 'step', 'lang', 'dir', + 'width'], + + /** + The `value` attribute of the input element. As the user inputs text, this + property is updated live. + + @property value + @type String + @default "" + */ + value: "", + + /** + The `type` attribute of the input element. + + @property type + @type String + @default "text" + */ + type: "text", + + /** + The `size` of the text field in characters. + + @property size + @type String + @default null + */ + size: null, + + /** + The `pattern` attribute of input element. + + @property pattern + @type String + @default null + */ + pattern: null, + + /** + The `min` attribute of input element used with `type="number"` or `type="range"`. + + @property min + @type String + @default null + @since 1.4.0 + */ + min: null, + + /** + The `max` attribute of input element used with `type="number"` or `type="range"`. + + @property max + @type String + @default null + @since 1.4.0 + */ + max: null + }); + }); +define("ember-handlebars/controls/text_support", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/target_action_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var get = __dependency1__.get; + var set = __dependency2__.set; + var Mixin = __dependency3__.Mixin; + var TargetActionSupport = __dependency4__["default"]; + + /** + Shared mixin used by `Ember.TextField` and `Ember.TextArea`. + + @class TextSupport + @namespace Ember + @uses Ember.TargetActionSupport + @extends Ember.Mixin + @private + */ + var TextSupport = Mixin.create(TargetActionSupport, { + value: "", + + attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex', 'readonly', + 'autofocus', 'form', 'selectionDirection', 'spellcheck', 'required', + 'title', 'autocapitalize', 'autocorrect'], + placeholder: null, + disabled: false, + maxlength: null, + + init: function() { + this._super(); + this.on("focusOut", this, this._elementValueDidChange); + this.on("change", this, this._elementValueDidChange); + this.on("paste", this, this._elementValueDidChange); + this.on("cut", this, this._elementValueDidChange); + this.on("input", this, this._elementValueDidChange); + this.on("keyUp", this, this.interpretKeyEvents); + }, + + /** + The action to be sent when the user presses the return key. + + This is similar to the `{{action}}` helper, but is fired when + the user presses the return key when editing a text field, and sends + the value of the field as the context. + + @property action + @type String + @default null + */ + action: null, + + /** + The event that should send the action. + + Options are: + + * `enter`: the user pressed enter + * `keyPress`: the user pressed a key + + @property onEvent + @type String + @default enter + */ + onEvent: 'enter', + + /** + Whether they `keyUp` event that triggers an `action` to be sent continues + propagating to other views. + + By default, when the user presses the return key on their keyboard and + the text field has an `action` set, the action will be sent to the view's + controller and the key event will stop propagating. + + If you would like parent views to receive the `keyUp` event even after an + action has been dispatched, set `bubbles` to true. + + @property bubbles + @type Boolean + @default false + */ + bubbles: false, + + interpretKeyEvents: function(event) { + var map = TextSupport.KEY_EVENTS; + var method = map[event.keyCode]; + + this._elementValueDidChange(); + if (method) { return this[method](event); } + }, + + _elementValueDidChange: function() { + set(this, 'value', this.$().val()); + }, + + /** + Called when the user inserts a new line. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13. + Uses sendAction to send the `enter` action. + + @method insertNewline + @param {Event} event + */ + insertNewline: function(event) { + sendAction('enter', this, event); + sendAction('insert-newline', this, event); + }, + + /** + Called when the user hits escape. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27. + Uses sendAction to send the `escape-press` action. + + @method cancel + @param {Event} event + */ + cancel: function(event) { + sendAction('escape-press', this, event); + }, + + /** + Called when the text area is focused. + + Uses sendAction to send the `focus-in` action. + + @method focusIn + @param {Event} event + */ + focusIn: function(event) { + sendAction('focus-in', this, event); + }, + + /** + Called when the text area is blurred. + + Uses sendAction to send the `focus-out` action. + + @method focusOut + @param {Event} event + */ + focusOut: function(event) { + sendAction('focus-out', this, event); + }, + + /** + Called when the user presses a key. Enabled by setting + the `onEvent` property to `keyPress`. + + Uses sendAction to send the `key-press` action. + + @method keyPress + @param {Event} event + */ + keyPress: function(event) { + sendAction('key-press', this, event); + } + + }); + + TextSupport.KEY_EVENTS = { + 13: 'insertNewline', + 27: 'cancel' + }; + + // In principle, this shouldn't be necessary, but the legacy + // sendAction semantics for TextField are different from + // the component semantics so this method normalizes them. + function sendAction(eventName, view, event) { + var action = get(view, eventName); + var on = get(view, 'onEvent'); + var value = get(view, 'value'); + + // back-compat support for keyPress as an event name even though + // it's also a method name that consumes the event (and therefore + // incompatible with sendAction semantics). + if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) { + view.sendAction('action', value); + } + + view.sendAction(eventName, value); + + if (action || on === eventName) { + if(!get(view, 'bubbles')) { + event.stopPropagation(); + } + } + } + + __exports__["default"] = TextSupport; + }); +define("ember-handlebars/ext", + ["ember-metal/core","ember-runtime/system/string","ember-handlebars-compiler","ember-metal/property_get","ember-metal/error","ember-metal/mixin","ember-views/views/view","ember-handlebars/views/metamorph_view","ember-metal/path_cache","ember-metal/is_empty","ember-metal/cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.assert, Ember.Handlebars, Ember.lookup + // var emberAssert = Ember.assert; + + var fmt = __dependency2__.fmt; + + var EmberHandlebars = __dependency3__["default"]; + var helpers = EmberHandlebars.helpers; + + var get = __dependency4__.get; + var EmberError = __dependency5__["default"]; + var IS_BINDING = __dependency6__.IS_BINDING; + + var View = __dependency7__["default"]; + var _Metamorph = __dependency8__._Metamorph; + var detectIsGlobal = __dependency9__.isGlobal; + + // late bound via requireModule because of circular dependencies. + var resolveHelper, SimpleHandlebarsView; + + var isEmpty = __dependency10__["default"]; + + var slice = [].slice; + var originalTemplate = EmberHandlebars.template; + + /** + If a path starts with a reserved keyword, returns the root + that should be used. + + @private + @method normalizePath + @for Ember + @param root {Object} + @param path {String} + @param data {Hash} + */ + + var Cache = __dependency11__["default"]; + + var FIRST_SEGMENT_CACHE = new Cache(1000, function(path){ + return path.split('.', 1)[0]; + }); + + function normalizePath(root, path, data) { + var keywords = (data && data.keywords) || {}; + var keyword, isKeyword; + + // Get the first segment of the path. For example, if the + // path is "foo.bar.baz", returns "foo". + keyword = FIRST_SEGMENT_CACHE.get(path); + + // Test to see if the first path is a keyword that has been + // passed along in the view's data hash. If so, we will treat + // that object as the new root. + if (keywords.hasOwnProperty(keyword)) { + // Look up the value in the template's data hash. + root = keywords[keyword]; + isKeyword = true; + + // Handle cases where the entire path is the reserved + // word. In that case, return the object itself. + if (path === keyword) { + path = ''; + } else { + // Strip the keyword from the path and look up + // the remainder from the newly found root. + path = path.substr(keyword.length+1); + } + } + + return { + root: root, + path: path, + isKeyword: isKeyword + }; + } + + + /** + Lookup both on root and on window. If the path starts with + a keyword, the corresponding object will be looked up in the + template's data hash and used to resolve the path. + + @method get + @for Ember.Handlebars + @param {Object} root The object to look up the property on + @param {String} path The path to be lookedup + @param {Object} options The template's option hash + */ + function handlebarsGet(root, path, options) { + var data = options && options.data; + var normalizedPath = normalizePath(root, path, data); + var value; + + // In cases where the path begins with a keyword, change the + // root to the value represented by that keyword, and ensure + // the path is relative to it. + root = normalizedPath.root; + path = normalizedPath.path; + + // Ember.get with a null root and GlobalPath will fall back to + // Ember.lookup, which is no longer allowed in templates. + // + // But when outputting a primitive, root will be the primitive + // and path a blank string. These primitives should pass through + // to `get`. + if (root || path === '') { + value = get(root, path); + } + + if (detectIsGlobal(path)) { + if (value === undefined && root !== Ember.lookup) { + root = Ember.lookup; + value = get(root, path); + } + if (root === Ember.lookup || root === null) { + Ember.deprecate("Global lookup of "+path+" from a Handlebars template is deprecated."); + } + } + + return value; + } + + /** + handlebarsGetView resolves a view based on strings passed into a template. + For example: + + ```handlebars + {{view "some-view"}} + {{view view.someView}} + {{view App.SomeView}} {{! deprecated }} + ``` + + A value is first checked to be a string- non-strings are presumed to be + an object and returned. This handles the "access a view on a context" + case (line 2 in the above examples). + + Next a string is normalized, then called on the context with `get`. If + there is still no value, a GlobalPath will be fetched from the global + context (raising a deprecation) and a localPath will be passed to the + container to be looked up. + + @private + @for Ember.Handlebars + @param {Object} context The context of the template being rendered + @param {String} path The path to be lookedup + @param {Object} container The container + @param {Object} data The template's data hash + */ + function handlebarsGetView(context, path, container, data) { + var viewClass; + if ('string' === typeof path) { + if (data) { + var normalizedPath = normalizePath(context, path, data); + context = normalizedPath.root; + path = normalizedPath.path; + } + + // Only lookup view class on context if there is a context. If not, + // the global lookup path on get may kick in. + viewClass = context && get(context, path); + var isGlobal = detectIsGlobal(path); + + if (!viewClass && !isGlobal) { + Ember.assert("View requires a container to resolve views not passed in through the context", !!container); + viewClass = container.lookupFactory('view:'+path); + } + if (!viewClass && isGlobal) { + var globalViewClass = get(path); + Ember.deprecate('Resolved the view "'+path+'" on the global context. Pass a view name to be looked up on the container instead, such as {{view "select"}}. http://emberjs.com/guides/deprecations#toc_global-lookup-of-views-since-1-8', !globalViewClass); + if (globalViewClass) { + viewClass = globalViewClass; + } + } + } else { + viewClass = path; + } + + // Sometimes a view's value is yet another path + if ('string' === typeof viewClass && data && data.view) { + viewClass = handlebarsGetView(data.view, viewClass, container, data); + } + + Ember.assert( + fmt(path+" must be a subclass of Ember.View, not %@", [viewClass]), + View.detect(viewClass) + ); + + return viewClass; + } + + /** + This method uses `Ember.Handlebars.get` to lookup a value, then ensures + that the value is escaped properly. + + If `unescaped` is a truthy value then the escaping will not be performed. + + @method getEscaped + @for Ember.Handlebars + @param {Object} root The object to look up the property on + @param {String} path The path to be lookedup + @param {Object} options The template's option hash + @since 1.4.0 + */ + function getEscaped(root, path, options) { + var result = handlebarsGet(root, path, options); + + if (result === null || result === undefined) { + result = ""; + } else if (!(result instanceof Handlebars.SafeString)) { + result = String(result); + } + if (!options.hash.unescaped){ + result = Handlebars.Utils.escapeExpression(result); + } + + return result; + } + + __exports__.getEscaped = getEscaped;function resolveParams(context, params, options) { + var resolvedParams = [], types = options.types, param, type; + + for (var i=0, l=params.length; i{{user.name}} + +
+
{{user.role.label}}
+ {{user.role.id}} + +

{{user.role.description}}

+
+ ``` + + `{{with}}` can be our best friend in these cases, + instead of writing `user.role.*` over and over, we use `{{#with user.role}}`. + Now the context within the `{{#with}} .. {{/with}}` block is `user.role` so you can do the following: + + ```handlebars +
{{user.name}}
+ +
+ {{#with user.role}} +
{{label}}
+ {{id}} + +

{{description}}

+ {{/with}} +
+ ``` + + ### `as` operator + + This operator aliases the scope to a new name. It's helpful for semantic clarity and to retain + default scope or to reference from another `{{with}}` block. + + ```handlebars + // posts might not be + {{#with user.posts as blogPosts}} +
+ There are {{blogPosts.length}} blog posts written by {{user.name}}. +
+ + {{#each post in blogPosts}} +
  • {{post.title}}
  • + {{/each}} + {{/with}} + ``` + + Without the `as` operator, it would be impossible to reference `user.name` in the example above. + + NOTE: The alias should not reuse a name from the bound property path. + For example: `{{#with foo.bar as foo}}` is not supported because it attempts to alias using + the first part of the property path, `foo`. Instead, use `{{#with foo.bar as baz}}`. + + ### `controller` option + + Adding `controller='something'` instructs the `{{with}}` helper to create and use an instance of + the specified controller with the new context as its content. + + This is very similar to using an `itemController` option with the `{{each}}` helper. + + ```handlebars + {{#with users.posts controller='userBlogPosts'}} + {{!- The current context is wrapped in our controller instance }} + {{/with}} + ``` + + In the above example, the template provided to the `{{with}}` block is now wrapped in the + `userBlogPost` controller, which provides a very elegant way to decorate the context with custom + functions/properties. + + @method with + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function withHelper(context, options) { + var bindContext, preserveContext, controller; + var helperName = 'with'; + + if (arguments.length === 4) { + var keywordName, path, rootPath, normalized, contextPath; + + Ember.assert("If you pass more than one argument to the with helper, it must be in the form #with foo as bar", arguments[1] === "as"); + options = arguments[3]; + keywordName = arguments[2]; + path = arguments[0]; + + if (path) { + helperName += ' ' + path + ' as ' + keywordName; + } + + Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); + + var localizedOptions = o_create(options); + localizedOptions.data = o_create(options.data); + localizedOptions.data.keywords = o_create(options.data.keywords || {}); + + if (isGlobalPath(path)) { + contextPath = path; + } else { + normalized = normalizePath(this, path, options.data); + path = normalized.path; + rootPath = normalized.root; + + // This is a workaround for the fact that you cannot bind separate objects + // together. When we implement that functionality, we should use it here. + var contextKey = jQuery.expando + guidFor(rootPath); + localizedOptions.data.keywords[contextKey] = rootPath; + // if the path is '' ("this"), just bind directly to the current context + contextPath = path ? contextKey + '.' + path : contextKey; + } + + localizedOptions.hash.keywordName = keywordName; + localizedOptions.hash.keywordPath = contextPath; + + bindContext = this; + context = contextPath; + options = localizedOptions; + preserveContext = true; + } else { + Ember.assert("You must pass exactly one argument to the with helper", arguments.length === 2); + Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); + + helperName += ' ' + context; + bindContext = options.contexts[0]; + preserveContext = false; + } + + options.helperName = helperName; + options.isWithHelper = true; + + return bind.call(bindContext, context, options, preserveContext, exists); + } + /** + See [boundIf](/api/classes/Ember.Handlebars.helpers.html#method_boundIf) + and [unboundIf](/api/classes/Ember.Handlebars.helpers.html#method_unboundIf) + + @method if + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function ifHelper(context, options) { + Ember.assert("You must pass exactly one argument to the if helper", arguments.length === 2); + Ember.assert("You must pass a block to the if helper", options.fn && options.fn !== Handlebars.VM.noop); + + options.helperName = options.helperName || ('if ' + context); + + if (options.data.isUnbound) { + return helpers.unboundIf.call(options.contexts[0], context, options); + } else { + return helpers.boundIf.call(options.contexts[0], context, options); + } + } + + /** + @method unless + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function unlessHelper(context, options) { + Ember.assert("You must pass exactly one argument to the unless helper", arguments.length === 2); + Ember.assert("You must pass a block to the unless helper", options.fn && options.fn !== Handlebars.VM.noop); + + var fn = options.fn; + var inverse = options.inverse; + var helperName = 'unless'; + + if (context) { + helperName += ' ' + context; + } + + options.fn = inverse; + options.inverse = fn; + + options.helperName = options.helperName || helperName; + + if (options.data.isUnbound) { + return helpers.unboundIf.call(options.contexts[0], context, options); + } else { + return helpers.boundIf.call(options.contexts[0], context, options); + } + } + + /** + `bind-attr` allows you to create a binding between DOM element attributes and + Ember objects. For example: + + ```handlebars + imageTitle + ``` + + The above handlebars template will fill the ``'s `src` attribute with + the value of the property referenced with `"imageUrl"` and its `alt` + attribute with the value of the property referenced with `"imageTitle"`. + + If the rendering context of this template is the following object: + + ```javascript + { + imageUrl: 'http://lolcats.info/haz-a-funny', + imageTitle: 'A humorous image of a cat' + } + ``` + + The resulting HTML output will be: + + ```html + A humorous image of a cat + ``` + + `bind-attr` cannot redeclare existing DOM element attributes. The use of `src` + in the following `bind-attr` example will be ignored and the hard coded value + of `src="/failwhale.gif"` will take precedence: + + ```handlebars + imageTitle + ``` + + ### `bind-attr` and the `class` attribute + + `bind-attr` supports a special syntax for handling a number of cases unique + to the `class` DOM element attribute. The `class` attribute combines + multiple discrete values into a single attribute as a space-delimited + list of strings. Each string can be: + + * a string return value of an object's property. + * a boolean return value of an object's property + * a hard-coded value + + A string return value works identically to other uses of `bind-attr`. The + return value of the property will become the value of the attribute. For + example, the following view and template: + + ```javascript + AView = View.extend({ + someProperty: function() { + return "aValue"; + }.property() + }) + ``` + + ```handlebars + + ``` + + A boolean return value will insert a specified class name if the property + returns `true` and remove the class name if the property returns `false`. + + A class name is provided via the syntax + `somePropertyName:class-name-if-true`. + + ```javascript + AView = View.extend({ + someBool: true + }) + ``` + + ```handlebars + + ``` + + Result in the following rendered output: + + ```html + + ``` + + An additional section of the binding can be provided if you want to + replace the existing class instead of removing it when the boolean + value changes: + + ```handlebars + + ``` + + A hard-coded value can be used by prepending `:` to the desired + class name: `:class-name-to-always-apply`. + + ```handlebars + + ``` + + Results in the following rendered output: + + ```html + + ``` + + All three strategies - string return value, boolean return value, and + hard-coded value – can be combined in a single declaration: + + ```handlebars + + ``` + + @method bind-attr + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string + */ + function bindAttrHelper(options) { + var attrs = options.hash; + + Ember.assert("You must specify at least one hash argument to bind-attr", !!keys(attrs).length); + + var view = options.data.view; + var ret = []; + + // we relied on the behavior of calling without + // context to mean this === window, but when running + // "use strict", it's possible for this to === undefined; + var ctx = this || window; + + // Generate a unique id for this element. This will be added as a + // data attribute to the element so it can be looked up when + // the bound property changes. + var dataId = uuid(); + + // Handle classes differently, as we can bind multiple classes + var classBindings = attrs['class']; + if (classBindings != null) { + var classResults = bindClasses(ctx, classBindings, view, dataId, options); + + ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"'); + delete attrs['class']; + } + + var attrKeys = keys(attrs); + + // For each attribute passed, create an observer and emit the + // current value of the property as an attribute. + forEach.call(attrKeys, function(attr) { + var path = attrs[attr]; + var normalized; + + Ember.assert(fmt("You must provide an expression as the value of bound attribute. You specified: %@=%@", [attr, path]), typeof path === 'string'); + + normalized = normalizePath(ctx, path, options.data); + + var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options); + var type = typeOf(value); + + Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean'); + + var observer; + + observer = function observer() { + var result = handlebarsGet(ctx, path, options); + + Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]), + result === null || result === undefined || typeof result === 'number' || + typeof result === 'string' || typeof result === 'boolean'); + + var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']"); + + // If we aren't able to find the element, it means the element + // to which we were bound has been removed from the view. + // In that case, we can assume the template has been re-rendered + // and we need to clean up the observer. + if (!elem || elem.length === 0) { + removeObserver(normalized.root, normalized.path, observer); + return; + } + + View.applyAttributeBindings(elem, attr, result); + }; + + // Add an observer to the view for when the property changes. + // When the observer fires, find the element using the + // unique data id and update the attribute to the new value. + // Note: don't add observer when path is 'this' or path + // is whole keyword e.g. {{#each x in list}} ... {{bind-attr attr="x"}} + if (path !== 'this' && !(normalized.isKeyword && normalized.path === '' )) { + view.registerObserver(normalized.root, normalized.path, observer); + } + + // if this changes, also change the logic in ember-views/lib/views/view.js + if ((type === 'string' || (type === 'number' && !isNaN(value)))) { + ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"'); + } else if (value && type === 'boolean') { + // The developer controls the attr name, so it should always be safe + ret.push(attr + '="' + attr + '"'); + } + }, this); + + // Add the unique identifier + // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG + ret.push('data-bindattr-' + dataId + '="' + dataId + '"'); + return new SafeString(ret.join(' ')); + } + + /** + See `bind-attr` + + @method bindAttr + @for Ember.Handlebars.helpers + @deprecated + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function bindAttrHelperDeprecated() { + Ember.warn("The 'bindAttr' view helper is deprecated in favor of 'bind-attr'"); + return helpers['bind-attr'].apply(this, arguments); + } + + /** + Helper that, given a space-separated string of property paths and a context, + returns an array of class names. Calling this method also has the side + effect of setting up observers at those property paths, such that if they + change, the correct class name will be reapplied to the DOM element. + + For example, if you pass the string "fooBar", it will first look up the + "fooBar" value of the context. If that value is true, it will add the + "foo-bar" class to the current element (i.e., the dasherized form of + "fooBar"). If the value is a string, it will add that string as the class. + Otherwise, it will not add any new class name. + + @private + @method bindClasses + @for Ember.Handlebars + @param {Ember.Object} context The context from which to lookup properties + @param {String} classBindings A string, space-separated, of class bindings + to use + @param {View} view The view in which observers should look for the + element to update + @param {Srting} bindAttrId Optional bindAttr id used to lookup elements + @return {Array} An array of class names to add + */ + function bindClasses(context, classBindings, view, bindAttrId, options) { + var ret = []; + var newClass, value, elem; + + // Helper method to retrieve the property from the context and + // determine which class string to return, based on whether it is + // a Boolean or not. + var classStringForPath = function(root, parsedPath, options) { + var val; + var path = parsedPath.path; + + if (path === 'this') { + val = root; + } else if (path === '') { + val = true; + } else { + val = handlebarsGet(root, path, options); + } + + return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }; + + // For each property passed, loop through and setup + // an observer. + forEach.call(classBindings.split(' '), function(binding) { + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + var observer; + var parsedPath = View._parsePropertyPath(binding); + var path = parsedPath.path; + var pathRoot = context; + var normalized; + + if (path !== '' && path !== 'this') { + normalized = normalizePath(context, path, options.data); + + pathRoot = normalized.root; + path = normalized.path; + } + + // Set up an observer on the context. If the property changes, toggle the + // class name. + observer = function() { + // Get the current value of the property + newClass = classStringForPath(context, parsedPath, options); + elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$(); + + // If we can't find the element anymore, a parent template has been + // re-rendered and we've been nuked. Remove the observer. + if (!elem || elem.length === 0) { + removeObserver(pathRoot, path, observer); + } else { + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + } + }; + + if (path !== '' && path !== 'this') { + view.registerObserver(pathRoot, path, observer); + } + + // We've already setup the observer; now we just need to figure out the + // correct behavior right now on the first pass through. + value = classStringForPath(context, parsedPath, options); + + if (value) { + ret.push(value); + + // Make sure we save the current value so that it can be removed if the + // observer fires. + oldClass = value; + } + }); + + return ret; + } + + __exports__.bind = bind; + __exports__._triageMustacheHelper = _triageMustacheHelper; + __exports__.resolveHelper = resolveHelper; + __exports__.bindHelper = bindHelper; + __exports__.boundIfHelper = boundIfHelper; + __exports__.unboundIfHelper = unboundIfHelper; + __exports__.withHelper = withHelper; + __exports__.ifHelper = ifHelper; + __exports__.unlessHelper = unlessHelper; + __exports__.bindAttrHelper = bindAttrHelper; + __exports__.bindAttrHelperDeprecated = bindAttrHelperDeprecated; + __exports__.bindClasses = bindClasses; + }); +define("ember-handlebars/helpers/collection", + ["ember-metal/core","ember-metal/utils","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-handlebars/ext","ember-handlebars/helpers/view","ember-metal/computed","ember-views/views/collection_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.deprecate + var inspect = __dependency2__.inspect; + + // var emberAssert = Ember.assert; + // emberDeprecate = Ember.deprecate; + + var EmberHandlebars = __dependency3__["default"]; + var helpers = EmberHandlebars.helpers; + + var fmt = __dependency4__.fmt; + var get = __dependency5__.get; + var handlebarsGet = __dependency6__.handlebarsGet; + var handlebarsGetView = __dependency6__.handlebarsGetView; + var ViewHelper = __dependency7__.ViewHelper; + var computed = __dependency8__.computed; + var CollectionView = __dependency9__["default"]; + + var alias = computed.alias; + /** + `{{collection}}` is a `Ember.Handlebars` helper for adding instances of + `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html) + for additional information on how a `CollectionView` functions. + + `{{collection}}`'s primary use is as a block helper with a `contentBinding` + option pointing towards an `Ember.Array`-compatible object. An `Ember.View` + instance will be created for each item in its `content` property. Each view + will have its own `content` property set to the appropriate item in the + collection. + + The provided block will be applied as the template for each item's view. + + Given an empty `` the following template: + + ```handlebars + {{! application.hbs }} + {{#collection content=model}} + Hi {{view.content.name}} + {{/collection}} + ``` + + And the following application code + + ```javascript + App = Ember.Application.create(); + App.ApplicationRoute = Ember.Route.extend({ + model: function(){ + return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; + } + }); + ``` + + The following HTML will result: + + ```html +
    +
    Hi Yehuda
    +
    Hi Tom
    +
    Hi Peter
    +
    + ``` + + ### Non-block version of collection + + If you provide an `itemViewClass` option that has its own `template` you may + omit the block. + + The following template: + + ```handlebars + {{! application.hbs }} + {{collection content=model itemViewClass="an-item"}} + ``` + + And application code + + ```javascript + App = Ember.Application.create(); + App.ApplicationRoute = Ember.Route.extend({ + model: function(){ + return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; + } + }); + + App.AnItemView = Ember.View.extend({ + template: Ember.Handlebars.compile("Greetings {{view.content.name}}") + }); + ``` + + Will result in the HTML structure below + + ```html +
    +
    Greetings Yehuda
    +
    Greetings Tom
    +
    Greetings Peter
    +
    + ``` + + ### Specifying a CollectionView subclass + + By default the `{{collection}}` helper will create an instance of + `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to + the helper by passing it as the first argument: + + ```handlebars + {{#collection "my-custom-collection" content=model}} + Hi {{view.content.name}} + {{/collection}} + ``` + + This example would look for the class `App.MyCustomCollection`. + + ### Forwarded `item.*`-named Options + + As with the `{{view}}`, helper options passed to the `{{collection}}` will be + set on the resulting `Ember.CollectionView` as properties. Additionally, + options prefixed with `item` will be applied to the views rendered for each + item (note the camelcasing): + + ```handlebars + {{#collection content=model + itemTagName="p" + itemClassNames="greeting"}} + Howdy {{view.content.name}} + {{/collection}} + ``` + + Will result in the following HTML structure: + + ```html +
    +

    Howdy Yehuda

    +

    Howdy Tom

    +

    Howdy Peter

    +
    + ``` + + @method collection + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + @deprecated Use `{{each}}` helper instead. + */ + function collectionHelper(path, options) { + Ember.deprecate("Using the {{collection}} helper without specifying a class has been deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection'); + + // If no path is provided, treat path param as options. + if (path && path.data && path.data.isRenderData) { + options = path; + path = undefined; + Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1); + } else { + Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2); + } + + var fn = options.fn, + data = options.data, + inverse = options.inverse, + view = options.data.view, + // This should be deterministic, and should probably come from a + // parent view and not the controller. + container = (view.controller && view.controller.container ? view.controller.container : view.container); + + // If passed a path string, convert that into an object. + // Otherwise, just default to the standard class. + var collectionClass; + if (path) { + collectionClass = handlebarsGetView(this, path, container, options.data); + Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass); + } + else { + collectionClass = CollectionView; + } + + var hash = options.hash; + var itemHash = {}; + var match; + + // Extract item view class if provided else default to the standard class + var collectionPrototype = collectionClass.proto(); + var itemViewClass; + + if (hash.itemView) { + itemViewClass = handlebarsGetView(this, hash.itemView, container, options.data); + } else if (hash.itemViewClass) { + itemViewClass = handlebarsGetView(collectionPrototype, hash.itemViewClass, container, options.data); + } else { + itemViewClass = handlebarsGetView(collectionPrototype, collectionPrototype.itemViewClass, container, options.data); + } + + Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewClass]), !!itemViewClass); + + delete hash.itemViewClass; + delete hash.itemView; + + // Go through options passed to the {{collection}} helper and extract options + // that configure item views instead of the collection itself. + for (var prop in hash) { + if (hash.hasOwnProperty(prop)) { + match = prop.match(/^item(.)(.*)$/); + + if (match && prop !== 'itemController') { + // Convert itemShouldFoo -> shouldFoo + itemHash[match[1].toLowerCase() + match[2]] = hash[prop]; + // Delete from hash as this will end up getting passed to the + // {{view}} helper method. + delete hash[prop]; + } + } + } + + if (fn) { + itemHash.template = fn; + delete options.fn; + } + + var emptyViewClass; + if (inverse && inverse !== EmberHandlebars.VM.noop) { + emptyViewClass = get(collectionPrototype, 'emptyViewClass'); + emptyViewClass = emptyViewClass.extend({ + template: inverse, + tagName: itemHash.tagName + }); + } else if (hash.emptyViewClass) { + emptyViewClass = handlebarsGetView(this, hash.emptyViewClass, container, options.data); + } + if (emptyViewClass) { hash.emptyView = emptyViewClass; } + + if (hash.keyword) { + itemHash._context = this; + } else { + itemHash._context = alias('content'); + } + + var viewOptions = ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this); + hash.itemViewClass = itemViewClass.extend(viewOptions); + + options.helperName = options.helperName || 'collection'; + + return helpers.view.call(this, collectionClass, options); + } + + __exports__["default"] = collectionHelper; + }); +define("ember-handlebars/helpers/debug", + ["ember-metal/core","ember-metal/utils","ember-metal/logger","ember-metal/property_get","ember-handlebars/ext","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /*jshint debug:true*/ + + /** + @module ember + @submodule ember-handlebars + */ + var Ember = __dependency1__["default"]; + // Ember.FEATURES, + var inspect = __dependency2__.inspect; + var Logger = __dependency3__["default"]; + + var get = __dependency4__.get; + var normalizePath = __dependency5__.normalizePath; + var handlebarsGet = __dependency5__.handlebarsGet; + + var a_slice = [].slice; + + /** + `log` allows you to output the value of variables in the current rendering + context. `log` also accepts primitive types such as strings or numbers. + + ```handlebars + {{log "myVariable:" myVariable }} + ``` + + @method log + @for Ember.Handlebars.helpers + @param {String} property + */ + function logHelper() { + var params = a_slice.call(arguments, 0, -1); + var options = arguments[arguments.length - 1]; + var logger = Logger.log; + var values = []; + var allowPrimitives = true; + + for (var i = 0; i < params.length; i++) { + var type = options.types[i]; + + if (type === 'ID' || !allowPrimitives) { + var context = (options.contexts && options.contexts[i]) || this; + var normalized = normalizePath(context, params[i], options.data); + + if (normalized.path === 'this') { + values.push(normalized.root); + } else { + values.push(handlebarsGet(normalized.root, normalized.path, options)); + } + } else { + values.push(params[i]); + } + } + + logger.apply(logger, values); + } + + /** + Execute the `debugger` statement in the current context. + + ```handlebars + {{debugger}} + ``` + + Before invoking the `debugger` statement, there + are a few helpful variables defined in the + body of this helper that you can inspect while + debugging that describe how and where this + helper was invoked: + + - templateContext: this is most likely a controller + from which this template looks up / displays properties + - typeOfTemplateContext: a string description of + what the templateContext is + + For example, if you're wondering why a value `{{foo}}` + isn't rendering as expected within a template, you + could place a `{{debugger}}` statement, and when + the `debugger;` breakpoint is hit, you can inspect + `templateContext`, determine if it's the object you + expect, and/or evaluate expressions in the console + to perform property lookups on the `templateContext`: + + ``` + > templateContext.get('foo') // -> "" + ``` + + @method debugger + @for Ember.Handlebars.helpers + @param {String} property + */ + function debuggerHelper(options) { + + // These are helpful values you can inspect while debugging. + var templateContext = this; + var typeOfTemplateContext = inspect(templateContext); + Ember.Logger.info('Use `this` to access the context of the calling template.'); + + debugger; + } + + __exports__.logHelper = logHelper; + __exports__.debuggerHelper = debuggerHelper; + }); +define("ember-handlebars/helpers/each", + ["ember-metal/core","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-metal/property_set","ember-views/views/collection_view","ember-metal/binding","ember-runtime/mixins/controller","ember-runtime/controllers/array_controller","ember-runtime/mixins/array","ember-runtime/copy","ember-metal/run_loop","ember-metal/events","ember-handlebars/ext","ember-metal/computed","ember-metal/observer","ember-handlebars/views/metamorph_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-handlebars + */ + var Ember = __dependency1__["default"]; + // Ember.assert;, Ember.K + var K = Ember.K; + + var EmberHandlebars = __dependency2__["default"]; + var helpers = EmberHandlebars.helpers; + + var fmt = __dependency3__.fmt; + var get = __dependency4__.get; + var set = __dependency5__.set; + var CollectionView = __dependency6__["default"]; + var Binding = __dependency7__.Binding; + var ControllerMixin = __dependency8__["default"]; + var ArrayController = __dependency9__["default"]; + var EmberArray = __dependency10__["default"]; + var copy = __dependency11__["default"]; + var run = __dependency12__["default"]; + var on = __dependency13__.on; + var handlebarsGet = __dependency14__.handlebarsGet; + var computed = __dependency15__.computed; + + var addObserver = __dependency16__.addObserver; + var removeObserver = __dependency16__.removeObserver; + var addBeforeObserver = __dependency16__.addBeforeObserver; + var removeBeforeObserver = __dependency16__.removeBeforeObserver; + + var _Metamorph = __dependency17__._Metamorph; + var _MetamorphView = __dependency17__._MetamorphView; + + var EachView = CollectionView.extend(_Metamorph, { + + init: function() { + var itemController = get(this, 'itemController'); + var binding; + + if (itemController) { + var controller = get(this, 'controller.container').lookupFactory('controller:array').create({ + _isVirtual: true, + parentController: get(this, 'controller'), + itemController: itemController, + target: get(this, 'controller'), + _eachView: this + }); + + this.disableContentObservers(function() { + set(this, 'content', controller); + binding = new Binding('content', '_eachView.dataSource').oneWay(); + binding.connect(controller); + }); + + set(this, '_arrayController', controller); + } else { + this.disableContentObservers(function() { + binding = new Binding('content', 'dataSource').oneWay(); + binding.connect(this); + }); + } + + return this._super(); + }, + + _assertArrayLike: function(content) { + Ember.assert(fmt("The value that #each loops over must be an Array. You " + + "passed %@, but it should have been an ArrayController", + [content.constructor]), + !ControllerMixin.detect(content) || + (content && content.isGenerated) || + content instanceof ArrayController); + Ember.assert(fmt("The value that #each loops over must be an Array. You passed %@", [(ControllerMixin.detect(content) && content.get('model') !== undefined) ? fmt("'%@' (wrapped in %@)", [content.get('model'), content]) : content]), EmberArray.detect(content)); + }, + + disableContentObservers: function(callback) { + removeBeforeObserver(this, 'content', null, '_contentWillChange'); + removeObserver(this, 'content', null, '_contentDidChange'); + + callback.call(this); + + addBeforeObserver(this, 'content', null, '_contentWillChange'); + addObserver(this, 'content', null, '_contentDidChange'); + }, + + itemViewClass: _MetamorphView, + emptyViewClass: _MetamorphView, + + createChildView: function(view, attrs) { + view = this._super(view, attrs); + + // At the moment, if a container view subclass wants + // to insert keywords, it is responsible for cloning + // the keywords hash. This will be fixed momentarily. + var keyword = get(this, 'keyword'); + var content = get(view, 'content'); + + if (keyword) { + var data = get(view, 'templateData'); + + data = copy(data); + data.keywords = view.cloneKeywords(); + set(view, 'templateData', data); + + // In this case, we do not bind, because the `content` of + // a #each item cannot change. + data.keywords[keyword] = content; + } + + // If {{#each}} is looping over an array of controllers, + // point each child view at their respective controller. + if (content && content.isController) { + set(view, 'controller', content); + } + + return view; + }, + + destroy: function() { + if (!this._super()) { return; } + + var arrayController = get(this, '_arrayController'); + + if (arrayController) { + arrayController.destroy(); + } + + return this; + } + }); + + var GroupedEach = EmberHandlebars.GroupedEach = function(context, path, options) { + var self = this; + var normalized = EmberHandlebars.normalizePath(context, path, options.data); + + this.context = context; + this.path = path; + this.options = options; + this.template = options.fn; + this.containingView = options.data.view; + this.normalizedRoot = normalized.root; + this.normalizedPath = normalized.path; + this.content = this.lookupContent(); + + this.addContentObservers(); + this.addArrayObservers(); + + this.containingView.on('willClearRender', function() { + self.destroy(); + }); + }; + + GroupedEach.prototype = { + contentWillChange: function() { + this.removeArrayObservers(); + }, + + contentDidChange: function() { + this.content = this.lookupContent(); + this.addArrayObservers(); + this.rerenderContainingView(); + }, + + contentArrayWillChange: K, + + contentArrayDidChange: function() { + this.rerenderContainingView(); + }, + + lookupContent: function() { + return handlebarsGet(this.normalizedRoot, this.normalizedPath, this.options); + }, + + addArrayObservers: function() { + if (!this.content) { return; } + + this.content.addArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + removeArrayObservers: function() { + if (!this.content) { return; } + + this.content.removeArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + addContentObservers: function() { + addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange); + addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange); + }, + + removeContentObservers: function() { + removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange); + removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange); + }, + + render: function() { + if (!this.content) { return; } + + var content = this.content; + var contentLength = get(content, 'length'); + var options = this.options; + var data = options.data; + var template = this.template; + + data.insideEach = true; + for (var i = 0; i < contentLength; i++) { + var context = content.objectAt(i); + options.data.keywords[options.hash.keyword] = context; + template(context, { data: data }); + } + }, + + rerenderContainingView: function() { + var self = this; + run.scheduleOnce('render', this, function() { + // It's possible it's been destroyed after we enqueued a re-render call. + if (!self.destroyed) { + self.containingView.rerender(); + } + }); + }, + + destroy: function() { + this.removeContentObservers(); + if (this.content) { + this.removeArrayObservers(); + } + this.destroyed = true; + } + }; + + /** + The `{{#each}}` helper loops over elements in a collection. It is an extension + of the base Handlebars `{{#each}}` helper. + + The default behavior of `{{#each}}` is to yield its inner block once for every + item in an array. Each yield will provide the item as the context of the block. + + ```javascript + var developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}]; + ``` + + ```handlebars + {{#each developers}} + {{name}} + {{! `this` is each developer }} + {{/each}} + ``` + + `{{#each}}` supports an alternative syntax with element naming. This preserves + context of the yielded block: + + ```handlebars + {{#each person in developers}} + {{person.name}} + {{! `this` is whatever it was outside the #each }} + {{/each}} + ``` + + The same rules apply to arrays of primitives, but the items may need to be + references with `{{this}}`. + + ```javascript + var developerNames = ['Yehuda', 'Tom', 'Paul'] + ``` + + ```handlebars + {{#each developerNames}} + {{this}} + {{/each}} + ``` + + ### {{else}} condition + + `{{#each}}` can have a matching `{{else}}`. The contents of this block will render + if the collection is empty. + + ``` + {{#each person in developers}} + {{person.name}} + {{else}} +

    Sorry, nobody is available for this task.

    + {{/each}} + ``` + + ### Specifying an alternative view for each item + + `itemViewClass` can control which view will be used during the render of each + item's template. + + The following template: + + ```handlebars +
      + {{#each developers itemViewClass="person"}} + {{name}} + {{/each}} +
    + ``` + + Will use the following view for each item + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li' + }); + ``` + + Resulting in HTML output that looks like the following: + + ```html +
      +
    • Yehuda
    • +
    • Tom
    • +
    • Paul
    • +
    + ``` + + `itemViewClass` also enables a non-block form of `{{each}}`. The view + must {{#crossLink "Ember.View/toc_templates"}}provide its own template{{/crossLink}}, + and then the block should be dropped. An example that outputs the same HTML + as the previous one: + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li', + template: '{{name}}' + }); + ``` + + ```handlebars +
      + {{each developers itemViewClass="person"}} +
    + ``` + + ### Specifying an alternative view for no items (else) + + The `emptyViewClass` option provides the same flexibility to the `{{else}}` + case of the each helper. + + ```javascript + App.NoPeopleView = Ember.View.extend({ + tagName: 'li', + template: 'No person is available, sorry' + }); + ``` + + ```handlebars +
      + {{#each developers emptyViewClass="no-people"}} +
    • {{name}}
    • + {{/each}} +
    + ``` + + ### Wrapping each item in a controller + + Controllers in Ember manage state and decorate data. In many cases, + providing a controller for each item in a list can be useful. + Specifically, an {{#crossLink "Ember.ObjectController"}}Ember.ObjectController{{/crossLink}} + should probably be used. Item controllers are passed the item they + will present as a `model` property, and an object controller will + proxy property lookups to `model` for us. + + This allows state and decoration to be added to the controller + while any other property lookups are delegated to the model. An example: + + ```javascript + App.RecruitController = Ember.ObjectController.extend({ + isAvailableForHire: function() { + return !this.get('isEmployed') && this.get('isSeekingWork'); + }.property('isEmployed', 'isSeekingWork') + }) + ``` + + ```handlebars + {{#each person in developers itemController="recruit"}} + {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}} + {{/each}} + ``` + + ### (Experimental) Grouped Each + + If a list's membership often changes, but properties of items in that + group rarely change, a significant improvement in template rendering + time can be achieved by using the experimental [group helper](https://github.com/emberjs/group-helper). + + ```handlebars + {{#group}} + {{#each people}} + {{firstName}} {{lastName}} + {{/each}} + {{/group}} + ``` + + When the membership of `people` changes, or when any property changes, the entire + `{{#group}}` block will be re-rendered. + + An `{{#each}}` inside the `{{#group}}` helper can opt-out of the special group + behavior by passing the `groupedRows` option. For example: + + ```handlebars + {{#group}} + {{#each dealers}} + {{! uses group's special behavior }} + {{firstName}} {{lastName}} + {{/each}} + + {{#each car in cars groupedRows=true}} + {{! does not use group's special behavior }} + {{car.make}} {{car.model}} {{car.color}} + {{/each}} + {{/group}} + ``` + + Any change to the `dealers` collection will cause the entire group to be re-rendered. + Changes to the `cars` collection will be re-rendered individually, as they are with + normal `{{#each}}` usage. + + `{{#group}}` is implemented with an `itemViewClass`, so specifying an `itemViewClass` + on an `{{#each}}` will also disable the special re-rendering behavior. + + @method each + @for Ember.Handlebars.helpers + @param [name] {String} name for item (used with `in`) + @param [path] {String} path + @param [options] {Object} Handlebars key/value pairs of options + @param [options.itemViewClass] {String} a path to a view class used for each item + @param [options.emptyViewClass] {String} a path to a view class used for each item + @param [options.itemController] {String} name of a controller to be created for each item + @param [options.groupedRows] {boolean} enable normal item-by-item rendering when inside a `#group` helper + */ + function eachHelper(path, options) { + var ctx; + var helperName = 'each'; + + if (arguments.length === 4) { + Ember.assert("If you pass more than one argument to the each helper, it must be in the form #each foo in bar", arguments[1] === "in"); + + var keywordName = arguments[0]; + + + options = arguments[3]; + path = arguments[2]; + + helperName += ' ' + keywordName + ' in ' + path; + + if (path === '') { path = "this"; } + + options.hash.keyword = keywordName; + + } else if (arguments.length === 1) { + options = path; + path = 'this'; + } else { + helperName += ' ' + path; + } + + options.hash.dataSourceBinding = path; + // Set up emptyView as a metamorph with no tag + //options.hash.emptyViewClass = Ember._MetamorphView; + + // can't rely on this default behavior when use strict + ctx = this || window; + + options.helperName = options.helperName || helperName; + + if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) { + new GroupedEach(ctx, path, options).render(); + } else { + return helpers.collection.call(ctx, EmberHandlebars.EachView, options); + } + } + + __exports__.EachView = EachView; + __exports__.GroupedEach = GroupedEach; + __exports__.eachHelper = eachHelper; + }); +define("ember-handlebars/helpers/loc", + ["ember-runtime/system/string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var loc = __dependency1__.loc; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + Calls [Ember.String.loc](/api/classes/Ember.String.html#method_loc) with the + provided string. + + This is a convenient way to localize text within a template: + + ```javascript + Ember.STRINGS = { + '_welcome_': 'Bonjour' + }; + ``` + + ```handlebars +
    + {{loc '_welcome_'}} +
    + ``` + + ```html +
    + Bonjour +
    + ``` + + See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to + set up localized string references. + + @method loc + @for Ember.Handlebars.helpers + @param {String} str The string to format + @see {Ember.String#loc} + */ + __exports__["default"] = loc; + }); +define("ember-handlebars/helpers/partial", + ["ember-metal/core","ember-metal/is_none","ember-handlebars/ext","ember-handlebars/helpers/binding","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + // var emberAssert = Ember.assert; + + var isNone = __dependency2__.isNone; + var handlebarsGet = __dependency3__.handlebarsGet; + var bind = __dependency4__.bind; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + The `partial` helper renders another template without + changing the template context: + + ```handlebars + {{foo}} + {{partial "nav"}} + ``` + + The above example template will render a template named + "_nav", which has the same context as the parent template + it's rendered into, so if the "_nav" template also referenced + `{{foo}}`, it would print the same thing as the `{{foo}}` + in the above example. + + If a "_nav" template isn't found, the `partial` helper will + fall back to a template named "nav". + + ## Bound template names + + The parameter supplied to `partial` can also be a path + to a property containing a template name, e.g.: + + ```handlebars + {{partial someTemplateName}} + ``` + + The above example will look up the value of `someTemplateName` + on the template context (e.g. a controller) and use that + value as the name of the template to render. If the resolved + value is falsy, nothing will be rendered. If `someTemplateName` + changes, the partial will be re-rendered using the new template + name. + + ## Setting the partial's context with `with` + + The `partial` helper can be used in conjunction with the `with` + helper to set a context that will be used by the partial: + + ```handlebars + {{#with currentUser}} + {{partial "user_info"}} + {{/with}} + ``` + + @method partial + @for Ember.Handlebars.helpers + @param {String} partialName the name of the template to render minus the leading underscore + */ + + __exports__["default"] = function partialHelper(name, options) { + + var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; + + options.helperName = options.helperName || 'partial'; + + if (options.types[0] === "ID") { + // Helper was passed a property path; we need to + // create a binding that will re-render whenever + // this property changes. + options.fn = function(context, fnOptions) { + var partialName = handlebarsGet(context, name, fnOptions); + renderPartial(context, partialName, fnOptions); + }; + + return bind.call(context, name, options, true, exists); + } else { + // Render the partial right into parent template. + renderPartial(context, name, options); + } + } + + function exists(value) { + return !isNone(value); + } + + function renderPartial(context, name, options) { + var nameParts = name.split("/"); + var lastPart = nameParts[nameParts.length - 1]; + + nameParts[nameParts.length - 1] = "_" + lastPart; + + var view = options.data.view; + var underscoredName = nameParts.join("/"); + var template = view.templateForName(underscoredName); + var deprecatedTemplate = !template && view.templateForName(name); + + Ember.assert("Unable to find partial with name '"+name+"'.", template || deprecatedTemplate); + + template = template || deprecatedTemplate; + + template(context, { data: options.data }); + } + }); +define("ember-handlebars/helpers/shared", + ["ember-handlebars/ext","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var handlebarsGet = __dependency1__.handlebarsGet; + + __exports__["default"] = function resolvePaths(options) { + var ret = []; + var contexts = options.contexts; + var roots = options.roots; + var data = options.data; + + for (var i=0, l=contexts.length; i{{unbound somePropertyThatDoesntChange}} + ``` + + `unbound` can also be used in conjunction with a bound helper to + render it in its unbound form: + + ```handlebars +
    {{unbound helperName somePropertyThatDoesntChange}}
    + ``` + + @method unbound + @for Ember.Handlebars.helpers + @param {String} property + @return {String} HTML string + */ + __exports__["default"] = function unboundHelper(property, fn) { + var options = arguments[arguments.length - 1]; + var container = options.data.view.container; + var helper, context, out, ctx; + + ctx = this; + if (arguments.length > 2) { + // Unbound helper call. + options.data.isUnbound = true; + helper = resolveHelper(container, property) || helpers.helperMissing; + out = helper.apply(ctx, slice.call(arguments, 1)); + delete options.data.isUnbound; + return out; + } + + context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : ctx; + return handlebarsGet(context, property, fn); + } + }); +define("ember-handlebars/helpers/view", + ["ember-metal/core","ember-runtime/system/object","ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-views/system/jquery","ember-views/views/view","ember-metal/binding","ember-metal/keys","ember-handlebars/ext","ember-runtime/system/string","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /*globals Handlebars */ + + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // Ember.warn, Ember.assert + // var emberWarn = Ember.warn, emberAssert = Ember.assert; + + var EmberObject = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var IS_BINDING = __dependency5__.IS_BINDING; + var jQuery = __dependency6__["default"]; + var View = __dependency7__["default"]; + var isGlobalPath = __dependency8__.isGlobalPath; + var keys = __dependency9__["default"]; + var normalizePath = __dependency10__.normalizePath; + var handlebarsGet = __dependency10__.handlebarsGet; + var handlebarsGetView = __dependency10__.handlebarsGetView; + var EmberString = __dependency11__["default"]; + + + var LOWERCASE_A_Z = /^[a-z]/; + var VIEW_PREFIX = /^view\./; + + function makeBindings(thisContext, options) { + var hash = options.hash; + var hashType = options.hashTypes; + + for (var prop in hash) { + if (hashType[prop] === 'ID') { + + var value = hash[prop]; + + if (IS_BINDING.test(prop)) { + Ember.warn("You're attempting to render a view by passing " + prop + "=" + value + " to a view helper, but this syntax is ambiguous. You should either surround " + value + " in quotes or remove `Binding` from " + prop + "."); + } else { + hash[prop + 'Binding'] = value; + hashType[prop + 'Binding'] = 'STRING'; + delete hash[prop]; + delete hashType[prop]; + } + } + } + + if (hash.hasOwnProperty('idBinding')) { + // id can't be bound, so just perform one-time lookup. + hash.id = handlebarsGet(thisContext, hash.idBinding, options); + hashType.id = 'STRING'; + delete hash.idBinding; + delete hashType.idBinding; + } + } + + var ViewHelper = EmberObject.create({ + propertiesFromHTMLOptions: function(options) { + var hash = options.hash; + var data = options.data; + var classes = hash['class']; + + var extensions = { + helperName: options.helperName || '' + }; + + if (hash.id) { + extensions.elementId = hash.id; + } + + if (hash.tag) { + extensions.tagName = hash.tag; + } + + if (classes) { + classes = classes.split(' '); + extensions.classNames = classes; + } + + if (hash.classBinding) { + extensions.classNameBindings = hash.classBinding.split(' '); + } + + if (hash.classNameBindings) { + if (extensions.classNameBindings === undefined) { + extensions.classNameBindings = []; + } + extensions.classNameBindings = extensions.classNameBindings.concat(hash.classNameBindings.split(' ')); + } + + if (hash.attributeBindings) { + Ember.assert("Setting 'attributeBindings' via Handlebars is not allowed. Please subclass Ember.View and set it there instead."); + extensions.attributeBindings = null; + } + + // Set the proper context for all bindings passed to the helper. This applies to regular attribute bindings + // as well as class name bindings. If the bindings are local, make them relative to the current context + // instead of the view. + var path; + var hashKeys = keys(hash); + + for (var i = 0, l = hashKeys.length; i < l; i++) { + var prop = hashKeys[i]; + var isBinding = IS_BINDING.test(prop); + + if (prop !== 'classNameBindings') { + extensions[prop] = hash[prop]; + } + + // Test if the property ends in "Binding" + if (isBinding && typeof extensions[prop] === 'string') { + path = this.contextualizeBindingPath(hash[prop], data); + if (path) { + extensions[prop] = path; + } + } + } + + if (extensions.classNameBindings) { + // Evaluate the context of class name bindings: + for (var j = 0, k = extensions.classNameBindings.length; j < k; j++) { + var full = extensions.classNameBindings[j]; + + if (typeof full === 'string') { + // Contextualize the path of classNameBinding so this: + // + // classNameBinding="isGreen:green" + // + // is converted to this: + // + // classNameBinding="_parentView.context.isGreen:green" + var parsedPath = View._parsePropertyPath(full); + if (parsedPath.path !== '') { + path = this.contextualizeBindingPath(parsedPath.path, data); + if (path) { + extensions.classNameBindings[j] = path + parsedPath.classNames; + } + } + } + } + } + + return extensions; + }, + + // Transform bindings from the current context to a context that can be evaluated within the view. + // Returns null if the path shouldn't be changed. + // + // TODO: consider the addition of a prefix that would allow this method to return `path`. + contextualizeBindingPath: function(path, data) { + var normalized = normalizePath(null, path, data); + if (normalized.isKeyword) { + return 'templateData.keywords.' + path; + } else if (isGlobalPath(path)) { + return null; + } else if (path === 'this' || path === '') { + return '_parentView.context'; + } else { + return '_parentView.context.' + path; + } + }, + + helper: function(thisContext, path, options) { + var data = options.data; + var fn = options.fn; + var newView; + + makeBindings(thisContext, options); + + var container = this.container || (data && data.view && data.view.container); + newView = handlebarsGetView(thisContext, path, container, options.data); + + var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); + var currentView = data.view; + viewOptions.templateData = data; + var newViewProto = newView.proto(); + + if (fn) { + Ember.assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newViewProto, 'templateName')); + viewOptions.template = fn; + } + + // We only want to override the `_context` computed property if there is + // no specified controller. See View#_context for more information. + if (!newViewProto.controller && !newViewProto.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { + viewOptions._context = thisContext; + } + + currentView.appendChild(newView, viewOptions); + }, + + instanceHelper: function(thisContext, newView, options) { + var data = options.data; + var fn = options.fn; + + makeBindings(thisContext, options); + + Ember.assert( + 'Only a instance of a view may be passed to the ViewHelper.instanceHelper', + View.detectInstance(newView) + ); + + var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); + var currentView = data.view; + viewOptions.templateData = data; + + if (fn) { + Ember.assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newView, 'templateName')); + viewOptions.template = fn; + } + + // We only want to override the `_context` computed property if there is + // no specified controller. See View#_context for more information. + if (!newView.controller && !newView.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { + viewOptions._context = thisContext; + } + + currentView.appendChild(newView, viewOptions); + } + }); + __exports__.ViewHelper = ViewHelper; + /** + `{{view}}` inserts a new instance of an `Ember.View` into a template passing its + options to the `Ember.View`'s `create` method and using the supplied block as + the view's own template. + + An empty `` and the following template: + + ```handlebars + A span: + {{#view tagName="span"}} + hello. + {{/view}} + ``` + + Will result in HTML structure: + + ```html + + + +
    + A span: + + Hello. + +
    + + ``` + + ### `parentView` setting + + The `parentView` property of the new `Ember.View` instance created through + `{{view}}` will be set to the `Ember.View` instance of the template where + `{{view}}` was called. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile("{{#view}} my parent: {{parentView.elementId}} {{/view}}") + }); + + aView.appendTo('body'); + ``` + + Will result in HTML structure: + + ```html +
    +
    + my parent: ember1 +
    +
    + ``` + + ### Setting CSS id and class attributes + + The HTML `id` attribute can be set on the `{{view}}`'s resulting element with + the `id` option. This option will _not_ be passed to `Ember.View.create`. + + ```handlebars + {{#view tagName="span" id="a-custom-id"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + The HTML `class` attribute can be set on the `{{view}}`'s resulting element + with the `class` or `classNameBindings` options. The `class` option will + directly set the CSS `class` attribute and will not be passed to + `Ember.View.create`. `classNameBindings` will be passed to `create` and use + `Ember.View`'s class name binding functionality: + + ```handlebars + {{#view tagName="span" class="a-custom-class"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + ### Supplying a different view class + + `{{view}}` can take an optional first argument before its supplied options to + specify a path to a custom view class. + + ```handlebars + {{#view "custom"}}{{! will look up App.CustomView }} + hello. + {{/view}} + ``` + + The first argument can also be a relative path accessible from the current + context. + + ```javascript + MyApp = Ember.Application.create({}); + MyApp.OuterView = Ember.View.extend({ + innerViewClass: Ember.View.extend({ + classNames: ['a-custom-view-class-as-property'] + }), + template: Ember.Handlebars.compile('{{#view view.innerViewClass}} hi {{/view}}') + }); + + MyApp.OuterView.create().appendTo('body'); + ``` + + Will result in the following HTML: + + ```html +
    +
    + hi +
    +
    + ``` + + ### Blockless use + + If you supply a custom `Ember.View` subclass that specifies its own template + or provide a `templateName` option to `{{view}}` it can be used without + supplying a block. Attempts to use both a `templateName` option and supply a + block will throw an error. + + ```javascript + var App = Ember.Application.create(); + App.WithTemplateDefinedView = Ember.View.extend({ + templateName: 'defined-template' + }); + ``` + + ```handlebars + {{! application.hbs }} + {{view 'with-template-defined'}} + ``` + + ```handlebars + {{! defined-template.hbs }} + Some content for the defined template view. + ``` + + ### `viewName` property + + You can supply a `viewName` option to `{{view}}`. The `Ember.View` instance + will be referenced as a property of its parent view by this name. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile('{{#view viewName="aChildByName"}} hi {{/view}}') + }); + + aView.appendTo('body'); + aView.get('aChildByName') // the instance of Ember.View created by {{view}} helper + ``` + + @method view + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + */ + function viewHelper(path, options) { + Ember.assert("The view helper only takes a single argument", arguments.length <= 2); + + // If no path is provided, treat path param as options + // and get an instance of the registered `view:toplevel` + if (path && path.data && path.data.isRenderData) { + options = path; + if (options.data && options.data.view && options.data.view.container) { + path = options.data.view.container.lookupFactory('view:toplevel'); + } else { + path = View; + } + } + + options.helperName = options.helperName || 'view'; + + return ViewHelper.helper(this, path, options); + } + + __exports__.viewHelper = viewHelper; + }); +define("ember-handlebars/helpers/yield", + ["ember-metal/core","ember-metal/property_get","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // var emberAssert = Ember.assert; + + var get = __dependency2__.get; + + /** + `{{yield}}` denotes an area of a template that will be rendered inside + of another template. It has two main uses: + + ### Use with `layout` + When used in a Handlebars template that is assigned to an `Ember.View` + instance's `layout` property Ember will render the layout template first, + inserting the view's own rendered output at the `{{yield}}` location. + + An empty `` and the following application code: + + ```javascript + AView = Ember.View.extend({ + classNames: ['a-view-with-layout'], + layout: Ember.Handlebars.compile('
    {{yield}}
    '), + template: Ember.Handlebars.compile('I am wrapped') + }); + + aView = AView.create(); + aView.appendTo('body'); + ``` + + Will result in the following HTML output: + + ```html + +
    +
    + I am wrapped +
    +
    + + ``` + + The `yield` helper cannot be used outside of a template assigned to an + `Ember.View`'s `layout` property and will throw an error if attempted. + + ```javascript + BView = Ember.View.extend({ + classNames: ['a-view-with-layout'], + template: Ember.Handlebars.compile('{{yield}}') + }); + + bView = BView.create(); + bView.appendTo('body'); + + // throws + // Uncaught Error: assertion failed: + // You called yield in a template that was not a layout + ``` + + ### Use with Ember.Component + When designing components `{{yield}}` is used to denote where, inside the component's + template, an optional block passed to the component should render: + + ```handlebars + + {{#labeled-textfield value=someProperty}} + First name: + {{/labeled-textfield}} + ``` + + ```handlebars + + + ``` + + Result: + + ```html + + ``` + + @method yield + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string + */ + __exports__["default"] = function yieldHelper(options) { + var view = options.data.view; + + while (view && !get(view, 'layout')) { + if (view._contextView) { + view = view._contextView; + } else { + view = get(view, '_parentView'); + } + } + + Ember.assert("You called yield in a template that was not a layout", !!view); + + view._yield(this, options); + } + }); +define("ember-handlebars/loader", + ["ember-handlebars/component_lookup","ember-views/system/jquery","ember-metal/error","ember-runtime/system/lazy_load","ember-handlebars-compiler","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /*globals Handlebars */ + + var ComponentLookup = __dependency1__["default"]; + var jQuery = __dependency2__["default"]; + var EmberError = __dependency3__["default"]; + var onLoad = __dependency4__.onLoad; + + var EmberHandlebars = __dependency5__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + Find templates stored in the head tag as script tags and make them available + to `Ember.CoreView` in the global `Ember.TEMPLATES` object. This will be run + as as jQuery DOM-ready callback. + + Script tags with `text/x-handlebars` will be compiled + with Ember's Handlebars and are suitable for use as a view's template. + Those with type `text/x-raw-handlebars` will be compiled with regular + Handlebars and are suitable for use in views' computed properties. + + @private + @method bootstrap + @for Ember.Handlebars + @static + @param ctx + */ + function bootstrap(ctx) { + var selectors = 'script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]'; + + jQuery(selectors, ctx) + .each(function() { + // Get a reference to the script tag + var script = jQuery(this); + + var compile = (script.attr('type') === 'text/x-raw-handlebars') ? + jQuery.proxy(Handlebars.compile, Handlebars) : + jQuery.proxy(EmberHandlebars.compile, EmberHandlebars); + // Get the name of the script, used by Ember.View's templateName property. + // First look for data-template-name attribute, then fall back to its + // id if no name is found. + var templateName = script.attr('data-template-name') || script.attr('id') || 'application'; + var template = compile(script.html()); + + // Check if template of same name already exists + if (Ember.TEMPLATES[templateName] !== undefined) { + throw new EmberError('Template named "' + templateName + '" already exists.'); + } + + // For templates which have a name, we save them and then remove them from the DOM + Ember.TEMPLATES[templateName] = template; + + // Remove script tag from DOM + script.remove(); + }); + } + + function _bootstrap() { + bootstrap( jQuery(document) ); + } + + function registerComponentLookup(container) { + container.register('component-lookup:main', ComponentLookup); + } + + /* + We tie this to application.load to ensure that we've at least + attempted to bootstrap at the point that the application is loaded. + + We also tie this to document ready since we're guaranteed that all + the inline templates are present at this point. + + There's no harm to running this twice, since we remove the templates + from the DOM after processing. + */ + + onLoad('Ember.Application', function(Application) { + Application.initializer({ + name: 'domTemplates', + initialize: _bootstrap + }); + + Application.initializer({ + name: 'registerComponentLookup', + after: 'domTemplates', + initialize: registerComponentLookup + }); + }); + + __exports__["default"] = bootstrap; + }); +define("ember-handlebars/string", + ["ember-runtime/system/string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + // required so we can extend this object. + var EmberStringUtils = __dependency1__["default"]; + + /** + Mark a string as safe for unescaped output with Handlebars. If you + return HTML from a Handlebars helper, use this function to + ensure Handlebars does not escape the HTML. + + ```javascript + Ember.String.htmlSafe('
    someString
    ') + ``` + + @method htmlSafe + @for Ember.String + @static + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars + */ + function htmlSafe(str) { + return new Handlebars.SafeString(str); + } + + EmberStringUtils.htmlSafe = htmlSafe; + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { + + /** + Mark a string as being safe for unescaped output with Handlebars. + + ```javascript + '
    someString
    '.htmlSafe() + ``` + + See [Ember.String.htmlSafe](/api/classes/Ember.String.html#method_htmlSafe). + + @method htmlSafe + @for String + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars + */ + String.prototype.htmlSafe = function() { + return htmlSafe(this); + }; + } + + __exports__["default"] = htmlSafe; + }); +define("ember-handlebars/views/handlebars_bound_view", + ["ember-handlebars-compiler","ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-views/views/view","ember-views/views/states","ember-handlebars/views/metamorph_view","ember-handlebars/ext","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /*globals Handlebars, Metamorph:true */ + /*jshint newcap:false*/ + + + /** + @module ember + @submodule ember-handlebars + */ + + var EmberHandlebars = __dependency1__["default"]; + // EmberHandlebars.SafeString; + var SafeString = EmberHandlebars.SafeString; + + var Ember = __dependency2__["default"]; + // Ember.K + var K = Ember.K; + + var EmberError = __dependency3__["default"]; + var get = __dependency4__.get; + var set = __dependency5__.set; + var merge = __dependency6__["default"]; + var run = __dependency7__["default"]; + var computed = __dependency8__.computed; + var View = __dependency9__["default"]; + var cloneStates = __dependency10__.cloneStates; + var states = __dependency10__.states; + var viewStates = states; + + var _MetamorphView = __dependency11__["default"]; + var handlebarsGet = __dependency12__.handlebarsGet; + var uuid = __dependency13__.uuid; + + function SimpleHandlebarsView(path, pathRoot, isEscaped, templateData) { + this.path = path; + this.pathRoot = pathRoot; + this.isEscaped = isEscaped; + this.templateData = templateData; + this[Ember.GUID_KEY] = uuid(); + this._lastNormalizedValue = undefined; + this.state = 'preRender'; + this.updateId = null; + this._parentView = null; + this.buffer = null; + this._morph = null; + } + + SimpleHandlebarsView.prototype = { + isVirtual: true, + isView: true, + + destroy: function () { + if (this.updateId) { + run.cancel(this.updateId); + this.updateId = null; + } + if (this._parentView) { + this._parentView.removeChild(this); + } + this.morph = null; + this.state = 'destroyed'; + }, + + propertyWillChange: K, + + propertyDidChange: K, + + normalizedValue: function() { + var path = this.path; + var pathRoot = this.pathRoot; + var escape = this.isEscaped; + var result, templateData; + + // Use the pathRoot as the result if no path is provided. This + // happens if the path is `this`, which gets normalized into + // a `pathRoot` of the current Handlebars context and a path + // of `''`. + if (path === '') { + result = pathRoot; + } else { + templateData = this.templateData; + result = handlebarsGet(pathRoot, path, { data: templateData }); + } + + if (result === null || result === undefined) { + result = ""; + } else if (!escape && !(result instanceof SafeString)) { + result = new SafeString(result); + } + + return result; + }, + + render: function(buffer) { + var value = this.normalizedValue(); + this._lastNormalizedValue = value; + buffer._element = value; + }, + + rerender: function() { + switch(this.state) { + case 'preRender': + case 'destroyed': + break; + case 'inBuffer': + throw new EmberError("Something you did tried to replace an {{expression}} before it was inserted into the DOM."); + case 'hasElement': + case 'inDOM': + this.updateId = run.scheduleOnce('render', this, 'update'); + break; + } + return this; + }, + + update: function () { + this.updateId = null; + var value = this.normalizedValue(); + // doesn't diff SafeString instances + if (value !== this._lastNormalizedValue) { + this._lastNormalizedValue = value; + this._morph.update(value); + } + }, + + _transitionTo: function(state) { + this.state = state; + } + }; + + states = cloneStates(viewStates); + + merge(states._default, { + rerenderIfNeeded: K + }); + + merge(states.inDOM, { + rerenderIfNeeded: function(view) { + if (view.normalizedValue() !== view._lastNormalizedValue) { + view.rerender(); + } + } + }); + + /** + `Ember._HandlebarsBoundView` is a private view created by the Handlebars + `{{bind}}` helpers that is used to keep track of bound properties. + + Every time a property is bound using a `{{mustache}}`, an anonymous subclass + of `Ember._HandlebarsBoundView` is created with the appropriate sub-template + and context set up. When the associated property changes, just the template + for this view will re-render. + + @class _HandlebarsBoundView + @namespace Ember + @extends Ember._MetamorphView + @private + */ + var _HandlebarsBoundView = _MetamorphView.extend({ + instrumentName: 'boundHandlebars', + + _states: states, + + /** + The function used to determine if the `displayTemplate` or + `inverseTemplate` should be rendered. This should be a function that takes + a value and returns a Boolean. + + @property shouldDisplayFunc + @type Function + @default null + */ + shouldDisplayFunc: null, + + /** + Whether the template rendered by this view gets passed the context object + of its parent template, or gets passed the value of retrieving `path` + from the `pathRoot`. + + For example, this is true when using the `{{#if}}` helper, because the + template inside the helper should look up properties relative to the same + object as outside the block. This would be `false` when used with `{{#with + foo}}` because the template should receive the object found by evaluating + `foo`. + + @property preserveContext + @type Boolean + @default false + */ + preserveContext: false, + + /** + If `preserveContext` is true, this is the object that will be used + to render the template. + + @property previousContext + @type Object + */ + previousContext: null, + + /** + The template to render when `shouldDisplayFunc` evaluates to `true`. + + @property displayTemplate + @type Function + @default null + */ + displayTemplate: null, + + /** + The template to render when `shouldDisplayFunc` evaluates to `false`. + + @property inverseTemplate + @type Function + @default null + */ + inverseTemplate: null, + + + /** + The path to look up on `pathRoot` that is passed to + `shouldDisplayFunc` to determine which template to render. + + In addition, if `preserveContext` is `false,` the object at this path will + be passed to the template when rendering. + + @property path + @type String + @default null + */ + path: null, + + /** + The object from which the `path` will be looked up. Sometimes this is the + same as the `previousContext`, but in cases where this view has been + generated for paths that start with a keyword such as `view` or + `controller`, the path root will be that resolved object. + + @property pathRoot + @type Object + */ + pathRoot: null, + + normalizedValue: function() { + var path = get(this, 'path'); + var pathRoot = get(this, 'pathRoot'); + var valueNormalizer = get(this, 'valueNormalizerFunc'); + var result, templateData; + + // Use the pathRoot as the result if no path is provided. This + // happens if the path is `this`, which gets normalized into + // a `pathRoot` of the current Handlebars context and a path + // of `''`. + if (path === '') { + result = pathRoot; + } else { + templateData = get(this, 'templateData'); + result = handlebarsGet(pathRoot, path, { data: templateData }); + } + + return valueNormalizer ? valueNormalizer(result) : result; + }, + + rerenderIfNeeded: function() { + this.currentState.rerenderIfNeeded(this); + }, + + /** + Determines which template to invoke, sets up the correct state based on + that logic, then invokes the default `Ember.View` `render` implementation. + + This method will first look up the `path` key on `pathRoot`, + then pass that value to the `shouldDisplayFunc` function. If that returns + `true,` the `displayTemplate` function will be rendered to DOM. Otherwise, + `inverseTemplate`, if specified, will be rendered. + + For example, if this `Ember._HandlebarsBoundView` represented the `{{#with + foo}}` helper, it would look up the `foo` property of its context, and + `shouldDisplayFunc` would always return true. The object found by looking + up `foo` would be passed to `displayTemplate`. + + @method render + @param {Ember.RenderBuffer} buffer + */ + render: function(buffer) { + // If not invoked via a triple-mustache ({{{foo}}}), escape + // the content of the template. + var escape = get(this, 'isEscaped'); + + var shouldDisplay = get(this, 'shouldDisplayFunc'); + var preserveContext = get(this, 'preserveContext'); + var context = get(this, 'previousContext'); + + var inverseTemplate = get(this, 'inverseTemplate'); + var displayTemplate = get(this, 'displayTemplate'); + + var result = this.normalizedValue(); + + this._lastNormalizedValue = result; + + // First, test the conditional to see if we should + // render the template or not. + if (shouldDisplay(result)) { + set(this, 'template', displayTemplate); + + // If we are preserving the context (for example, if this + // is an #if block, call the template with the same object. + if (preserveContext) { + set(this, '_context', context); + } else { + // Otherwise, determine if this is a block bind or not. + // If so, pass the specified object to the template + if (displayTemplate) { + set(this, '_context', result); + } else { + // This is not a bind block, just push the result of the + // expression to the render context and return. + if (result === null || result === undefined) { + result = ""; + } else if (!(result instanceof SafeString)) { + result = String(result); + } + + if (escape) { result = Handlebars.Utils.escapeExpression(result); } + buffer.push(result); + return; + } + } + } else if (inverseTemplate) { + set(this, 'template', inverseTemplate); + + if (preserveContext) { + set(this, '_context', context); + } else { + set(this, '_context', result); + } + } else { + set(this, 'template', function() { return ''; }); + } + + return this._super(buffer); + } + }); + + __exports__._HandlebarsBoundView = _HandlebarsBoundView; + __exports__.SimpleHandlebarsView = SimpleHandlebarsView; + }); +define("ember-handlebars/views/metamorph_view", + ["ember-metal/core","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /* global Metamorph:true */ + + /*jshint newcap:false*/ + var Ember = __dependency1__["default"]; + // Ember.deprecate + + var CoreView = __dependency2__["default"]; + var View = __dependency3__["default"]; + var Mixin = __dependency4__.Mixin; + var run = __dependency5__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + function notifyMutationListeners() { + run.once(View, 'notifyMutationListeners'); + } + + // The `morph` and `outerHTML` properties are internal only + // and not observable. + + /** + @class _Metamorph + @namespace Ember + @private + */ + var _Metamorph = Mixin.create({ + isVirtual: true, + tagName: '', + + instrumentName: 'metamorph', + + init: function() { + this._super(); + Ember.deprecate('Supplying a tagName to Metamorph views is unreliable and is deprecated. You may be setting the tagName on a Handlebars helper that creates a Metamorph.', !this.tagName); + } + }); + __exports__._Metamorph = _Metamorph; + /** + @class _MetamorphView + @namespace Ember + @extends Ember.View + @uses Ember._Metamorph + @private + */ + var _MetamorphView = View.extend(_Metamorph); + __exports__._MetamorphView = _MetamorphView; + /** + @class _SimpleMetamorphView + @namespace Ember + @extends Ember.CoreView + @uses Ember._Metamorph + @private + */ + var _SimpleMetamorphView = CoreView.extend(_Metamorph); + __exports__._SimpleMetamorphView = _SimpleMetamorphView;__exports__["default"] = View.extend(_Metamorph); + }); +define("ember-metal-views", + ["ember-metal-views/renderer","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Renderer = __dependency1__["default"]; + __exports__.Renderer = Renderer; + }); +define("ember-metal-views/renderer", + ["morph","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var DOMHelper = __dependency1__.DOMHelper; + + function Renderer() { + this._uuid = 0; + this._views = new Array(2000); + this._queue = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + this._parents = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + this._elements = new Array(17); + this._inserts = {}; + this._dom = new DOMHelper(); + } + + function Renderer_renderTree(_view, _parentView, _insertAt) { + var views = this._views; + views[0] = _view; + var insertAt = _insertAt === undefined ? -1 : _insertAt; + var index = 0; + var total = 1; + var levelBase = _parentView ? _parentView._level+1 : 0; + + var root = _parentView == null ? _view : _parentView._root; + + // if root view has a _morph assigned + var willInsert = !!root._morph; + + var queue = this._queue; + queue[0] = 0; + var length = 1; + + var parentIndex = -1; + var parents = this._parents; + var parent = _parentView || null; + var elements = this._elements; + var element = null; + var contextualElement = null; + var level = 0; + + var view = _view; + var children, i, l, child; + while (length) { + elements[level] = element; + if (!view._morph) { + // ensure props we add are in same order + view._morph = null; + } + view._root = root; + this.uuid(view); + view._level = levelBase + level; + if (view._elementCreated) { + this.remove(view, false, true); + } + + this.willCreateElement(view); + + contextualElement = view._morph && view._morph.contextualElement; + if (!contextualElement && parent && parent._childViewsMorph) { + contextualElement = parent._childViewsMorph.contextualElement; + } + if (!contextualElement && view._didCreateElementWithoutMorph) { + // This code path is only used by createElement and rerender when createElement + // was previously called on a view. + contextualElement = document.body; + } + Ember.assert("Required contextualElement for view "+_view+" is missing", contextualElement); + element = this.createElement(view, contextualElement); + + parents[level++] = parentIndex; + parentIndex = index; + parent = view; + + // enqueue for end + queue[length++] = index; + // enqueue children + children = this.childViews(view); + if (children) { + for (i=children.length-1;i>=0;i--) { + child = children[i]; + index = total++; + views[index] = child; + queue[length++] = index; + view = child; + } + } + + index = queue[--length]; + view = views[index]; + + while (parentIndex === index) { + level--; + view._elementCreated = true; + this.didCreateElement(view); + if (willInsert) { + this.willInsertElement(view); + } + + if (level === 0) { + length--; + break; + } + + parentIndex = parents[level]; + parent = parentIndex === -1 ? _parentView : views[parentIndex]; + this.insertElement(view, parent, element, -1); + index = queue[--length]; + view = views[index]; + element = elements[level]; + elements[level] = null; + } + } + + this.insertElement(view, _parentView, element, insertAt); + + for (i=total-1;i>=0;i--) { + if (willInsert) { + views[i]._elementInserted = true; + this.didInsertElement(views[i]); + } + views[i] = null; + } + + return element; + } + + Renderer.prototype.uuid = function Renderer_uuid(view) { + if (view._uuid === undefined) { + view._uuid = ++this._uuid; + view._renderer = this; + } // else assert(view._renderer === this) + return view._uuid; + }; + + Renderer.prototype.scheduleInsert = + function Renderer_scheduleInsert(view, morph) { + if (view._morph || view._elementCreated) { + throw new Error("You cannot insert a View that has already been rendered"); + } + Ember.assert("You cannot insert a View without a morph", morph); + view._morph = morph; + var viewId = this.uuid(view); + this._inserts[viewId] = this.scheduleRender(this, function() { + this._inserts[viewId] = null; + this.renderTree(view); + }); + }; + + Renderer.prototype.appendTo = + function Renderer_appendTo(view, target) { + var morph = this._dom.appendMorph(target); + this.scheduleInsert(view, morph); + }; + + Renderer.prototype.replaceIn = + function Renderer_replaceIn(view, target) { + var morph = this._dom.createMorph(target, null, null); + this.scheduleInsert(view, morph); + }; + + function Renderer_remove(_view, shouldDestroy, reset) { + var viewId = this.uuid(_view); + + if (this._inserts[viewId]) { + this.cancelRender(this._inserts[viewId]); + this._inserts[viewId] = undefined; + } + + if (!_view._elementCreated) { + return; + } + + var removeQueue = []; + var destroyQueue = []; + var morph = _view._morph; + var idx, len, view, staticChildren, queue, + childViews, i, l, parentView; + + removeQueue.push(_view); + + for (idx=0; idx -1; + }; + + var defineNativeShim = function(nativeFunc, shim) { + if (isNativeFunc(nativeFunc)) { + return nativeFunc; + } + return shim; + }; + + // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/map + var map = defineNativeShim(ArrayPrototype.map, function(fun /*, thisp */) { + //"use strict"; + + if (this === void 0 || this === null || typeof fun !== "function") { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + var res = new Array(len); + var thisp = arguments[1]; + + for (var i = 0; i < len; i++) { + if (i in t) { + res[i] = fun.call(thisp, t[i], i, t); + } + } + + return res; + }); + + // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/foreach + var forEach = defineNativeShim(ArrayPrototype.forEach, function(fun /*, thisp */) { + //"use strict"; + + if (this === void 0 || this === null || typeof fun !== "function") { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + var thisp = arguments[1]; + + for (var i = 0; i < len; i++) { + if (i in t) { + fun.call(thisp, t[i], i, t); + } + } + }); + + var indexOf = defineNativeShim(ArrayPrototype.indexOf, function (obj, fromIndex) { + if (fromIndex === null || fromIndex === undefined) { + fromIndex = 0; + } + else if (fromIndex < 0) { + fromIndex = Math.max(0, this.length + fromIndex); + } + + for (var i = fromIndex, j = this.length; i < j; i++) { + if (this[i] === obj) { + return i; + } + } + return -1; + }); + + var lastIndexOf = defineNativeShim(ArrayPrototype.lastIndexOf, function(obj, fromIndex) { + var len = this.length; + var idx; + + if (fromIndex === undefined) fromIndex = len-1; + else fromIndex = (fromIndex < 0) ? Math.ceil(fromIndex) : Math.floor(fromIndex); + if (fromIndex < 0) fromIndex += len; + + for(idx = fromIndex;idx>=0;idx--) { + if (this[idx] === obj) return idx ; + } + return -1; + }); + + var filter = defineNativeShim(ArrayPrototype.filter, function (fn, context) { + var i, value; + var result = []; + var length = this.length; + + for (i = 0; i < length; i++) { + if (this.hasOwnProperty(i)) { + value = this[i]; + if (fn.call(context, value, i, this)) { + result.push(value); + } + } + } + return result; + }); + + if (Ember.SHIM_ES5) { + ArrayPrototype.map = ArrayPrototype.map || map; + ArrayPrototype.forEach = ArrayPrototype.forEach || forEach; + ArrayPrototype.filter = ArrayPrototype.filter || filter; + ArrayPrototype.indexOf = ArrayPrototype.indexOf || indexOf; + ArrayPrototype.lastIndexOf = ArrayPrototype.lastIndexOf || lastIndexOf; + } + + /** + Array polyfills to support ES5 features in older browsers. + + @namespace Ember + @property ArrayPolyfills + */ + __exports__.map = map; + __exports__.forEach = forEach; + __exports__.filter = filter; + __exports__.indexOf = indexOf; + __exports__.lastIndexOf = lastIndexOf; + }); +define("ember-metal/binding", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/map","ember-metal/observer","ember-metal/run_loop","ember-metal/path_cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.Logger, Ember.LOG_BINDINGS, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var trySet = __dependency3__.trySet; + var guidFor = __dependency4__.guidFor; + var Map = __dependency5__["default"]; + var addObserver = __dependency6__.addObserver; + var removeObserver = __dependency6__.removeObserver; + var _suspendObserver = __dependency6__._suspendObserver; + var run = __dependency7__["default"]; + var isGlobalPath = __dependency8__.isGlobal; + + + // ES6TODO: where is Ember.lookup defined? + /** + @module ember-metal + */ + + // .......................................................... + // CONSTANTS + // + + /** + Debug parameter you can turn on. This will log all bindings that fire to + the console. This should be disabled in production code. Note that you + can also enable this from the console or temporarily. + + @property LOG_BINDINGS + @for Ember + @type Boolean + @default false + */ + Ember.LOG_BINDINGS = false || !!Ember.ENV.LOG_BINDINGS; + + /** + Returns true if the provided path is global (e.g., `MyApp.fooController.bar`) + instead of local (`foo.bar.baz`). + + @method isGlobalPath + @for Ember + @private + @param {String} path + @return Boolean + */ + + function getWithGlobals(obj, path) { + return get(isGlobalPath(path) ? Ember.lookup : obj, path); + } + + // .......................................................... + // BINDING + // + + function Binding(toPath, fromPath) { + this._direction = 'fwd'; + this._from = fromPath; + this._to = toPath; + this._directionMap = new Map(); + this._readyToSync = undefined; + this._oneWay = undefined; + } + + /** + @class Binding + @namespace Ember + */ + + Binding.prototype = { + /** + This copies the Binding so it can be connected to another object. + + @method copy + @return {Ember.Binding} `this` + */ + copy: function () { + var copy = new Binding(this._to, this._from); + if (this._oneWay) { copy._oneWay = true; } + return copy; + }, + + // .......................................................... + // CONFIG + // + + /** + This will set `from` property path to the specified value. It will not + attempt to resolve this property path to an actual object until you + connect the binding. + + The binding will search for the property path starting at the root object + you pass when you `connect()` the binding. It follows the same rules as + `get()` - see that method for more information. + + @method from + @param {String} path the property path to connect to + @return {Ember.Binding} `this` + */ + from: function(path) { + this._from = path; + return this; + }, + + /** + This will set the `to` property path to the specified value. It will not + attempt to resolve this property path to an actual object until you + connect the binding. + + The binding will search for the property path starting at the root object + you pass when you `connect()` the binding. It follows the same rules as + `get()` - see that method for more information. + + @method to + @param {String|Tuple} path A property path or tuple + @return {Ember.Binding} `this` + */ + to: function(path) { + this._to = path; + return this; + }, + + /** + Configures the binding as one way. A one-way binding will relay changes + on the `from` side to the `to` side, but not the other way around. This + means that if you change the `to` side directly, the `from` side may have + a different value. + + @method oneWay + @return {Ember.Binding} `this` + */ + oneWay: function() { + this._oneWay = true; + return this; + }, + + /** + @method toString + @return {String} string representation of binding + */ + toString: function() { + var oneWay = this._oneWay ? '[oneWay]' : ''; + return "Ember.Binding<" + guidFor(this) + ">(" + this._from + " -> " + this._to + ")" + oneWay; + }, + + // .......................................................... + // CONNECT AND SYNC + // + + /** + Attempts to connect this binding instance so that it can receive and relay + changes. This method will raise an exception if you have not set the + from/to properties yet. + + @method connect + @param {Object} obj The root object for this binding. + @return {Ember.Binding} `this` + */ + connect: function(obj) { + Ember.assert('Must pass a valid object to Ember.Binding.connect()', !!obj); + + var fromPath = this._from; + var toPath = this._to; + trySet(obj, toPath, getWithGlobals(obj, fromPath)); + + // add an observer on the object to be notified when the binding should be updated + addObserver(obj, fromPath, this, this.fromDidChange); + + // if the binding is a two-way binding, also set up an observer on the target + if (!this._oneWay) { addObserver(obj, toPath, this, this.toDidChange); } + + this._readyToSync = true; + + return this; + }, + + /** + Disconnects the binding instance. Changes will no longer be relayed. You + will not usually need to call this method. + + @method disconnect + @param {Object} obj The root object you passed when connecting the binding. + @return {Ember.Binding} `this` + */ + disconnect: function(obj) { + Ember.assert('Must pass a valid object to Ember.Binding.disconnect()', !!obj); + + var twoWay = !this._oneWay; + + // remove an observer on the object so we're no longer notified of + // changes that should update bindings. + removeObserver(obj, this._from, this, this.fromDidChange); + + // if the binding is two-way, remove the observer from the target as well + if (twoWay) { removeObserver(obj, this._to, this, this.toDidChange); } + + this._readyToSync = false; // disable scheduled syncs... + return this; + }, + + // .......................................................... + // PRIVATE + // + + /* called when the from side changes */ + fromDidChange: function(target) { + this._scheduleSync(target, 'fwd'); + }, + + /* called when the to side changes */ + toDidChange: function(target) { + this._scheduleSync(target, 'back'); + }, + + _scheduleSync: function(obj, dir) { + var directionMap = this._directionMap; + var existingDir = directionMap.get(obj); + + // if we haven't scheduled the binding yet, schedule it + if (!existingDir) { + run.schedule('sync', this, this._sync, obj); + directionMap.set(obj, dir); + } + + // If both a 'back' and 'fwd' sync have been scheduled on the same object, + // default to a 'fwd' sync so that it remains deterministic. + if (existingDir === 'back' && dir === 'fwd') { + directionMap.set(obj, 'fwd'); + } + }, + + _sync: function(obj) { + var log = Ember.LOG_BINDINGS; + + // don't synchronize destroyed objects or disconnected bindings + if (obj.isDestroyed || !this._readyToSync) { return; } + + // get the direction of the binding for the object we are + // synchronizing from + var directionMap = this._directionMap; + var direction = directionMap.get(obj); + + var fromPath = this._from; + var toPath = this._to; + + directionMap["delete"](obj); + + // if we're synchronizing from the remote object... + if (direction === 'fwd') { + var fromValue = getWithGlobals(obj, this._from); + if (log) { + Ember.Logger.log(' ', this.toString(), '->', fromValue, obj); + } + if (this._oneWay) { + trySet(obj, toPath, fromValue); + } else { + _suspendObserver(obj, toPath, this, this.toDidChange, function () { + trySet(obj, toPath, fromValue); + }); + } + // if we're synchronizing *to* the remote object + } else if (direction === 'back') { + var toValue = get(obj, this._to); + if (log) { + Ember.Logger.log(' ', this.toString(), '<-', toValue, obj); + } + _suspendObserver(obj, fromPath, this, this.fromDidChange, function () { + trySet(isGlobalPath(fromPath) ? Ember.lookup : obj, fromPath, toValue); + }); + } + } + + }; + + function mixinProperties(to, from) { + for (var key in from) { + if (from.hasOwnProperty(key)) { + to[key] = from[key]; + } + } + } + + mixinProperties(Binding, { + + /* + See `Ember.Binding.from`. + + @method from + @static + */ + from: function() { + var C = this; + var binding = new C(); + return binding.from.apply(binding, arguments); + }, + + /* + See `Ember.Binding.to`. + + @method to + @static + */ + to: function() { + var C = this; + var binding = new C(); + return binding.to.apply(binding, arguments); + }, + + /** + Creates a new Binding instance and makes it apply in a single direction. + A one-way binding will relay changes on the `from` side object (supplied + as the `from` argument) the `to` side, but not the other way around. + This means that if you change the "to" side directly, the "from" side may have + a different value. + + See `Binding.oneWay`. + + @method oneWay + @param {String} from from path. + @param {Boolean} [flag] (Optional) passing nothing here will make the + binding `oneWay`. You can instead pass `false` to disable `oneWay`, making the + binding two way again. + @return {Ember.Binding} `this` + */ + oneWay: function(from, flag) { + var C = this; + var binding = new C(null, from); + return binding.oneWay(flag); + } + + }); + /** + An `Ember.Binding` connects the properties of two objects so that whenever + the value of one property changes, the other property will be changed also. + + ## Automatic Creation of Bindings with `/^*Binding/`-named Properties + + You do not usually create Binding objects directly but instead describe + bindings in your class or object definition using automatic binding + detection. + + Properties ending in a `Binding` suffix will be converted to `Ember.Binding` + instances. The value of this property should be a string representing a path + to another object or a custom binding instance created using Binding helpers + (see "One Way Bindings"): + + ``` + valueBinding: "MyApp.someController.title" + ``` + + This will create a binding from `MyApp.someController.title` to the `value` + property of your object instance automatically. Now the two values will be + kept in sync. + + ## One Way Bindings + + One especially useful binding customization you can use is the `oneWay()` + helper. This helper tells Ember that you are only interested in + receiving changes on the object you are binding from. For example, if you + are binding to a preference and you want to be notified if the preference + has changed, but your object will not be changing the preference itself, you + could do: + + ``` + bigTitlesBinding: Ember.Binding.oneWay("MyApp.preferencesController.bigTitles") + ``` + + This way if the value of `MyApp.preferencesController.bigTitles` changes the + `bigTitles` property of your object will change also. However, if you + change the value of your `bigTitles` property, it will not update the + `preferencesController`. + + One way bindings are almost twice as fast to setup and twice as fast to + execute because the binding only has to worry about changes to one side. + + You should consider using one way bindings anytime you have an object that + may be created frequently and you do not intend to change a property; only + to monitor it for changes (such as in the example above). + + ## Adding Bindings Manually + + All of the examples above show you how to configure a custom binding, but the + result of these customizations will be a binding template, not a fully active + Binding instance. The binding will actually become active only when you + instantiate the object the binding belongs to. It is useful however, to + understand what actually happens when the binding is activated. + + For a binding to function it must have at least a `from` property and a `to` + property. The `from` property path points to the object/key that you want to + bind from while the `to` path points to the object/key you want to bind to. + + When you define a custom binding, you are usually describing the property + you want to bind from (such as `MyApp.someController.value` in the examples + above). When your object is created, it will automatically assign the value + you want to bind `to` based on the name of your binding key. In the + examples above, during init, Ember objects will effectively call + something like this on your binding: + + ```javascript + binding = Ember.Binding.from("valueBinding").to("value"); + ``` + + This creates a new binding instance based on the template you provide, and + sets the to path to the `value` property of the new object. Now that the + binding is fully configured with a `from` and a `to`, it simply needs to be + connected to become active. This is done through the `connect()` method: + + ```javascript + binding.connect(this); + ``` + + Note that when you connect a binding you pass the object you want it to be + connected to. This object will be used as the root for both the from and + to side of the binding when inspecting relative paths. This allows the + binding to be automatically inherited by subclassed objects as well. + + This also allows you to bind between objects using the paths you declare in + `from` and `to`: + + ```javascript + // Example 1 + binding = Ember.Binding.from("App.someObject.value").to("value"); + binding.connect(this); + + // Example 2 + binding = Ember.Binding.from("parentView.value").to("App.someObject.value"); + binding.connect(this); + ``` + + Now that the binding is connected, it will observe both the from and to side + and relay changes. + + If you ever needed to do so (you almost never will, but it is useful to + understand this anyway), you could manually create an active binding by + using the `Ember.bind()` helper method. (This is the same method used by + to setup your bindings on objects): + + ```javascript + Ember.bind(MyApp.anotherObject, "value", "MyApp.someController.value"); + ``` + + Both of these code fragments have the same effect as doing the most friendly + form of binding creation like so: + + ```javascript + MyApp.anotherObject = Ember.Object.create({ + valueBinding: "MyApp.someController.value", + + // OTHER CODE FOR THIS OBJECT... + }); + ``` + + Ember's built in binding creation method makes it easy to automatically + create bindings for you. You should always use the highest-level APIs + available, even if you understand how it works underneath. + + @class Binding + @namespace Ember + @since Ember 0.9 + */ + // Ember.Binding = Binding; ES6TODO: where to put this? + + + /** + Global helper method to create a new binding. Just pass the root object + along with a `to` and `from` path to create and connect the binding. + + @method bind + @for Ember + @param {Object} obj The root object of the transform. + @param {String} to The path to the 'to' side of the binding. + Must be relative to obj. + @param {String} from The path to the 'from' side of the binding. + Must be relative to obj or a global path. + @return {Ember.Binding} binding instance + */ + function bind(obj, to, from) { + return new Binding(to, from).connect(obj); + } + + __exports__.bind = bind;/** + @method oneWay + @for Ember + @param {Object} obj The root object of the transform. + @param {String} to The path to the 'to' side of the binding. + Must be relative to obj. + @param {String} from The path to the 'from' side of the binding. + Must be relative to obj or a global path. + @return {Ember.Binding} binding instance + */ + function oneWay(obj, to, from) { + return new Binding(to, from).oneWay().connect(obj); + } + + __exports__.oneWay = oneWay;__exports__.Binding = Binding; + __exports__.isGlobalPath = isGlobalPath; + }); +define("ember-metal/cache", + ["ember-metal/dictionary","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var dictionary = __dependency1__["default"]; + __exports__["default"] = Cache; + + function Cache(limit, func) { + this.store = dictionary(null); + this.size = 0; + this.misses = 0; + this.hits = 0; + this.limit = limit; + this.func = func; + } + + var FALSE = function() { }; + var ZERO = function() { }; + var UNDEFINED = function() { }; + var NULL = function() { }; + + Cache.prototype = { + set: function(key, value) { + if (this.limit > this.size) { + this.size ++; + if (value === undefined) { + this.store[key] = UNDEFINED; + } else { + this.store[key] = value; + } + } + + return value; + }, + + get: function(key) { + var value = this.store[key]; + + if (value === undefined) { + this.misses ++; + value = this.set(key, this.func(key)); + } else if (value === UNDEFINED) { + this.hits ++; + value = undefined; + } else { + this.hits ++; + // nothing to translate + } + + return value; + }, + + purge: function() { + this.store = dictionary(null); + this.size = 0; + this.hits = 0; + this.misses = 0; + } + }; + }); +define("ember-metal/chains", + ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/array","ember-metal/watch_key","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // warn, assert, etc; + var get = __dependency2__.get; + var normalizeTuple = __dependency2__.normalizeTuple; + var meta = __dependency3__.meta; + var forEach = __dependency4__.forEach; + var watchKey = __dependency5__.watchKey; + var unwatchKey = __dependency5__.unwatchKey; + + var metaFor = meta; + var warn = Ember.warn; + var FIRST_KEY = /^([^\.]+)/; + + function firstKey(path) { + return path.match(FIRST_KEY)[0]; + } + + var pendingQueue = []; + + // attempts to add the pendingQueue chains again. If some of them end up + // back in the queue and reschedule is true, schedules a timeout to try + // again. + function flushPendingChains() { + if (pendingQueue.length === 0) { return; } // nothing to do + + var queue = pendingQueue; + pendingQueue = []; + + forEach.call(queue, function(q) { q[0].add(q[1]); }); + + warn('Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos', pendingQueue.length === 0); + } + + __exports__.flushPendingChains = flushPendingChains;function addChainWatcher(obj, keyName, node) { + if (!obj || ('object' !== typeof obj)) { return; } // nothing to do + + var m = metaFor(obj); + var nodes = m.chainWatchers; + + if (!m.hasOwnProperty('chainWatchers')) { + nodes = m.chainWatchers = {}; + } + + if (!nodes[keyName]) { nodes[keyName] = []; } + nodes[keyName].push(node); + watchKey(obj, keyName, m); + } + + function removeChainWatcher(obj, keyName, node) { + if (!obj || 'object' !== typeof obj) { return; } // nothing to do + + var m = obj['__ember_meta__']; + if (m && !m.hasOwnProperty('chainWatchers')) { return; } // nothing to do + + var nodes = m && m.chainWatchers; + + if (nodes && nodes[keyName]) { + nodes = nodes[keyName]; + for (var i = 0, l = nodes.length; i < l; i++) { + if (nodes[i] === node) { + nodes.splice(i, 1); + break; + } + } + } + unwatchKey(obj, keyName, m); + } + + // A ChainNode watches a single key on an object. If you provide a starting + // value for the key then the node won't actually watch it. For a root node + // pass null for parent and key and object for value. + function ChainNode(parent, key, value) { + this._parent = parent; + this._key = key; + + // _watching is true when calling get(this._parent, this._key) will + // return the value of this node. + // + // It is false for the root of a chain (because we have no parent) + // and for global paths (because the parent node is the object with + // the observer on it) + this._watching = value===undefined; + + this._value = value; + this._paths = {}; + if (this._watching) { + this._object = parent.value(); + if (this._object) { addChainWatcher(this._object, this._key, this); } + } + + // Special-case: the EachProxy relies on immediate evaluation to + // establish its observers. + // + // TODO: Replace this with an efficient callback that the EachProxy + // can implement. + if (this._parent && this._parent._key === '@each') { + this.value(); + } + } + + var ChainNodePrototype = ChainNode.prototype; + + function lazyGet(obj, key) { + if (!obj) return undefined; + + var meta = obj['__ember_meta__']; + // check if object meant only to be a prototype + if (meta && meta.proto === obj) return undefined; + + if (key === "@each") return get(obj, key); + + // if a CP only return cached value + var desc = meta && meta.descs[key]; + if (desc && desc._cacheable) { + if (key in meta.cache) { + return meta.cache[key]; + } else { + return undefined; + } + } + + return get(obj, key); + } + + ChainNodePrototype.value = function() { + if (this._value === undefined && this._watching) { + var obj = this._parent.value(); + this._value = lazyGet(obj, this._key); + } + return this._value; + }; + + ChainNodePrototype.destroy = function() { + if (this._watching) { + var obj = this._object; + if (obj) { removeChainWatcher(obj, this._key, this); } + this._watching = false; // so future calls do nothing + } + }; + + // copies a top level object only + ChainNodePrototype.copy = function(obj) { + var ret = new ChainNode(null, null, obj); + var paths = this._paths; + var path; + + for (path in paths) { + if (paths[path] <= 0) { continue; } // this check will also catch non-number vals. + ret.add(path); + } + return ret; + }; + + // called on the root node of a chain to setup watchers on the specified + // path. + ChainNodePrototype.add = function(path) { + var obj, tuple, key, src, paths; + + paths = this._paths; + paths[path] = (paths[path] || 0) + 1; + + obj = this.value(); + tuple = normalizeTuple(obj, path); + + // the path was a local path + if (tuple[0] && tuple[0] === obj) { + path = tuple[1]; + key = firstKey(path); + path = path.slice(key.length+1); + + // global path, but object does not exist yet. + // put into a queue and try to connect later. + } else if (!tuple[0]) { + pendingQueue.push([this, path]); + tuple.length = 0; + return; + + // global path, and object already exists + } else { + src = tuple[0]; + key = path.slice(0, 0-(tuple[1].length+1)); + path = tuple[1]; + } + + tuple.length = 0; + this.chain(key, path, src); + }; + + // called on the root node of a chain to teardown watcher on the specified + // path + ChainNodePrototype.remove = function(path) { + var obj, tuple, key, src, paths; + + paths = this._paths; + if (paths[path] > 0) { paths[path]--; } + + obj = this.value(); + tuple = normalizeTuple(obj, path); + if (tuple[0] === obj) { + path = tuple[1]; + key = firstKey(path); + path = path.slice(key.length+1); + } else { + src = tuple[0]; + key = path.slice(0, 0-(tuple[1].length+1)); + path = tuple[1]; + } + + tuple.length = 0; + this.unchain(key, path); + }; + + ChainNodePrototype.count = 0; + + ChainNodePrototype.chain = function(key, path, src) { + var chains = this._chains; + var node; + if (!chains) { chains = this._chains = {}; } + + node = chains[key]; + if (!node) { node = chains[key] = new ChainNode(this, key, src); } + node.count++; // count chains... + + // chain rest of path if there is one + if (path) { + key = firstKey(path); + path = path.slice(key.length+1); + node.chain(key, path); // NOTE: no src means it will observe changes... + } + }; + + ChainNodePrototype.unchain = function(key, path) { + var chains = this._chains; + var node = chains[key]; + + // unchain rest of path first... + if (path && path.length>1) { + key = firstKey(path); + path = path.slice(key.length+1); + node.unchain(key, path); + } + + // delete node if needed. + node.count--; + if (node.count<=0) { + delete chains[node._key]; + node.destroy(); + } + + }; + + ChainNodePrototype.willChange = function(events) { + var chains = this._chains; + if (chains) { + for(var key in chains) { + if (!chains.hasOwnProperty(key)) { continue; } + chains[key].willChange(events); + } + } + + if (this._parent) { this._parent.chainWillChange(this, this._key, 1, events); } + }; + + ChainNodePrototype.chainWillChange = function(chain, path, depth, events) { + if (this._key) { path = this._key + '.' + path; } + + if (this._parent) { + this._parent.chainWillChange(this, path, depth+1, events); + } else { + if (depth > 1) { + events.push(this.value(), path); + } + path = 'this.' + path; + if (this._paths[path] > 0) { + events.push(this.value(), path); + } + } + }; + + ChainNodePrototype.chainDidChange = function(chain, path, depth, events) { + if (this._key) { path = this._key + '.' + path; } + if (this._parent) { + this._parent.chainDidChange(this, path, depth+1, events); + } else { + if (depth > 1) { + events.push(this.value(), path); + } + path = 'this.' + path; + if (this._paths[path] > 0) { + events.push(this.value(), path); + } + } + }; + + ChainNodePrototype.didChange = function(events) { + // invalidate my own value first. + if (this._watching) { + var obj = this._parent.value(); + if (obj !== this._object) { + removeChainWatcher(this._object, this._key, this); + this._object = obj; + addChainWatcher(obj, this._key, this); + } + this._value = undefined; + + // Special-case: the EachProxy relies on immediate evaluation to + // establish its observers. + if (this._parent && this._parent._key === '@each') + this.value(); + } + + // then notify chains... + var chains = this._chains; + if (chains) { + for(var key in chains) { + if (!chains.hasOwnProperty(key)) { continue; } + chains[key].didChange(events); + } + } + + // if no events are passed in then we only care about the above wiring update + if (events === null) { return; } + + // and finally tell parent about my path changing... + if (this._parent) { this._parent.chainDidChange(this, this._key, 1, events); } + }; + + function finishChains(obj) { + // We only create meta if we really have to + var m = obj['__ember_meta__'], + chains, chainWatchers, chainNodes; + if (m) { + // finish any current chains node watchers that reference obj + chainWatchers = m.chainWatchers; + if (chainWatchers) { + for(var key in chainWatchers) { + if (!chainWatchers.hasOwnProperty(key)) { continue; } + chainNodes = chainWatchers[key]; + if (chainNodes) { + for (var i=0,l=chainNodes.length;i 1) { + args = a_slice.call(arguments); + func = args.pop(); + } + + if (typeof func !== "function") { + throw new EmberError("Computed Property declared without a property function"); + } + + var cp = new ComputedProperty(func); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + /** + Returns the cached value for a property, if one exists. + This can be useful for peeking at the value of a computed + property that is generated lazily, without accidentally causing + it to be created. + + @method cacheFor + @for Ember + @param {Object} obj the object whose property you want to check + @param {String} key the name of the property whose cached value you want + to return + @return {Object} the cached value + */ + function cacheFor(obj, key) { + var meta = obj['__ember_meta__']; + var cache = meta && meta.cache; + var ret = cache && cache[key]; + + if (ret === UNDEFINED) { return undefined; } + return ret; + } + + cacheFor.set = function(cache, key, value) { + if (value === undefined) { + cache[key] = UNDEFINED; + } else { + cache[key] = value; + } + }; + + cacheFor.get = function(cache, key) { + var ret = cache[key]; + if (ret === UNDEFINED) { return undefined; } + return ret; + }; + + cacheFor.remove = function(cache, key) { + cache[key] = undefined; + }; + + __exports__.ComputedProperty = ComputedProperty; + __exports__.computed = computed; + __exports__.cacheFor = cacheFor; + }); +define("ember-metal/computed_macros", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/is_empty","ember-metal/is_none","ember-metal/alias"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var computed = __dependency4__.computed; + var isEmpty = __dependency5__["default"]; + var isNone = __dependency6__.isNone; + var alias = __dependency7__.alias; + + /** + @module ember-metal + */ + + var a_slice = [].slice; + + function getProperties(self, propertyNames) { + var ret = {}; + for(var i = 0; i < propertyNames.length; i++) { + ret[propertyNames[i]] = get(self, propertyNames[i]); + } + return ret; + } + + function registerComputed(name, macro) { + computed[name] = function(dependentKey) { + var args = a_slice.call(arguments); + return computed(dependentKey, function() { + return macro.apply(this, args); + }); + }; + } + + function registerComputedWithProperties(name, macro) { + computed[name] = function() { + var properties = a_slice.call(arguments); + + var computedFunc = computed(function() { + return macro.apply(this, [getProperties(this, properties)]); + }); + + return computedFunc.property.apply(computedFunc, properties); + }; + } + + /** + A computed property that returns true if the value of the dependent + property is null, an empty string, empty array, or empty function. + + Example + + ```javascript + var ToDoList = Ember.Object.extend({ + done: Ember.computed.empty('todos') + }); + + var todoList = ToDoList.create({ + todos: ['Unit Test', 'Documentation', 'Release'] + }); + + todoList.get('done'); // false + todoList.get('todos').clear(); + todoList.get('done'); // true + ``` + + @since 1.6.0 + @method computed.empty + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which negate + the original value for property + */ + computed.empty = function (dependentKey) { + return computed(dependentKey + '.length', function () { + return isEmpty(get(this, dependentKey)); + }); + }; + + /** + A computed property that returns true if the value of the dependent + property is NOT null, an empty string, empty array, or empty function. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasStuff: Ember.computed.notEmpty('backpack') + }); + + var hamster = Hamster.create({ backpack: ['Food', 'Sleeping Bag', 'Tent'] }); + + hamster.get('hasStuff'); // true + hamster.get('backpack').clear(); // [] + hamster.get('hasStuff'); // false + ``` + + @method computed.notEmpty + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which returns true if + original value for property is not empty. + */ + computed.notEmpty = function(dependentKey) { + return computed(dependentKey + '.length', function () { + return !isEmpty(get(this, dependentKey)); + }); + }; + + /** + A computed property that returns true if the value of the dependent + property is null or undefined. This avoids errors from JSLint complaining + about use of ==, which can be technically confusing. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + isHungry: Ember.computed.none('food') + }); + + var hamster = Hamster.create(); + + hamster.get('isHungry'); // true + hamster.set('food', 'Banana'); + hamster.get('isHungry'); // false + hamster.set('food', null); + hamster.get('isHungry'); // true + ``` + + @method computed.none + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which + returns true if original value for property is null or undefined. + */ + registerComputed('none', function(dependentKey) { + return isNone(get(this, dependentKey)); + }); + + /** + A computed property that returns the inverse boolean value + of the original value for the dependent property. + + Example + + ```javascript + var User = Ember.Object.extend({ + isAnonymous: Ember.computed.not('loggedIn') + }); + + var user = User.create({loggedIn: false}); + + user.get('isAnonymous'); // true + user.set('loggedIn', true); + user.get('isAnonymous'); // false + ``` + + @method computed.not + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which returns + inverse of the original value for property + */ + registerComputed('not', function(dependentKey) { + return !get(this, dependentKey); + }); + + /** + A computed property that converts the provided dependent property + into a boolean value. + + ```javascript + var Hamster = Ember.Object.extend({ + hasBananas: Ember.computed.bool('numBananas') + }); + + var hamster = Hamster.create(); + + hamster.get('hasBananas'); // false + hamster.set('numBananas', 0); + hamster.get('hasBananas'); // false + hamster.set('numBananas', 1); + hamster.get('hasBananas'); // true + hamster.set('numBananas', null); + hamster.get('hasBananas'); // false + ``` + + @method computed.bool + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which converts + to boolean the original value for property + */ + registerComputed('bool', function(dependentKey) { + return !!get(this, dependentKey); + }); + + /** + A computed property which matches the original value for the + dependent property against a given RegExp, returning `true` + if they values matches the RegExp and `false` if it does not. + + Example + + ```javascript + var User = Ember.Object.extend({ + hasValidEmail: Ember.computed.match('email', /^.+@.+\..+$/) + }); + + var user = User.create({loggedIn: false}); + + user.get('hasValidEmail'); // false + user.set('email', ''); + user.get('hasValidEmail'); // false + user.set('email', 'ember_hamster@example.com'); + user.get('hasValidEmail'); // true + ``` + + @method computed.match + @for Ember + @param {String} dependentKey + @param {RegExp} regexp + @return {Ember.ComputedProperty} computed property which match + the original value for property against a given RegExp + */ + registerComputed('match', function(dependentKey, regexp) { + var value = get(this, dependentKey); + return typeof value === 'string' ? regexp.test(value) : false; + }); + + /** + A computed property that returns true if the provided dependent property + is equal to the given value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + napTime: Ember.computed.equal('state', 'sleepy') + }); + + var hamster = Hamster.create(); + + hamster.get('napTime'); // false + hamster.set('state', 'sleepy'); + hamster.get('napTime'); // true + hamster.set('state', 'hungry'); + hamster.get('napTime'); // false + ``` + + @method computed.equal + @for Ember + @param {String} dependentKey + @param {String|Number|Object} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is equal to the given value. + */ + registerComputed('equal', function(dependentKey, value) { + return get(this, dependentKey) === value; + }); + + /** + A computed property that returns true if the provided dependent property + is greater than the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasTooManyBananas: Ember.computed.gt('numBananas', 10) + }); + + var hamster = Hamster.create(); + + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 3); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 11); + hamster.get('hasTooManyBananas'); // true + ``` + + @method computed.gt + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is greater than given value. + */ + registerComputed('gt', function(dependentKey, value) { + return get(this, dependentKey) > value; + }); + + /** + A computed property that returns true if the provided dependent property + is greater than or equal to the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasTooManyBananas: Ember.computed.gte('numBananas', 10) + }); + + var hamster = Hamster.create(); + + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 3); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 10); + hamster.get('hasTooManyBananas'); // true + ``` + + @method computed.gte + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is greater or equal then given value. + */ + registerComputed('gte', function(dependentKey, value) { + return get(this, dependentKey) >= value; + }); + + /** + A computed property that returns true if the provided dependent property + is less than the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + needsMoreBananas: Ember.computed.lt('numBananas', 3) + }); + + var hamster = Hamster.create(); + + hamster.get('needsMoreBananas'); // true + hamster.set('numBananas', 3); + hamster.get('needsMoreBananas'); // false + hamster.set('numBananas', 2); + hamster.get('needsMoreBananas'); // true + ``` + + @method computed.lt + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is less then given value. + */ + registerComputed('lt', function(dependentKey, value) { + return get(this, dependentKey) < value; + }); + + /** + A computed property that returns true if the provided dependent property + is less than or equal to the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + needsMoreBananas: Ember.computed.lte('numBananas', 3) + }); + + var hamster = Hamster.create(); + + hamster.get('needsMoreBananas'); // true + hamster.set('numBananas', 5); + hamster.get('needsMoreBananas'); // false + hamster.set('numBananas', 3); + hamster.get('needsMoreBananas'); // true + ``` + + @method computed.lte + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is less or equal than given value. + */ + registerComputed('lte', function(dependentKey, value) { + return get(this, dependentKey) <= value; + }); + + /** + A computed property that performs a logical `and` on the + original values for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + readyForCamp: Ember.computed.and('hasTent', 'hasBackpack') + }); + + var hamster = Hamster.create(); + + hamster.get('readyForCamp'); // false + hamster.set('hasTent', true); + hamster.get('readyForCamp'); // false + hamster.set('hasBackpack', true); + hamster.get('readyForCamp'); // true + ``` + + @method computed.and + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which performs + a logical `and` on the values of all the original values for properties. + */ + registerComputedWithProperties('and', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && !properties[key]) { + return false; + } + } + return true; + }); + + /** + A computed property which performs a logical `or` on the + original values for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + readyForRain: Ember.computed.or('hasJacket', 'hasUmbrella') + }); + + var hamster = Hamster.create(); + + hamster.get('readyForRain'); // false + hamster.set('hasJacket', true); + hamster.get('readyForRain'); // true + ``` + + @method computed.or + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which performs + a logical `or` on the values of all the original values for properties. + */ + registerComputedWithProperties('or', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && properties[key]) { + return true; + } + } + return false; + }); + + /** + A computed property that returns the first truthy value + from a list of dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasClothes: Ember.computed.any('hat', 'shirt') + }); + + var hamster = Hamster.create(); + + hamster.get('hasClothes'); // null + hamster.set('shirt', 'Hawaiian Shirt'); + hamster.get('hasClothes'); // 'Hawaiian Shirt' + ``` + + @method computed.any + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which returns + the first truthy value of given list of properties. + */ + registerComputedWithProperties('any', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && properties[key]) { + return properties[key]; + } + } + return null; + }); + + /** + A computed property that returns the array of values + for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + clothes: Ember.computed.collect('hat', 'shirt') + }); + + var hamster = Hamster.create(); + + hamster.get('clothes'); // [null, null] + hamster.set('hat', 'Camp Hat'); + hamster.set('shirt', 'Camp Shirt'); + hamster.get('clothes'); // ['Camp Hat', 'Camp Shirt'] + ``` + + @method computed.collect + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which maps + values of all passed in properties to an array. + */ + registerComputedWithProperties('collect', function(properties) { + var res = []; + for (var key in properties) { + if (properties.hasOwnProperty(key)) { + if (isNone(properties[key])) { + res.push(null); + } else { + res.push(properties[key]); + } + } + } + return res; + }); + + /** + Creates a new property that is an alias for another property + on an object. Calls to `get` or `set` this property behave as + though they were called on the original property. + + ```javascript + var Person = Ember.Object.extend({ + name: 'Alex Matchneer', + nomen: Ember.computed.alias('name') + }); + + var alex = Person.create(); + + alex.get('nomen'); // 'Alex Matchneer' + alex.get('name'); // 'Alex Matchneer' + + alex.set('nomen', '@machty'); + alex.get('name'); // '@machty' + ``` + + @method computed.alias + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates an + alias to the original value for property. + */ + computed.alias = alias; + + /** + Where `computed.alias` aliases `get` and `set`, and allows for bidirectional + data flow, `computed.oneWay` only provides an aliased `get`. The `set` will + not mutate the upstream property, rather causes the current property to + become the value set. This causes the downstream property to permanently + diverge from the upstream property. + + Example + + ```javascript + var User = Ember.Object.extend({ + firstName: null, + lastName: null, + nickName: Ember.computed.oneWay('firstName') + }); + + var teddy = User.create({ + firstName: 'Teddy', + lastName: 'Zeenny' + }); + + teddy.get('nickName'); // 'Teddy' + teddy.set('nickName', 'TeddyBear'); // 'TeddyBear' + teddy.get('firstName'); // 'Teddy' + ``` + + @method computed.oneWay + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + */ + computed.oneWay = function(dependentKey) { + return alias(dependentKey).oneWay(); + }; + + /** + This is a more semantically meaningful alias of `computed.oneWay`, + whose name is somewhat ambiguous as to which direction the data flows. + + @method computed.reads + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + */ + computed.reads = computed.oneWay; + + /** + Where `computed.oneWay` provides oneWay bindings, `computed.readOnly` provides + a readOnly one way binding. Very often when using `computed.oneWay` one does + not also want changes to propogate back up, as they will replace the value. + + This prevents the reverse flow, and also throws an exception when it occurs. + + Example + + ```javascript + var User = Ember.Object.extend({ + firstName: null, + lastName: null, + nickName: Ember.computed.readOnly('firstName') + }); + + var teddy = User.create({ + firstName: 'Teddy', + lastName: 'Zeenny' + }); + + teddy.get('nickName'); // 'Teddy' + teddy.set('nickName', 'TeddyBear'); // throws Exception + // throw new Ember.Error('Cannot Set: nickName on: ' );` + teddy.get('firstName'); // 'Teddy' + ``` + + @method computed.readOnly + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + @since 1.5.0 + */ + computed.readOnly = function(dependentKey) { + return alias(dependentKey).readOnly(); + }; + /** + A computed property that acts like a standard getter and setter, + but returns the value at the provided `defaultPath` if the + property itself has not been set to a value + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + wishList: Ember.computed.defaultTo('favoriteFood') + }); + + var hamster = Hamster.create({ favoriteFood: 'Banana' }); + + hamster.get('wishList'); // 'Banana' + hamster.set('wishList', 'More Unit Tests'); + hamster.get('wishList'); // 'More Unit Tests' + hamster.get('favoriteFood'); // 'Banana' + ``` + + @method computed.defaultTo + @for Ember + @param {String} defaultPath + @return {Ember.ComputedProperty} computed property which acts like + a standard getter and setter, but defaults to the value from `defaultPath`. + @deprecated Use `Ember.computed.oneWay` or custom CP with default instead. + */ + // ES6TODO: computed should have its own export path so you can do import {defaultTo} from computed + computed.defaultTo = function(defaultPath) { + return computed(function(key, newValue, cachedValue) { + Ember.deprecate('Usage of Ember.computed.defaultTo is deprecated, use `Ember.computed.oneWay` instead.'); + + if (arguments.length === 1) { + return get(this, defaultPath); + } + return newValue != null ? newValue : get(this, defaultPath); + }); + }; + + /** + Creates a new property that is an alias for another property + on an object. Calls to `get` or `set` this property behave as + though they were called on the original property, but also + print a deprecation warning. + + @method computed.deprecatingAlias + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates an + alias with a deprecation to the original value for property. + @since 1.7.0 + */ + computed.deprecatingAlias = function(dependentKey) { + return computed(dependentKey, function(key, value) { + Ember.deprecate('Usage of `' + key + '` is deprecated, use `' + dependentKey + '` instead.'); + + if (arguments.length > 1) { + set(this, dependentKey, value); + return value; + } else { + return get(this, dependentKey); + } + }); + }; + }); +define("ember-metal/core", + ["exports"], + function(__exports__) { + "use strict"; + /*globals Ember:true,Em:true,ENV,EmberENV,MetamorphENV:true */ + + /** + @module ember + @submodule ember-metal + */ + + /** + All Ember methods and functions are defined inside of this namespace. You + generally should not add new properties to this namespace as it may be + overwritten by future versions of Ember. + + You can also use the shorthand `Em` instead of `Ember`. + + Ember-Runtime is a framework that provides core functions for Ember including + cross-platform functions, support for property observing and objects. Its + focus is on small size and performance. You can use this in place of or + along-side other cross-platform libraries such as jQuery. + + The core Runtime framework is based on the jQuery API with a number of + performance optimizations. + + @class Ember + @static + @version 1.8.0-beta.4 + */ + + if ('undefined' === typeof Ember) { + // Create core object. Make it act like an instance of Ember.Namespace so that + // objects assigned to it are given a sane string representation. + Ember = {}; + } + + // Default imports, exports and lookup to the global object; + var imports = Ember.imports = Ember.imports || this; + var exports = Ember.exports = Ember.exports || this; + var lookup = Ember.lookup = Ember.lookup || this; + + // aliases needed to keep minifiers from removing the global context + exports.Em = exports.Ember = Ember; + + // Make sure these are set whether Ember was already defined or not + + Ember.isNamespace = true; + + Ember.toString = function() { return "Ember"; }; + + + /** + @property VERSION + @type String + @default '1.8.0-beta.4' + @static + */ + Ember.VERSION = '1.8.0-beta.4'; + + /** + Standard environmental variables. You can define these in a global `EmberENV` + variable before loading Ember to control various configuration settings. + + For backwards compatibility with earlier versions of Ember the global `ENV` + variable will be used if `EmberENV` is not defined. + + @property ENV + @type Hash + */ + + if (Ember.ENV) { + // do nothing if Ember.ENV is already setup + } else if ('undefined' !== typeof EmberENV) { + Ember.ENV = EmberENV; + } else if('undefined' !== typeof ENV) { + Ember.ENV = ENV; + } else { + Ember.ENV = {}; + } + + Ember.config = Ember.config || {}; + + // We disable the RANGE API by default for performance reasons + if ('undefined' === typeof Ember.ENV.DISABLE_RANGE_API) { + Ember.ENV.DISABLE_RANGE_API = true; + } + + if ("undefined" === typeof MetamorphENV) { + exports.MetamorphENV = {}; + } + + MetamorphENV.DISABLE_RANGE_API = Ember.ENV.DISABLE_RANGE_API; + + /** + Hash of enabled Canary features. Add to this before creating your application. + + You can also define `ENV.FEATURES` if you need to enable features flagged at runtime. + + @class FEATURES + @namespace Ember + @static + @since 1.1.0 + */ + + Ember.FEATURES = Ember.ENV.FEATURES || {}; + + /** + Test that a feature is enabled. Parsed by Ember's build tools to leave + experimental features out of beta/stable builds. + + You can define the following configuration options: + + * `ENV.ENABLE_ALL_FEATURES` - force all features to be enabled. + * `ENV.ENABLE_OPTIONAL_FEATURES` - enable any features that have not been explicitly + enabled/disabled. + + @method isEnabled + @param {String} feature + @return {Boolean} + @for Ember.FEATURES + @since 1.1.0 + */ + + Ember.FEATURES.isEnabled = function(feature) { + var featureValue = Ember.FEATURES[feature]; + + if (Ember.ENV.ENABLE_ALL_FEATURES) { + return true; + } else if (featureValue === true || featureValue === false || featureValue === undefined) { + return featureValue; + } else if (Ember.ENV.ENABLE_OPTIONAL_FEATURES) { + return true; + } else { + return false; + } + }; + + // .......................................................... + // BOOTSTRAP + // + + /** + Determines whether Ember should enhance some built-in object prototypes to + provide a more friendly API. If enabled, a few methods will be added to + `Function`, `String`, and `Array`. `Object.prototype` will not be enhanced, + which is the one that causes most trouble for people. + + In general we recommend leaving this option set to true since it rarely + conflicts with other code. If you need to turn it off however, you can + define an `ENV.EXTEND_PROTOTYPES` config to disable it. + + @property EXTEND_PROTOTYPES + @type Boolean + @default true + @for Ember + */ + Ember.EXTEND_PROTOTYPES = Ember.ENV.EXTEND_PROTOTYPES; + + if (typeof Ember.EXTEND_PROTOTYPES === 'undefined') { + Ember.EXTEND_PROTOTYPES = true; + } + + /** + Determines whether Ember logs a full stack trace during deprecation warnings + + @property LOG_STACKTRACE_ON_DEPRECATION + @type Boolean + @default true + */ + Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !== false); + + /** + Determines whether Ember should add ECMAScript 5 shims to older browsers. + + @property SHIM_ES5 + @type Boolean + @default Ember.EXTEND_PROTOTYPES + */ + Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : Ember.EXTEND_PROTOTYPES; + + /** + Determines whether Ember logs info about version of used libraries + + @property LOG_VERSION + @type Boolean + @default true + */ + Ember.LOG_VERSION = (Ember.ENV.LOG_VERSION === false) ? false : true; + + /** + Empty function. Useful for some operations. Always returns `this`. + + @method K + @private + @return {Object} + */ + var K = function() { return this; }; + var K = K; + __exports__.K = K;Ember.K = K; + //TODO: ES6 GLOBL TODO + + // Stub out the methods defined by the ember-debug package in case it's not loaded + + if ('undefined' === typeof Ember.assert) { Ember.assert = Ember.K; } + if ('undefined' === typeof Ember.warn) { Ember.warn = Ember.K; } + if ('undefined' === typeof Ember.debug) { Ember.debug = Ember.K; } + if ('undefined' === typeof Ember.runInDebug) { Ember.runInDebug = Ember.K; } + if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = Ember.K; } + if ('undefined' === typeof Ember.deprecateFunc) { + Ember.deprecateFunc = function(_, func) { return func; }; + } + + __exports__["default"] = Ember; + }); +define("ember-metal/dependent_keys", + ["ember-metal/platform","ember-metal/watching","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var create = __dependency1__.create; + var watch = __dependency2__.watch; + var unwatch = __dependency2__.unwatch; + + /** + @module ember-metal + */ + + var o_create = create; + + // .......................................................... + // DEPENDENT KEYS + // + + // data structure: + // meta.deps = { + // 'depKey': { + // 'keyName': count, + // } + // } + + /* + This function returns a map of unique dependencies for a + given object and key. + */ + function keysForDep(depsMeta, depKey) { + var keys = depsMeta[depKey]; + if (!keys) { + // if there are no dependencies yet for a the given key + // create a new empty list of dependencies for the key + keys = depsMeta[depKey] = {}; + } else if (!depsMeta.hasOwnProperty(depKey)) { + // otherwise if the dependency list is inherited from + // a superclass, clone the hash + keys = depsMeta[depKey] = o_create(keys); + } + return keys; + } + + function metaForDeps(meta) { + return keysForDep(meta, 'deps'); + } + + function addDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // add all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Increment the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) + 1; + // Watch the depKey + watch(obj, depKey, meta); + } + } + + __exports__.addDependentKeys = addDependentKeys;function removeDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // remove all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Decrement the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) - 1; + // Unwatch the depKey + unwatch(obj, depKey, meta); + } + } + + __exports__.removeDependentKeys = removeDependentKeys; + }); +define("ember-metal/deprecate_property", + ["ember-metal/core","ember-metal/platform","ember-metal/properties","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var Ember = __dependency1__["default"]; + var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; + var defineProperty = __dependency3__.defineProperty; + var get = __dependency4__.get; + var set = __dependency5__.set; + + + /** + Used internally to allow changing properties in a backwards compatible way, and print a helpful + deprecation warning. + + @method deprecateProperty + @param {Object} object The object to add the deprecated property to. + @param {String} deprecatedKey The property to add (and print deprecation warnings upon accessing). + @param {String} newKey The property that will be aliased. + @private + @since 1.7.0 + */ + + function deprecateProperty(object, deprecatedKey, newKey) { + function deprecate() { + Ember.deprecate('Usage of `' + deprecatedKey + '` is deprecated, use `' + newKey + '` instead.'); + } + + if (hasPropertyAccessors) { + defineProperty(object, deprecatedKey, { + configurable: true, + enumerable: false, + set: function(value) { deprecate(); set(this, newKey, value); }, + get: function() { deprecate(); return get(this, newKey); } + }); + } + } + + __exports__.deprecateProperty = deprecateProperty; + }); +define("ember-metal/dictionary", + ["exports"], + function(__exports__) { + "use strict"; + // the delete is meant to hint at runtimes that this object should remain in + // dictionary mode. This is clearly a runtime specific hack, but currently it + // appears worthwile in some usecases. Please note, these deletes do increase + // the cost of creation dramatically over a plain Object.create. And as this + // only makes sense for long-lived dictionaries that aren't instantiated often. + __exports__["default"] = function makeDictionary(parent) { + var dict = Object.create(parent); + dict['_dict'] = null; + delete dict['_dict']; + return dict; + } + }); +define("ember-metal/enumerable_utils", + ["ember-metal/array","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var _filter = __dependency1__.filter; + var a_forEach = __dependency1__.forEach; + var _indexOf = __dependency1__.indexOf; + var _map = __dependency1__.map; + + var splice = Array.prototype.splice; + + /** + * Defines some convenience methods for working with Enumerables. + * `Ember.EnumerableUtils` uses `Ember.ArrayPolyfills` when necessary. + * + * @class EnumerableUtils + * @namespace Ember + * @static + * */ + + /** + * Calls the map function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-map method when necessary. + * + * @method map + * @param {Object} obj The object that should be mapped + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + * @return {Array} An array of mapped values. + */ + function map(obj, callback, thisArg) { + return obj.map ? obj.map.call(obj, callback, thisArg) : _map.call(obj, callback, thisArg); + } + + __exports__.map = map;/** + * Calls the forEach function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-forEach method when necessary. + * + * @method forEach + * @param {Object} obj The object to call forEach on + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + */ + function forEach(obj, callback, thisArg) { + return obj.forEach ? obj.forEach.call(obj, callback, thisArg) : a_forEach.call(obj, callback, thisArg); + } + + __exports__.forEach = forEach;/** + * Calls the filter function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-filter method when necessary. + * + * @method filter + * @param {Object} obj The object to call filter on + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + * @return {Array} An array containing the filtered values + * @since 1.4.0 + */ + function filter(obj, callback, thisArg) { + return obj.filter ? obj.filter.call(obj, callback, thisArg) : _filter.call(obj, callback, thisArg); + } + + __exports__.filter = filter;/** + * Calls the indexOf function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-indexOf method when necessary. + * + * @method indexOf + * @param {Object} obj The object to call indexOn on + * @param {Function} callback The callback to execute + * @param {Object} index The index to start searching from + * + */ + function indexOf(obj, element, index) { + return obj.indexOf ? obj.indexOf.call(obj, element, index) : _indexOf.call(obj, element, index); + } + + __exports__.indexOf = indexOf;/** + * Returns an array of indexes of the first occurrences of the passed elements + * on the passed object. + * + * ```javascript + * var array = [1, 2, 3, 4, 5]; + * Ember.EnumerableUtils.indexesOf(array, [2, 5]); // [1, 4] + * + * var fubar = "Fubarr"; + * Ember.EnumerableUtils.indexesOf(fubar, ['b', 'r']); // [2, 4] + * ``` + * + * @method indexesOf + * @param {Object} obj The object to check for element indexes + * @param {Array} elements The elements to search for on *obj* + * + * @return {Array} An array of indexes. + * + */ + function indexesOf(obj, elements) { + return elements === undefined ? [] : map(elements, function(item) { + return indexOf(obj, item); + }); + } + + __exports__.indexesOf = indexesOf;/** + * Adds an object to an array. If the array already includes the object this + * method has no effect. + * + * @method addObject + * @param {Array} array The array the passed item should be added to + * @param {Object} item The item to add to the passed array + * + * @return 'undefined' + */ + function addObject(array, item) { + var index = indexOf(array, item); + if (index === -1) { array.push(item); } + } + + __exports__.addObject = addObject;/** + * Removes an object from an array. If the array does not contain the passed + * object this method has no effect. + * + * @method removeObject + * @param {Array} array The array to remove the item from. + * @param {Object} item The item to remove from the passed array. + * + * @return 'undefined' + */ + function removeObject(array, item) { + var index = indexOf(array, item); + if (index !== -1) { array.splice(index, 1); } + } + + __exports__.removeObject = removeObject;function _replace(array, idx, amt, objects) { + var args = [].concat(objects); + var ret = []; + // https://code.google.com/p/chromium/issues/detail?id=56588 + var size = 60000; + var start = idx; + var ends = amt; + var count, chunk; + + while (args.length) { + count = ends > size ? size : ends; + if (count <= 0) { count = 0; } + + chunk = args.splice(0, size); + chunk = [start, count].concat(chunk); + + start += size; + ends -= count; + + ret = ret.concat(splice.apply(array, chunk)); + } + return ret; + } + + __exports__._replace = _replace;/** + * Replaces objects in an array with the passed objects. + * + * ```javascript + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 1, 2, [4, 5]); // [1, 4, 5] + * + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 1, 1, [4, 5]); // [1, 4, 5, 3] + * + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 10, 1, [4, 5]); // [1, 2, 3, 4, 5] + * ``` + * + * @method replace + * @param {Array} array The array the objects should be inserted into. + * @param {Number} idx Starting index in the array to replace. If *idx* >= + * length, then append to the end of the array. + * @param {Number} amt Number of elements that should be removed from the array, + * starting at *idx* + * @param {Array} objects An array of zero or more objects that should be + * inserted into the array at *idx* + * + * @return {Array} The modified array. + */ + function replace(array, idx, amt, objects) { + if (array.replace) { + return array.replace(idx, amt, objects); + } else { + return _replace(array, idx, amt, objects); + } + } + + __exports__.replace = replace;/** + * Calculates the intersection of two arrays. This method returns a new array + * filled with the records that the two passed arrays share with each other. + * If there is no intersection, an empty array will be returned. + * + * ```javascript + * var array1 = [1, 2, 3, 4, 5]; + * var array2 = [1, 3, 5, 6, 7]; + * + * Ember.EnumerableUtils.intersection(array1, array2); // [1, 3, 5] + * + * var array1 = [1, 2, 3]; + * var array2 = [4, 5, 6]; + * + * Ember.EnumerableUtils.intersection(array1, array2); // [] + * ``` + * + * @method intersection + * @param {Array} array1 The first array + * @param {Array} array2 The second array + * + * @return {Array} The intersection of the two passed arrays. + */ + function intersection(array1, array2) { + var result = []; + forEach(array1, function(element) { + if (indexOf(array2, element) >= 0) { + result.push(element); + } + }); + + return result; + } + + __exports__.intersection = intersection;// TODO: this only exists to maintain the existing api, as we move forward it + // should only be part of the "global build" via some shim + __exports__["default"] = { + _replace: _replace, + addObject: addObject, + filter: filter, + forEach: forEach, + indexOf: indexOf, + indexesOf: indexesOf, + intersection: intersection, + map: map, + removeObject: removeObject, + replace: replace + }; + }); +define("ember-metal/error", + ["ember-metal/platform","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var create = __dependency1__.create; + + var errorProps = [ + 'description', + 'fileName', + 'lineNumber', + 'message', + 'name', + 'number', + 'stack' + ]; + + /** + A subclass of the JavaScript Error object for use in Ember. + + @class Error + @namespace Ember + @extends Error + @constructor + */ + function EmberError() { + var tmp = Error.apply(this, arguments); + + // Adds a `stack` property to the given error object that will yield the + // stack trace at the time captureStackTrace was called. + // When collecting the stack trace all frames above the topmost call + // to this function, including that call, will be left out of the + // stack trace. + // This is useful because we can hide Ember implementation details + // that are not very helpful for the user. + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Ember.Error); + } + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + } + + EmberError.prototype = create(Error.prototype); + + __exports__["default"] = EmberError; + }); +define("ember-metal/events", + ["ember-metal/core","ember-metal/utils","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + var Ember = __dependency1__["default"]; + var meta = __dependency2__.meta; + var tryFinally = __dependency2__.tryFinally; + var apply = __dependency2__.apply; + var applyStr = __dependency2__.applyStr; + var create = __dependency3__.create; + + var a_slice = [].slice; + var metaFor = meta; + + /* listener flags */ + var ONCE = 1; + var SUSPENDED = 2; + + + /* + The event system uses a series of nested hashes to store listeners on an + object. When a listener is registered, or when an event arrives, these + hashes are consulted to determine which target and action pair to invoke. + + The hashes are stored in the object's meta hash, and look like this: + + // Object's meta hash + { + listeners: { // variable name: `listenerSet` + "foo:changed": [ // variable name: `actions` + target, method, flags + ] + } + } + + */ + + function indexOf(array, target, method) { + var index = -1; + // hashes are added to the end of the event array + // so it makes sense to start searching at the end + // of the array and search in reverse + for (var i = array.length - 3 ; i >=0; i -= 3) { + if (target === array[i] && method === array[i + 1]) { + index = i; break; + } + } + return index; + } + + function actionsFor(obj, eventName) { + var meta = metaFor(obj, true); + var actions; + + if (!meta.listeners) { meta.listeners = {}; } + + if (!meta.hasOwnProperty('listeners')) { + // setup inherited copy of the listeners object + meta.listeners = create(meta.listeners); + } + + actions = meta.listeners[eventName]; + + // if there are actions, but the eventName doesn't exist in our listeners, then copy them from the prototype + if (actions && !meta.listeners.hasOwnProperty(eventName)) { + actions = meta.listeners[eventName] = meta.listeners[eventName].slice(); + } else if (!actions) { + actions = meta.listeners[eventName] = []; + } + + return actions; + } + + function listenersUnion(obj, eventName, otherActions) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + var target = actions[i]; + var method = actions[i+1]; + var flags = actions[i+2]; + var actionIndex = indexOf(otherActions, target, method); + + if (actionIndex === -1) { + otherActions.push(target, method, flags); + } + } + } + + __exports__.listenersUnion = listenersUnion;function listenersDiff(obj, eventName, otherActions) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + var diffActions = []; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + var target = actions[i]; + var method = actions[i+1]; + var flags = actions[i+2]; + var actionIndex = indexOf(otherActions, target, method); + + if (actionIndex !== -1) { continue; } + + otherActions.push(target, method, flags); + diffActions.push(target, method, flags); + } + + return diffActions; + } + + __exports__.listenersDiff = listenersDiff;/** + Add an event listener + + @method addListener + @for Ember + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Boolean} once A flag whether a function should only be called once + */ + function addListener(obj, eventName, target, method, once) { + Ember.assert("You must pass at least an object and event name to Ember.addListener", !!obj && !!eventName); + + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + var flags = 0; + + if (once) flags |= ONCE; + + if (actionIndex !== -1) { return; } + + actions.push(target, method, flags); + + if ('function' === typeof obj.didAddListener) { + obj.didAddListener(eventName, target, method); + } + } + + __exports__.addListener = addListener;/** + Remove an event listener + + Arguments should match those passed to `Ember.addListener`. + + @method removeListener + @for Ember + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + */ + function removeListener(obj, eventName, target, method) { + Ember.assert("You must pass at least an object and event name to Ember.removeListener", !!obj && !!eventName); + + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + function _removeListener(target, method) { + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + + // action doesn't exist, give up silently + if (actionIndex === -1) { return; } + + actions.splice(actionIndex, 3); + + if ('function' === typeof obj.didRemoveListener) { + obj.didRemoveListener(eventName, target, method); + } + } + + if (method) { + _removeListener(target, method); + } else { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + _removeListener(actions[i], actions[i+1]); + } + } + } + + /** + Suspend listener during callback. + + This should only be used by the target of the event listener + when it is taking an action that would cause the event, e.g. + an object might suspend its property change listener while it is + setting that property. + + @method suspendListener + @for Ember + + @private + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Function} callback + */ + function suspendListener(obj, eventName, target, method, callback) { + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + + if (actionIndex !== -1) { + actions[actionIndex+2] |= SUSPENDED; // mark the action as suspended + } + + function tryable() { return callback.call(target); } + function finalizer() { if (actionIndex !== -1) { actions[actionIndex+2] &= ~SUSPENDED; } } + + return tryFinally(tryable, finalizer); + } + + __exports__.suspendListener = suspendListener;/** + Suspends multiple listeners during a callback. + + @method suspendListeners + @for Ember + + @private + @param obj + @param {Array} eventName Array of event names + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Function} callback + */ + function suspendListeners(obj, eventNames, target, method, callback) { + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var suspendedActions = []; + var actionsList = []; + var eventName, actions, i, l; + + for (i=0, l=eventNames.length; i= 0; i -= 3) { // looping in reverse for once listeners + var target = actions[i], method = actions[i+1], flags = actions[i+2]; + if (!method) { continue; } + if (flags & SUSPENDED) { continue; } + if (flags & ONCE) { removeListener(obj, eventName, target, method); } + if (!target) { target = obj; } + if ('string' === typeof method) { + if (params) { + applyStr(target, method, params); + } else { + target[method](); + } + } else { + if (params) { + apply(target, method, params); + } else { + method.call(target); + } + } + } + return true; + } + + __exports__.sendEvent = sendEvent;/** + @private + @method hasListeners + @for Ember + @param obj + @param {String} eventName + */ + function hasListeners(obj, eventName) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + return !!(actions && actions.length); + } + + __exports__.hasListeners = hasListeners;/** + @private + @method listenersFor + @for Ember + @param obj + @param {String} eventName + */ + function listenersFor(obj, eventName) { + var ret = []; + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return ret; } + + for (var i = 0, l = actions.length; i < l; i += 3) { + var target = actions[i]; + var method = actions[i+1]; + ret.push([target, method]); + } + + return ret; + } + + __exports__.listenersFor = listenersFor;/** + Define a property as a function that should be executed when + a specified event or events are triggered. + + + ``` javascript + var Job = Ember.Object.extend({ + logCompleted: Ember.on('completed', function() { + console.log('Job completed!'); + }) + }); + + var job = Job.create(); + + Ember.sendEvent(job, 'completed'); // Logs 'Job completed!' + ``` + + @method on + @for Ember + @param {String} eventNames* + @param {Function} func + @return func + */ + function on(){ + var func = a_slice.call(arguments, -1)[0]; + var events = a_slice.call(arguments, 0, -1); + func.__ember_listens__ = events; + return func; + } + + __exports__.on = on;__exports__.removeListener = removeListener; + }); +define("ember-metal/expand_properties", + ["ember-metal/core","ember-metal/error","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var EmberError = __dependency2__["default"]; + var forEach = __dependency3__.forEach; + + /** + @module ember-metal + */ + + var BRACE_EXPANSION = /^((?:[^\.]*\.)*)\{(.*)\}$/; + var SPLIT_REGEX = /\{|\}/; + + /** + Expands `pattern`, invoking `callback` for each expansion. + + The only pattern supported is brace-expansion, anything else will be passed + once to `callback` directly. + + Example + + ```js + function echo(arg){ console.log(arg); } + + Ember.expandProperties('foo.bar', echo); //=> 'foo.bar' + Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar' + Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.bar', 'foo.baz' + Ember.expandProperties('{foo,bar}.baz', echo); //=> '{foo,bar}.baz' + Ember.expandProperties('foo.{bar,baz}.@each', echo) //=> 'foo.bar.@each', 'foo.baz.@each' + Ember.expandProperties('{foo,bar}.{spam,eggs}', echo) //=> 'foo.spam', 'foo.eggs', 'bar.spam', 'bar.eggs' + Ember.expandProperties('{foo}.bar.{baz}') //=> 'foo.bar.baz' + ``` + + @method + @private + @param {String} pattern The property pattern to expand. + @param {Function} callback The callback to invoke. It is invoked once per + expansion, and is passed the expansion. + */ + __exports__["default"] = function expandProperties(pattern, callback) { + if (pattern.indexOf(' ') > -1) { + throw new EmberError('Brace expanded properties cannot contain spaces, ' + + 'e.g. `user.{firstName, lastName}` should be `user.{firstName,lastName}`'); + } + + + return newExpandProperties(pattern, callback); + } + + function oldExpandProperties(pattern, callback) { + var match, prefix, list; + + if (match = BRACE_EXPANSION.exec(pattern)) { + prefix = match[1]; + list = match[2]; + + forEach(list.split(','), function (suffix) { + callback(prefix + suffix); + }); + } else { + callback(pattern); + } + } + + function newExpandProperties(pattern, callback) { + if ('string' === Ember.typeOf(pattern)) { + var parts = pattern.split(SPLIT_REGEX); + var properties = [parts]; + + forEach(parts, function(part, index) { + if (part.indexOf(',') >= 0) { + properties = duplicateAndReplace(properties, part.split(','), index); + } + }); + + forEach(properties, function(property) { + callback(property.join('')); + }); + } else { + callback(pattern); + } + } + + function duplicateAndReplace(properties, currentParts, index) { + var all = []; + + forEach(properties, function(property) { + forEach(currentParts, function(part) { + var current = property.slice(0); + current[index] = part; + all.push(current); + }); + }); + + return all; + } + }); +define("ember-metal/get_properties", + ["ember-metal/property_get","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var typeOf = __dependency2__.typeOf; + + /** + To get multiple properties at once, call `Ember.getProperties` + with an object followed by a list of strings or an array: + + ```javascript + Ember.getProperties(record, 'firstName', 'lastName', 'zipCode'); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + is equivalent to: + + ```javascript + Ember.getProperties(record, ['firstName', 'lastName', 'zipCode']); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + @method getProperties + @param obj + @param {String...|Array} list of keys to get + @return {Hash} + */ + __exports__["default"] = function getProperties(obj) { + var ret = {}; + var propertyNames = arguments; + var i = 1; + + if (arguments.length === 2 && typeOf(arguments[1]) === 'array') { + i = 0; + propertyNames = arguments[1]; + } + for(var len = propertyNames.length; i < len; i++) { + ret[propertyNames[i]] = get(obj, propertyNames[i]); + } + return ret; + } + }); +define("ember-metal/instrumentation", + ["ember-metal/core","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var tryCatchFinally = __dependency2__.tryCatchFinally; + + /** + The purpose of the Ember Instrumentation module is + to provide efficient, general-purpose instrumentation + for Ember. + + Subscribe to a listener by using `Ember.subscribe`: + + ```javascript + Ember.subscribe("render", { + before: function(name, timestamp, payload) { + + }, + + after: function(name, timestamp, payload) { + + } + }); + ``` + + If you return a value from the `before` callback, that same + value will be passed as a fourth parameter to the `after` + callback. + + Instrument a block of code by using `Ember.instrument`: + + ```javascript + Ember.instrument("render.handlebars", payload, function() { + // rendering logic + }, binding); + ``` + + Event names passed to `Ember.instrument` are namespaced + by periods, from more general to more specific. Subscribers + can listen for events by whatever level of granularity they + are interested in. + + In the above example, the event is `render.handlebars`, + and the subscriber listened for all events beginning with + `render`. It would receive callbacks for events named + `render`, `render.handlebars`, `render.container`, or + even `render.handlebars.layout`. + + @class Instrumentation + @namespace Ember + @static + */ + var subscribers = []; + __exports__.subscribers = subscribers;var cache = {}; + + var populateListeners = function(name) { + var listeners = []; + var subscriber; + + for (var i=0, l=subscribers.length; i -1) { + list.splice(index, 1); + } + this.size--; + return true; + } else { + return false; + } + }, + + /** + @method isEmpty + @return {Boolean} + */ + isEmpty: function() { + return this.size === 0; + }, + + /** + @method has + @param obj + @return {Boolean} + */ + has: function(obj) { + if (this.size === 0) { return false; } + + var guid = guidFor(obj); + var presenceSet = this.presenceSet; + + return !!presenceSet[guid]; + }, + + /** + @method forEach + @param {Function} fn + @param self + */ + forEach: function(fn /*, thisArg*/) { + if (typeof fn !== 'function') { + missingFunction(fn); + } + + if (this.size === 0) { return; } + + var list = this.list; + var length = arguments.length; + var i; + + if (length === 2) { + for (i = 0; i < list.length; i++) { + fn.call(arguments[1], list[i]); + } + } else { + for (i = 0; i < list.length; i++) { + fn(list[i]); + } + } + }, + + /** + @method toArray + @return {Array} + */ + toArray: function() { + return this.list.slice(); + }, + + /** + @method copy + @return {Ember.OrderedSet} + */ + copy: function() { + var Constructor = this.constructor; + var set = new Constructor(); + + set._silenceRemoveDeprecation = this._silenceRemoveDeprecation; + set.presenceSet = copyNull(this.presenceSet); + set.list = this.toArray(); + set.size = this.size; + + return set; + } + }; + + deprecateProperty(OrderedSet.prototype, 'length', 'size'); + + /** + A Map stores values indexed by keys. Unlike JavaScript's + default Objects, the keys of a Map can be any JavaScript + object. + + Internally, a Map has two data structures: + + 1. `keys`: an OrderedSet of all of the existing keys + 2. `values`: a JavaScript Object indexed by the `Ember.guidFor(key)` + + When a key/value pair is added for the first time, we + add the key to the `keys` OrderedSet, and create or + replace an entry in `values`. When an entry is deleted, + we delete its entry in `keys` and `values`. + + @class Map + @namespace Ember + @private + @constructor + */ + function Map() { + if (this instanceof this.constructor) { + this.keys = OrderedSet.create(); + this.keys._silenceRemoveDeprecation = true; + this.values = Object.create(null); + this.size = 0; + } else { + missingNew("OrderedSet"); + } + } + + Ember.Map = Map; + + /** + @method create + @static + */ + Map.create = function() { + var Constructor = this; + return new Constructor(); + }; + + Map.prototype = { + constructor: Map, + + /** + This property will change as the number of objects in the map changes. + + @property size + @type number + @default 0 + */ + size: 0, + + /** + Retrieve the value associated with a given key. + + @method get + @param {*} key + @return {*} the value associated with the key, or `undefined` + */ + get: function(key) { + if (this.size === 0) { return; } + + var values = this.values; + var guid = guidFor(key); + + return values[guid]; + }, + + /** + Adds a value to the map. If a value for the given key has already been + provided, the new value will replace the old value. + + @method set + @param {*} key + @param {*} value + @return {Ember.Map} + */ + set: function(key, value) { + var keys = this.keys; + var values = this.values; + var guid = guidFor(key); + + // ensure we don't store -0 + var k = key === -0 ? 0 : key; + + keys.add(k, guid); + + values[guid] = value; + + this.size = keys.size; + + return this; + }, + + /** + @deprecated see delete + Removes a value from the map for an associated key. + + @method remove + @param {*} key + @return {Boolean} true if an item was removed, false otherwise + */ + remove: function(key) { + Ember.deprecate('Calling `Map.prototype.remove` has been deprecated, please use `Map.prototype.delete` instead.'); + + return this["delete"](key); + }, + + /** + Removes a value from the map for an associated key. + + @method delete + @param {*} key + @return {Boolean} true if an item was removed, false otherwise + */ + "delete": function(key) { + if (this.size === 0) { return false; } + // don't use ES6 "delete" because it will be annoying + // to use in browsers that are not ES6 friendly; + var keys = this.keys; + var values = this.values; + var guid = guidFor(key); + + if (values[guid]) { + keys["delete"](key, guid); + delete values[guid]; + this.size = keys.size; + return true; + } else { + return false; + } + }, + + /** + Check whether a key is present. + + @method has + @param {*} key + @return {Boolean} true if the item was present, false otherwise + */ + has: function(key) { + if (this.size === 0) { return false; } + return this.keys.has(key); + }, + + /** + Iterate over all the keys and values. Calls the function once + for each key, passing in the key and value, in that order. + + The keys are guaranteed to be iterated over in insertion order. + + @method forEach + @param {Function} callback + @param {*} self if passed, the `this` value inside the + callback. By default, `this` is the map. + */ + forEach: function(callback /*, thisArg*/) { + if (typeof callback !== 'function') { + missingFunction(callback); + } + + if (this.size === 0) { return; } + + var length = arguments.length; + var map = this; + var cb, thisArg; + + if (length === 2) { + thisArg = arguments[1]; + cb = function(key) { + callback.call(thisArg, map.get(key), key); + }; + } else { + cb = function(key) { + callback(map.get(key), key); + }; + } + + this.keys.forEach(cb); + }, + + /** + @method clear + */ + clear: function() { + this.keys.clear(); + this.values = Object.create(null); + this.size = 0; + }, + + /** + @method copy + @return {Ember.Map} + */ + copy: function() { + return copyMap(this, new Map()); + } + }; + + deprecateProperty(Map.prototype, 'length', 'size'); + + /** + @class MapWithDefault + @namespace Ember + @extends Ember.Map + @private + @constructor + @param [options] + @param {*} [options.defaultValue] + */ + function MapWithDefault(options) { + this._super$constructor(); + this.defaultValue = options.defaultValue; + } + + /** + @method create + @static + @param [options] + @param {*} [options.defaultValue] + @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns + `Ember.MapWithDefault` otherwise returns `Ember.Map` + */ + MapWithDefault.create = function(options) { + if (options) { + return new MapWithDefault(options); + } else { + return new Map(); + } + }; + + MapWithDefault.prototype = create(Map.prototype); + MapWithDefault.prototype.constructor = MapWithDefault; + MapWithDefault.prototype._super$constructor = Map; + MapWithDefault.prototype._super$get = Map.prototype.get; + + /** + Retrieve the value associated with a given key. + + @method get + @param {*} key + @return {*} the value associated with the key, or the default value + */ + MapWithDefault.prototype.get = function(key) { + var hasValue = this.has(key); + + if (hasValue) { + return this._super$get(key); + } else { + var defaultValue = this.defaultValue(key); + this.set(key, defaultValue); + return defaultValue; + } + }; + + /** + @method copy + @return {Ember.MapWithDefault} + */ + MapWithDefault.prototype.copy = function() { + var Constructor = this.constructor; + return copyMap(this, new Constructor({ + defaultValue: this.defaultValue + })); + }; + + __exports__["default"] = Map; + + __exports__.OrderedSet = OrderedSet; + __exports__.Map = Map; + __exports__.MapWithDefault = MapWithDefault; + }); +define("ember-metal/merge", + ["ember-metal/keys","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var keys = __dependency1__["default"]; + + /** + Merge the contents of two objects together into the first object. + + ```javascript + Ember.merge({first: 'Tom'}, {last: 'Dale'}); // {first: 'Tom', last: 'Dale'} + var a = {first: 'Yehuda'}, b = {last: 'Katz'}; + Ember.merge(a, b); // a == {first: 'Yehuda', last: 'Katz'}, b == {last: 'Katz'} + ``` + + @method merge + @for Ember + @param {Object} original The object to merge into + @param {Object} updates The object to copy properties from + @return {Object} + */ + __exports__["default"] = function merge(original, updates) { + if (!updates || typeof updates !== 'object') { + return original; + } + + var props = keys(updates); + var prop; + var length = props.length; + + for (var i = 0; i < length; i++) { + prop = props[i]; + original[prop] = updates[prop]; + } + + return original; + } + }); +define("ember-metal/mixin", + ["ember-metal/core","ember-metal/merge","ember-metal/array","ember-metal/platform","ember-metal/utils","ember-metal/expand_properties","ember-metal/properties","ember-metal/computed","ember-metal/binding","ember-metal/observer","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-metal + */ + + var Ember = __dependency1__["default"]; + // warn, assert, wrap, et; + var merge = __dependency2__["default"]; + var map = __dependency3__.map; + var indexOf = __dependency3__.indexOf; + var forEach = __dependency3__.forEach; + var create = __dependency4__.create; + var guidFor = __dependency5__.guidFor; + var meta = __dependency5__.meta; + var wrap = __dependency5__.wrap; + var makeArray = __dependency5__.makeArray; + var apply = __dependency5__.apply; + var expandProperties = __dependency6__["default"]; + var Descriptor = __dependency7__.Descriptor; + var defineProperty = __dependency7__.defineProperty; + var ComputedProperty = __dependency8__.ComputedProperty; + var Binding = __dependency9__.Binding; + var addObserver = __dependency10__.addObserver; + var removeObserver = __dependency10__.removeObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeBeforeObserver = __dependency10__.removeBeforeObserver; + var addListener = __dependency11__.addListener; + var removeListener = __dependency11__.removeListener; + + var REQUIRED; + var a_map = map; + var a_indexOf = indexOf; + var a_forEach = forEach; + var a_slice = [].slice; + var o_create = create; + var metaFor = meta; + + function superFunction(){ + var func = this.__nextSuper; + var ret; + if (func) { + var args = new Array(arguments.length); + for (var i = 0, l = args.length; i < l; i++) { + args[i] = arguments[i]; + } + this.__nextSuper = null; + ret = apply(this, func, args); + this.__nextSuper = func; + } + return ret; + } + + function mixinsMeta(obj) { + var m = metaFor(obj, true); + var ret = m.mixins; + if (!ret) { + ret = m.mixins = {}; + } else if (!m.hasOwnProperty('mixins')) { + ret = m.mixins = o_create(ret); + } + return ret; + } + + function initMixin(mixin, args) { + if (args && args.length > 0) { + mixin.mixins = a_map.call(args, function(x) { + if (x instanceof Mixin) { return x; } + + // Note: Manually setup a primitive mixin here. This is the only + // way to actually get a primitive mixin. This way normal creation + // of mixins will give you combined mixins... + var mixin = new Mixin(); + mixin.properties = x; + return mixin; + }); + } + return mixin; + } + + function isMethod(obj) { + return 'function' === typeof obj && + obj.isMethod !== false && + obj !== Boolean && obj !== Object && obj !== Number && obj !== Array && obj !== Date && obj !== String; + } + + var CONTINUE = {}; + + function mixinProperties(mixinsMeta, mixin) { + var guid; + + if (mixin instanceof Mixin) { + guid = guidFor(mixin); + if (mixinsMeta[guid]) { return CONTINUE; } + mixinsMeta[guid] = mixin; + return mixin.properties; + } else { + return mixin; // apply anonymous mixin properties + } + } + + function concatenatedMixinProperties(concatProp, props, values, base) { + var concats; + + // reset before adding each new mixin to pickup concats from previous + concats = values[concatProp] || base[concatProp]; + if (props[concatProp]) { + concats = concats ? concats.concat(props[concatProp]) : props[concatProp]; + } + + return concats; + } + + function giveDescriptorSuper(meta, key, property, values, descs) { + var superProperty; + + // Computed properties override methods, and do not call super to them + if (values[key] === undefined) { + // Find the original descriptor in a parent mixin + superProperty = descs[key]; + } + + // If we didn't find the original descriptor in a parent mixin, find + // it on the original object. + superProperty = superProperty || meta.descs[key]; + + if (superProperty === undefined || !(superProperty instanceof ComputedProperty)) { + return property; + } + + // Since multiple mixins may inherit from the same parent, we need + // to clone the computed property so that other mixins do not receive + // the wrapped version. + property = o_create(property); + property.func = wrap(property.func, superProperty.func); + + return property; + } + + function giveMethodSuper(obj, key, method, values, descs) { + var superMethod; + + // Methods overwrite computed properties, and do not call super to them. + if (descs[key] === undefined) { + // Find the original method in a parent mixin + superMethod = values[key]; + } + + // If we didn't find the original value in a parent mixin, find it in + // the original object + superMethod = superMethod || obj[key]; + + // Only wrap the new method if the original method was a function + if (superMethod === undefined || 'function' !== typeof superMethod) { + return method; + } + + return wrap(method, superMethod); + } + + function applyConcatenatedProperties(obj, key, value, values) { + var baseValue = values[key] || obj[key]; + + if (baseValue) { + if ('function' === typeof baseValue.concat) { + return baseValue.concat(value); + } else { + return makeArray(baseValue).concat(value); + } + } else { + return makeArray(value); + } + } + + function applyMergedProperties(obj, key, value, values) { + var baseValue = values[key] || obj[key]; + + if (!baseValue) { return value; } + + var newBase = merge({}, baseValue); + var hasFunction = false; + + for (var prop in value) { + if (!value.hasOwnProperty(prop)) { continue; } + + var propValue = value[prop]; + if (isMethod(propValue)) { + // TODO: support for Computed Properties, etc? + hasFunction = true; + newBase[prop] = giveMethodSuper(obj, prop, propValue, baseValue, {}); + } else { + newBase[prop] = propValue; + } + } + + if (hasFunction) { + newBase._super = superFunction; + } + + return newBase; + } + + function addNormalizedProperty(base, key, value, meta, descs, values, concats, mergings) { + if (value instanceof Descriptor) { + if (value === REQUIRED && descs[key]) { return CONTINUE; } + + // Wrap descriptor function to implement + // __nextSuper() if needed + if (value.func) { + value = giveDescriptorSuper(meta, key, value, values, descs); + } + + descs[key] = value; + values[key] = undefined; + } else { + if ((concats && a_indexOf.call(concats, key) >= 0) || + key === 'concatenatedProperties' || + key === 'mergedProperties') { + value = applyConcatenatedProperties(base, key, value, values); + } else if ((mergings && a_indexOf.call(mergings, key) >= 0)) { + value = applyMergedProperties(base, key, value, values); + } else if (isMethod(value)) { + value = giveMethodSuper(base, key, value, values, descs); + } + + descs[key] = undefined; + values[key] = value; + } + } + + function mergeMixins(mixins, m, descs, values, base, keys) { + var mixin, props, key, concats, mergings, meta; + + function removeKeys(keyName) { + delete descs[keyName]; + delete values[keyName]; + } + + for(var i=0, l=mixins.length; i= 0) { + if (_detect(mixins[loc], targetMixin, seen)) { return true; } + } + return false; + } + + /** + @method detect + @param obj + @return {Boolean} + */ + MixinPrototype.detect = function(obj) { + if (!obj) { return false; } + if (obj instanceof Mixin) { return _detect(obj, this, {}); } + var m = obj['__ember_meta__']; + var mixins = m && m.mixins; + if (mixins) { + return !!mixins[guidFor(this)]; + } + return false; + }; + + MixinPrototype.without = function() { + var ret = new Mixin(this); + ret._without = a_slice.call(arguments); + return ret; + }; + + function _keys(ret, mixin, seen) { + if (seen[guidFor(mixin)]) { return; } + seen[guidFor(mixin)] = true; + + if (mixin.properties) { + var props = mixin.properties; + for (var key in props) { + if (props.hasOwnProperty(key)) { ret[key] = true; } + } + } else if (mixin.mixins) { + a_forEach.call(mixin.mixins, function(x) { _keys(ret, x, seen); }); + } + } + + MixinPrototype.keys = function() { + var keys = {}; + var seen = {}; + var ret = []; + _keys(keys, this, seen); + for(var key in keys) { + if (keys.hasOwnProperty(key)) { ret.push(key); } + } + return ret; + }; + + // returns the mixins currently applied to the specified object + // TODO: Make Ember.mixin + Mixin.mixins = function(obj) { + var m = obj['__ember_meta__']; + var mixins = m && m.mixins; + var ret = []; + + if (!mixins) { return ret; } + + for (var key in mixins) { + var mixin = mixins[key]; + + // skip primitive mixins since these are always anonymous + if (!mixin.properties) { ret.push(mixin); } + } + + return ret; + }; + + REQUIRED = new Descriptor(); + REQUIRED.toString = function() { return '(Required Property)'; }; + + /** + Denotes a required property for a mixin + + @method required + @for Ember + */ + function required() { + return REQUIRED; + } + + __exports__.required = required;function Alias(methodName) { + this.methodName = methodName; + } + + Alias.prototype = new Descriptor(); + + /** + Makes a method available via an additional name. + + ```javascript + App.Person = Ember.Object.extend({ + name: function() { + return 'Tomhuda Katzdale'; + }, + moniker: Ember.aliasMethod('name') + }); + + var goodGuy = App.Person.create(); + + goodGuy.name(); // 'Tomhuda Katzdale' + goodGuy.moniker(); // 'Tomhuda Katzdale' + ``` + + @method aliasMethod + @for Ember + @param {String} methodName name of the method to alias + @return {Ember.Descriptor} + */ + function aliasMethod(methodName) { + return new Alias(methodName); + } + + __exports__.aliasMethod = aliasMethod;// .......................................................... + // OBSERVER HELPER + // + + /** + Specify a method that observes property changes. + + ```javascript + Ember.Object.extend({ + valueObserver: Ember.observer('value', function() { + // Executes whenever the "value" property changes + }) + }); + ``` + + In the future this method may become asynchronous. If you want to ensure + synchronous behavior, use `immediateObserver`. + + Also available as `Function.prototype.observes` if prototype extensions are + enabled. + + @method observer + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function observer() { + var func = a_slice.call(arguments, -1)[0]; + var paths; + + var addWatchedProperty = function (path) { paths.push(path); }; + var _paths = a_slice.call(arguments, 0, -1); + + if (typeof func !== "function") { + // revert to old, soft-deprecated argument ordering + + func = arguments[0]; + _paths = a_slice.call(arguments, 1); + } + + paths = []; + + for (var i=0; i<_paths.length; ++i) { + expandProperties(_paths[i], addWatchedProperty); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.observer called without a function"); + } + + func.__ember_observes__ = paths; + return func; + } + + __exports__.observer = observer;/** + Specify a method that observes property changes. + + ```javascript + Ember.Object.extend({ + valueObserver: Ember.immediateObserver('value', function() { + // Executes whenever the "value" property changes + }) + }); + ``` + + In the future, `Ember.observer` may become asynchronous. In this event, + `Ember.immediateObserver` will maintain the synchronous behavior. + + Also available as `Function.prototype.observesImmediately` if prototype extensions are + enabled. + + @method immediateObserver + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function immediateObserver() { + for (var i=0, l=arguments.length; i this.changingFrom ? 'green' : 'red'; + // logic + } + }), + + friendsDidChange: Ember.observer('friends.@each.name', function(obj, keyName) { + // some logic + // obj.get(keyName) returns friends array + }) + }); + ``` + + Also available as `Function.prototype.observesBefore` if prototype extensions are + enabled. + + @method beforeObserver + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function beforeObserver() { + var func = a_slice.call(arguments, -1)[0]; + var paths; + + var addWatchedProperty = function(path) { paths.push(path); }; + + var _paths = a_slice.call(arguments, 0, -1); + + if (typeof func !== "function") { + // revert to old, soft-deprecated argument ordering + + func = arguments[0]; + _paths = a_slice.call(arguments, 1); + } + + paths = []; + + for (var i=0; i<_paths.length; ++i) { + expandProperties(_paths[i], addWatchedProperty); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.beforeObserver called without a function"); + } + + func.__ember_observesBefore__ = paths; + return func; + } + + __exports__.beforeObserver = beforeObserver;__exports__.IS_BINDING = IS_BINDING; + __exports__.Mixin = Mixin; + }); +define("ember-metal/observer", + ["ember-metal/watching","ember-metal/array","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var watch = __dependency1__.watch; + var unwatch = __dependency1__.unwatch; + var map = __dependency2__.map; + var listenersFor = __dependency3__.listenersFor; + var addListener = __dependency3__.addListener; + var removeListener = __dependency3__.removeListener; + var suspendListeners = __dependency3__.suspendListeners; + var suspendListener = __dependency3__.suspendListener; + /** + @module ember-metal + */ + + var AFTER_OBSERVERS = ':change'; + var BEFORE_OBSERVERS = ':before'; + + function changeEvent(keyName) { + return keyName + AFTER_OBSERVERS; + } + + function beforeEvent(keyName) { + return keyName + BEFORE_OBSERVERS; + } + + /** + @method addObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function addObserver(obj, _path, target, method) { + addListener(obj, changeEvent(_path), target, method); + watch(obj, _path); + + return this; + } + + __exports__.addObserver = addObserver;function observersFor(obj, path) { + return listenersFor(obj, changeEvent(path)); + } + + __exports__.observersFor = observersFor;/** + @method removeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function removeObserver(obj, _path, target, method) { + unwatch(obj, _path); + removeListener(obj, changeEvent(_path), target, method); + + return this; + } + + __exports__.removeObserver = removeObserver;/** + @method addBeforeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function addBeforeObserver(obj, _path, target, method) { + addListener(obj, beforeEvent(_path), target, method); + watch(obj, _path); + + return this; + } + + __exports__.addBeforeObserver = addBeforeObserver;// Suspend observer during callback. + // + // This should only be used by the target of the observer + // while it is setting the observed path. + function _suspendBeforeObserver(obj, path, target, method, callback) { + return suspendListener(obj, beforeEvent(path), target, method, callback); + } + + __exports__._suspendBeforeObserver = _suspendBeforeObserver;function _suspendObserver(obj, path, target, method, callback) { + return suspendListener(obj, changeEvent(path), target, method, callback); + } + + __exports__._suspendObserver = _suspendObserver;function _suspendBeforeObservers(obj, paths, target, method, callback) { + var events = map.call(paths, beforeEvent); + return suspendListeners(obj, events, target, method, callback); + } + + __exports__._suspendBeforeObservers = _suspendBeforeObservers;function _suspendObservers(obj, paths, target, method, callback) { + var events = map.call(paths, changeEvent); + return suspendListeners(obj, events, target, method, callback); + } + + __exports__._suspendObservers = _suspendObservers;function beforeObserversFor(obj, path) { + return listenersFor(obj, beforeEvent(path)); + } + + __exports__.beforeObserversFor = beforeObserversFor;/** + @method removeBeforeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function removeBeforeObserver(obj, _path, target, method) { + unwatch(obj, _path); + removeListener(obj, beforeEvent(_path), target, method); + + return this; + } + + __exports__.removeBeforeObserver = removeBeforeObserver; + }); +define("ember-metal/observer_set", + ["ember-metal/utils","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var guidFor = __dependency1__.guidFor; + var sendEvent = __dependency2__.sendEvent; + + /* + this.observerSet = { + [senderGuid]: { // variable name: `keySet` + [keyName]: listIndex + } + }, + this.observers = [ + { + sender: obj, + keyName: keyName, + eventName: eventName, + listeners: [ + [target, method, flags] + ] + }, + ... + ] + */ + __exports__["default"] = ObserverSet; + function ObserverSet() { + this.clear(); + } + + + ObserverSet.prototype.add = function(sender, keyName, eventName) { + var observerSet = this.observerSet; + var observers = this.observers; + var senderGuid = guidFor(sender); + var keySet = observerSet[senderGuid]; + var index; + + if (!keySet) { + observerSet[senderGuid] = keySet = {}; + } + index = keySet[keyName]; + if (index === undefined) { + index = observers.push({ + sender: sender, + keyName: keyName, + eventName: eventName, + listeners: [] + }) - 1; + keySet[keyName] = index; + } + return observers[index].listeners; + }; + + ObserverSet.prototype.flush = function() { + var observers = this.observers; + var i, len, observer, sender; + this.clear(); + for (i=0, len=observers.length; i < len; ++i) { + observer = observers[i]; + sender = observer.sender; + if (sender.isDestroying || sender.isDestroyed) { continue; } + sendEvent(sender, observer.eventName, [sender, observer.keyName], observer.listeners); + } + }; + + ObserverSet.prototype.clear = function() { + this.observerSet = {}; + this.observers = []; + }; + }); +define("ember-metal/path_cache", + ["ember-metal/cache","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Cache = __dependency1__["default"]; + + var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; + var IS_GLOBAL_PATH = /^([A-Z$]|([0-9][A-Z$])).*[\.]/; + var HAS_THIS = 'this.'; + + var isGlobalCache = new Cache(1000, function(key) { return IS_GLOBAL.test(key); }); + var isGlobalPathCache = new Cache(1000, function(key) { return IS_GLOBAL_PATH.test(key); }); + var hasThisCache = new Cache(1000, function(key) { return key.indexOf(HAS_THIS) !== -1; }); + var isPathCache = new Cache(1000, function(key) { return key.indexOf('.') !== -1; }); + + var caches = { + isGlobalCache: isGlobalCache, + isGlobalPathCache: isGlobalPathCache, + hasThisCache: hasThisCache, + isPathCache: isPathCache + }; + __exports__.caches = caches; + function isGlobal(path) { + return isGlobalCache.get(path); + } + + __exports__.isGlobal = isGlobal;function isGlobalPath(path) { + return isGlobalPathCache.get(path); + } + + __exports__.isGlobalPath = isGlobalPath;function hasThis(path) { + return hasThisCache.get(path); + } + + __exports__.hasThis = hasThis;function isPath(path) { + return isPathCache.get(path); + } + + __exports__.isPath = isPath; + }); +define("ember-metal/platform", + ["exports"], + function(__exports__) { + "use strict"; + /*globals Node */ + + /** + @module ember-metal + */ + var defineProperty = (function checkCompliance(defineProperty) { + if (!defineProperty) return; + try { + var a = 5; + var obj = {}; + defineProperty(obj, 'a', { + configurable: true, + enumerable: true, + get: function () { + return a; + }, + set: function (v) { + a = v; + } + }); + if (obj.a !== 5) return; + obj.a = 10; + if (a !== 10) return; + + // check non-enumerability + defineProperty(obj, 'a', { + configurable: true, + enumerable: false, + writable: true, + value: true + }); + for (var key in obj) { + if (key === 'a') return; + } + + // Detects a bug in Android <3.2 where you cannot redefine a property using + // Object.defineProperty once accessors have already been set. + if (obj.a !== true) return; + + // defineProperty is compliant + return defineProperty; + } catch (e) { + // IE8 defines Object.defineProperty but calling it on an Object throws + return; + } + })(Object.defineProperty); + + var hasES5CompliantDefineProperty = !!defineProperty; + + if (hasES5CompliantDefineProperty && typeof document !== 'undefined') { + // This is for Safari 5.0, which supports Object.defineProperty, but not + // on DOM nodes. + var canDefinePropertyOnDOM = (function() { + try { + defineProperty(document.createElement('div'), 'definePropertyOnDOM', {}); + return true; + } catch(e) { } + + return false; + })(); + + if (!canDefinePropertyOnDOM) { + defineProperty = function(obj, keyName, desc) { + var isNode; + + if (typeof Node === "object") { + isNode = obj instanceof Node; + } else { + isNode = typeof obj === "object" && typeof obj.nodeType === "number" && typeof obj.nodeName === "string"; + } + + if (isNode) { + // TODO: Should we have a warning here? + return (obj[keyName] = desc.value); + } else { + return Object.defineProperty(obj, keyName, desc); + } + }; + } + } + + if (!hasES5CompliantDefineProperty) { + defineProperty = function defineProperty(obj, keyName, desc) { + if (!desc.get) { obj[keyName] = desc.value; } + }; + } + + // ES5 15.2.3.7 + // http://es5.github.com/#x15.2.3.7 + if (!Object.defineProperties) { + Object.defineProperties = function defineProperties(object, properties) { + for (var property in properties) { + if (properties.hasOwnProperty(property) && property !== "__proto__") { + defineProperty(object, property, properties[property]); + } + } + return object; + }; + } + + /** + Identical to `Object.create()`. Implements if not available natively. + + @method create + @for Ember + */ + var create; + // ES5 15.2.3.5 + // http://es5.github.com/#x15.2.3.5 + if (!(Object.create && !Object.create(null).hasOwnProperty)) { + /* jshint scripturl:true, proto:true */ + // Contributed by Brandon Benvie, October, 2012 + var createEmpty; + var supportsProto = !({'__proto__':null} instanceof Object); + // the following produces false positives + // in Opera Mini => not a reliable check + // Object.prototype.__proto__ === null + if (supportsProto || typeof document === 'undefined') { + createEmpty = function () { + return { "__proto__": null }; + }; + } else { + // In old IE __proto__ can't be used to manually set `null`, nor does + // any other method exist to make an object that inherits from nothing, + // aside from Object.prototype itself. Instead, create a new global + // object and *steal* its Object.prototype and strip it bare. This is + // used as the prototype to create nullary objects. + createEmpty = function () { + var iframe = document.createElement('iframe'); + var parent = document.body || document.documentElement; + iframe.style.display = 'none'; + parent.appendChild(iframe); + iframe.src = 'javascript:'; + var empty = iframe.contentWindow.Object.prototype; + parent.removeChild(iframe); + iframe = null; + delete empty.constructor; + delete empty.hasOwnProperty; + delete empty.propertyIsEnumerable; + delete empty.isPrototypeOf; + delete empty.toLocaleString; + delete empty.toString; + delete empty.valueOf; + + function Empty() {} + Empty.prototype = empty; + // short-circuit future calls + createEmpty = function () { + return new Empty(); + }; + return new Empty(); + }; + } + + create = Object.create = function create(prototype, properties) { + + var object; + function Type() {} // An empty constructor. + + if (prototype === null) { + object = createEmpty(); + } else { + if (typeof prototype !== "object" && typeof prototype !== "function") { + // In the native implementation `parent` can be `null` + // OR *any* `instanceof Object` (Object|Function|Array|RegExp|etc) + // Use `typeof` tho, b/c in old IE, DOM elements are not `instanceof Object` + // like they are in modern browsers. Using `Object.create` on DOM elements + // is...err...probably inappropriate, but the native version allows for it. + throw new TypeError("Object prototype may only be an Object or null"); // same msg as Chrome + } + + Type.prototype = prototype; + + object = new Type(); + } + + if (properties !== undefined) { + Object.defineProperties(object, properties); + } + + return object; + }; + } else { + create = Object.create; + } + + var hasPropertyAccessors = hasES5CompliantDefineProperty; + var canDefineNonEnumerableProperties = hasES5CompliantDefineProperty; + + /** + @class platform + @namespace Ember + */ + + /** + Platform specific methods and feature detectors needed by the framework. + + @class platform + @namespace Ember + @static + */ + // TODO remove this + var platform = {}; + + /** + Identical to `Object.defineProperty()`. Implements as much functionality + as possible if not available natively. + + @method defineProperty + @param {Object} obj The object to modify + @param {String} keyName property name to modify + @param {Object} desc descriptor hash + @return {void} + */ + platform.defineProperty = defineProperty; + + /** + Set to true if the platform supports native getters and setters. + + @property hasPropertyAccessors + @final + */ + platform.hasPropertyAccessors = hasPropertyAccessors; + + __exports__.create = create; + __exports__.defineProperty = defineProperty; + __exports__.hasPropertyAccessors = hasPropertyAccessors; + __exports__.canDefineNonEnumerableProperties = canDefineNonEnumerableProperties; + __exports__.platform = platform; + }); +define("ember-metal/properties", + ["ember-metal/core","ember-metal/utils","ember-metal/platform","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var Ember = __dependency1__["default"]; + var metaFor = __dependency2__.meta; + var objectDefineProperty = __dependency3__.defineProperty; + var hasPropertyAccessors = __dependency3__.hasPropertyAccessors; + var overrideChains = __dependency4__.overrideChains; + // .......................................................... + // DESCRIPTOR + // + + /** + Objects of this type can implement an interface to respond to requests to + get and set. The default implementation handles simple properties. + + You generally won't need to create or subclass this directly. + + @class Descriptor + @namespace Ember + @private + @constructor + */ + function Descriptor() {} + + __exports__.Descriptor = Descriptor;// .......................................................... + // DEFINING PROPERTIES API + // + + function MANDATORY_SETTER_FUNCTION(value) { + Ember.assert("You must use Ember.set() to access this property (of " + this + ")", false); + } + + __exports__.MANDATORY_SETTER_FUNCTION = MANDATORY_SETTER_FUNCTION;function DEFAULT_GETTER_FUNCTION(name) { + return function GETTER_FUNCTION() { + var meta = this['__ember_meta__']; + return meta && meta.values[name]; + }; + } + + __exports__.DEFAULT_GETTER_FUNCTION = DEFAULT_GETTER_FUNCTION;/** + NOTE: This is a low-level method used by other parts of the API. You almost + never want to call this method directly. Instead you should use + `Ember.mixin()` to define new properties. + + Defines a property on an object. This method works much like the ES5 + `Object.defineProperty()` method except that it can also accept computed + properties and other special descriptors. + + Normally this method takes only three parameters. However if you pass an + instance of `Ember.Descriptor` as the third param then you can pass an + optional value as the fourth parameter. This is often more efficient than + creating new descriptor hashes for each property. + + ## Examples + + ```javascript + // ES5 compatible mode + Ember.defineProperty(contact, 'firstName', { + writable: true, + configurable: false, + enumerable: true, + value: 'Charles' + }); + + // define a simple property + Ember.defineProperty(contact, 'lastName', undefined, 'Jolley'); + + // define a computed property + Ember.defineProperty(contact, 'fullName', Ember.computed(function() { + return this.firstName+' '+this.lastName; + }).property('firstName', 'lastName')); + ``` + + @private + @method defineProperty + @for Ember + @param {Object} obj the object to define this property on. This may be a prototype. + @param {String} keyName the name of the property + @param {Ember.Descriptor} [desc] an instance of `Ember.Descriptor` (typically a + computed property) or an ES5 descriptor. + You must provide this or `data` but not both. + @param {*} [data] something other than a descriptor, that will + become the explicit value of this property. + */ + function defineProperty(obj, keyName, desc, data, meta) { + var descs, existingDesc, watching, value; + + if (!meta) meta = metaFor(obj); + descs = meta.descs; + existingDesc = meta.descs[keyName]; + var watchEntry = meta.watching[keyName]; + + watching = watchEntry !== undefined && watchEntry > 0; + + if (existingDesc instanceof Descriptor) { + existingDesc.teardown(obj, keyName); + } + + if (desc instanceof Descriptor) { + value = desc; + + descs[keyName] = desc; + + if (watching && hasPropertyAccessors) { + objectDefineProperty(obj, keyName, { + configurable: true, + enumerable: true, + writable: true, + value: undefined // make enumerable + }); + } else { + obj[keyName] = undefined; // make enumerable + } + if (desc.setup) { desc.setup(obj, keyName); } + } else { + descs[keyName] = undefined; // shadow descriptor in proto + if (desc == null) { + value = data; + + + if (watching && hasPropertyAccessors) { + meta.values[keyName] = data; + objectDefineProperty(obj, keyName, { + configurable: true, + enumerable: true, + set: MANDATORY_SETTER_FUNCTION, + get: DEFAULT_GETTER_FUNCTION(keyName) + }); + } else { + obj[keyName] = data; + } + } else { + value = desc; + + // compatibility with ES5 + objectDefineProperty(obj, keyName, desc); + } + } + + // if key is being watched, override chains that + // were initialized with the prototype + if (watching) { overrideChains(obj, keyName, meta); } + + // The `value` passed to the `didDefineProperty` hook is + // either the descriptor or data, whichever was passed. + if (obj.didDefineProperty) { obj.didDefineProperty(obj, keyName, value); } + + return this; + } + __exports__.defineProperty = defineProperty; + }); +define("ember-metal/property_events", + ["ember-metal/utils","ember-metal/events","ember-metal/observer_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var guidFor = __dependency1__.guidFor; + var tryFinally = __dependency1__.tryFinally; + var sendEvent = __dependency2__.sendEvent; + var listenersUnion = __dependency2__.listenersUnion; + var listenersDiff = __dependency2__.listenersDiff; + var ObserverSet = __dependency3__["default"]; + + var beforeObserverSet = new ObserverSet(); + var observerSet = new ObserverSet(); + var deferred = 0; + + // .......................................................... + // PROPERTY CHANGES + // + + /** + This function is called just before an object property is about to change. + It will notify any before observers and prepare caches among other things. + + Normally you will not need to call this method directly but if for some + reason you can't directly watch a property you can invoke this method + manually along with `Ember.propertyDidChange()` which you should call just + after the property value changes. + + @method propertyWillChange + @for Ember + @param {Object} obj The object with the property that will change + @param {String} keyName The property key (or path) that will change. + @return {void} + */ + function propertyWillChange(obj, keyName) { + var m = obj['__ember_meta__']; + var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; + var proto = m && m.proto; + var desc = m && m.descs[keyName]; + + if (!watching) { return; } + if (proto === obj) { return; } + if (desc && desc.willChange) { desc.willChange(obj, keyName); } + dependentKeysWillChange(obj, keyName, m); + chainsWillChange(obj, keyName, m); + notifyBeforeObservers(obj, keyName); + } + + /** + This function is called just after an object property has changed. + It will notify any observers and clear caches among other things. + + Normally you will not need to call this method directly but if for some + reason you can't directly watch a property you can invoke this method + manually along with `Ember.propertyWillChange()` which you should call just + before the property value changes. + + @method propertyDidChange + @for Ember + @param {Object} obj The object with the property that will change + @param {String} keyName The property key (or path) that will change. + @return {void} + */ + function propertyDidChange(obj, keyName) { + var m = obj['__ember_meta__']; + var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; + var proto = m && m.proto; + var desc = m && m.descs[keyName]; + + if (proto === obj) { return; } + + // shouldn't this mean that we're watching this key? + if (desc && desc.didChange) { desc.didChange(obj, keyName); } + if (!watching && keyName !== 'length') { return; } + + if (m && m.deps && m.deps[keyName]) { + dependentKeysDidChange(obj, keyName, m); + } + + chainsDidChange(obj, keyName, m, false); + notifyObservers(obj, keyName); + } + + var WILL_SEEN, DID_SEEN; + // called whenever a property is about to change to clear the cache of any dependent keys (and notify those properties of changes, etc...) + function dependentKeysWillChange(obj, depKey, meta) { + if (obj.isDestroying) { return; } + + var deps; + if (meta && meta.deps && (deps = meta.deps[depKey])) { + var seen = WILL_SEEN; + var top = !seen; + if (top) { seen = WILL_SEEN = {}; } + iterDeps(propertyWillChange, obj, deps, depKey, seen, meta); + if (top) { WILL_SEEN = null; } + } + } + + // called whenever a property has just changed to update dependent keys + function dependentKeysDidChange(obj, depKey, meta) { + if (obj.isDestroying) { return; } + + var deps; + if (meta && meta.deps && (deps = meta.deps[depKey])) { + var seen = DID_SEEN; + var top = !seen; + if (top) { seen = DID_SEEN = {}; } + iterDeps(propertyDidChange, obj, deps, depKey, seen, meta); + if (top) { DID_SEEN = null; } + } + } + + function keysOf(obj) { + var keys = []; + for (var key in obj) keys.push(key); + return keys; + } + + function iterDeps(method, obj, deps, depKey, seen, meta) { + var keys, key, i, desc; + var guid = guidFor(obj); + var current = seen[guid]; + if (!current) current = seen[guid] = {}; + if (current[depKey]) return; + current[depKey] = true; + + if (deps) { + keys = keysOf(deps); + var descs = meta.descs; + for (i=0; i 0) { + ret = meta.values[keyName]; + } else { + ret = obj[keyName]; + } + + if (ret === undefined && + 'object' === typeof obj && !(keyName in obj) && 'function' === typeof obj.unknownProperty) { + return obj.unknownProperty(keyName); + } + + return ret; + } + }; + + // Currently used only by Ember Data tests + if (Ember.config.overrideAccessors) { + Ember.get = get; + Ember.config.overrideAccessors(); + get = Ember.get; + } + + /** + Normalizes a target/path pair to reflect that actual target/path that should + be observed, etc. This takes into account passing in global property + paths (i.e. a path beginning with a captial letter not defined on the + target). + + @private + @method normalizeTuple + @for Ember + @param {Object} target The current target. May be `null`. + @param {String} path A path on the target or a global property path. + @return {Array} a temporary array with the normalized target/path pair. + */ + function normalizeTuple(target, path) { + var hasThis = pathHasThis(path); + var isGlobal = !hasThis && isGlobalPath(path); + var key; + + if (!target || isGlobal) target = Ember.lookup; + if (hasThis) path = path.slice(5); + + Ember.deprecate( + "normalizeTuple will return '"+path+"' as a non-global. This behavior will change in the future (issue #3852)", + target === Ember.lookup || !target || hasThis || isGlobal || !isGlobalPath(path+'.') + ); + + if (target === Ember.lookup) { + key = path.match(FIRST_KEY)[0]; + target = get(target, key); + path = path.slice(key.length+1); + } + + // must return some kind of path to be valid else other things will break. + if (!path || path.length===0) throw new EmberError('Path cannot be empty'); + + return [ target, path ]; + } + + function _getPath(root, path) { + var hasThis, parts, tuple, idx, len; + + // If there is no root and path is a key name, return that + // property from the global object. + // E.g. get('Ember') -> Ember + if (root === null && !isPath(path)) { + return get(Ember.lookup, path); + } + + // detect complicated paths and normalize them + hasThis = pathHasThis(path); + + if (!root || hasThis) { + tuple = normalizeTuple(root, path); + root = tuple[0]; + path = tuple[1]; + tuple.length = 0; + } + + parts = path.split("."); + len = parts.length; + for (idx = 0; root != null && idx < len; idx++) { + root = get(root, parts[idx], true); + if (root && root.isDestroyed) { return undefined; } + } + return root; + } + + function getWithDefault(root, key, defaultValue) { + var value = get(root, key); + + if (value === undefined) { return defaultValue; } + return value; + } + + __exports__.getWithDefault = getWithDefault;__exports__["default"] = get; + __exports__.get = get; + __exports__.normalizeTuple = normalizeTuple; + __exports__._getPath = _getPath; + }); +define("ember-metal/property_set", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_events","ember-metal/properties","ember-metal/error","ember-metal/path_cache","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var getPath = __dependency2__._getPath; + var propertyWillChange = __dependency3__.propertyWillChange; + var propertyDidChange = __dependency3__.propertyDidChange; + var defineProperty = __dependency4__.defineProperty; + var EmberError = __dependency5__["default"]; + var isPath = __dependency6__.isPath; + var hasPropertyAccessors = __dependency7__.hasPropertyAccessors; + + var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; + + /** + Sets the value of a property on an object, respecting computed properties + and notifying observers and other listeners of the change. If the + property is not defined but the object implements the `setUnknownProperty` + method then that will be invoked as well. + + @method set + @for Ember + @param {Object} obj The object to modify. + @param {String} keyName The property key to set + @param {Object} value The value to set + @return {Object} the passed value. + */ + var set = function set(obj, keyName, value, tolerant) { + if (typeof obj === 'string') { + Ember.assert("Path '" + obj + "' must be global if no obj is given.", IS_GLOBAL.test(obj)); + value = keyName; + keyName = obj; + obj = null; + } + + Ember.assert("Cannot call set with "+ keyName +" key.", !!keyName); + + if (!obj) { + return setPath(obj, keyName, value, tolerant); + } + + var meta = obj['__ember_meta__']; + var desc = meta && meta.descs[keyName]; + var isUnknown, currentValue; + + if (desc === undefined && isPath(keyName)) { + return setPath(obj, keyName, value, tolerant); + } + + Ember.assert("You need to provide an object and key to `set`.", !!obj && keyName !== undefined); + Ember.assert('calling set on destroyed object', !obj.isDestroyed); + + if (desc !== undefined) { + desc.set(obj, keyName, value); + } else { + + if (typeof obj === 'object' && obj !== null && value !== undefined && obj[keyName] === value) { + return value; + } + + isUnknown = 'object' === typeof obj && !(keyName in obj); + + // setUnknownProperty is called if `obj` is an object, + // the property does not already exist, and the + // `setUnknownProperty` method exists on the object + if (isUnknown && 'function' === typeof obj.setUnknownProperty) { + obj.setUnknownProperty(keyName, value); + } else if (meta && meta.watching[keyName] > 0) { + + if (hasPropertyAccessors) { + currentValue = meta.values[keyName]; + } else { + currentValue = obj[keyName]; + } + // only trigger a change if the value has changed + if (value !== currentValue) { + propertyWillChange(obj, keyName); + + if (hasPropertyAccessors) { + if ((currentValue === undefined && !(keyName in obj)) || !obj.propertyIsEnumerable(keyName)) { + defineProperty(obj, keyName, null, value); // setup mandatory setter + } else { + meta.values[keyName] = value; + } + } else { + obj[keyName] = value; + } + propertyDidChange(obj, keyName); + } + } else { + obj[keyName] = value; + } + } + return value; + }; + + // Currently used only by Ember Data tests + // ES6TODO: Verify still true + if (Ember.config.overrideAccessors) { + Ember.set = set; + Ember.config.overrideAccessors(); + set = Ember.set; + } + + function setPath(root, path, value, tolerant) { + var keyName; + + // get the last part of the path + keyName = path.slice(path.lastIndexOf('.') + 1); + + // get the first part of the part + path = (path === keyName) ? keyName : path.slice(0, path.length-(keyName.length+1)); + + // unless the path is this, look up the first part to + // get the root + if (path !== 'this') { + root = getPath(root, path); + } + + if (!keyName || keyName.length === 0) { + throw new EmberError('Property set failed: You passed an empty path'); + } + + if (!root) { + if (tolerant) { return; } + else { throw new EmberError('Property set failed: object in path "'+path+'" could not be found or was destroyed.'); } + } + + return set(root, keyName, value); + } + + /** + Error-tolerant form of `Ember.set`. Will not blow up if any part of the + chain is `undefined`, `null`, or destroyed. + + This is primarily used when syncing bindings, which may try to update after + an object has been destroyed. + + @method trySet + @for Ember + @param {Object} obj The object to modify. + @param {String} path The property path to set + @param {Object} value The value to set + */ + function trySet(root, path, value) { + return set(root, path, value, true); + } + + __exports__.trySet = trySet;__exports__.set = set; + }); +define("ember-metal/run_loop", + ["ember-metal/core","ember-metal/utils","ember-metal/array","ember-metal/property_events","backburner","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var apply = __dependency2__.apply; + var GUID_KEY = __dependency2__.GUID_KEY; + var indexOf = __dependency3__.indexOf; + var beginPropertyChanges = __dependency4__.beginPropertyChanges; + var endPropertyChanges = __dependency4__.endPropertyChanges; + var Backburner = __dependency5__["default"]; + + function onBegin(current) { + run.currentRunLoop = current; + } + + function onEnd(current, next) { + run.currentRunLoop = next; + } + + // ES6TODO: should Backburner become es6? + var backburner = new Backburner(['sync', 'actions', 'destroy'], { + GUID_KEY: GUID_KEY, + sync: { + before: beginPropertyChanges, + after: endPropertyChanges + }, + defaultQueue: 'actions', + onBegin: onBegin, + onEnd: onEnd, + onErrorTarget: Ember, + onErrorMethod: 'onerror' + }); + var slice = [].slice; + var concat = [].concat; + + // .......................................................... + // run - this is ideally the only public API the dev sees + // + + /** + Runs the passed target and method inside of a RunLoop, ensuring any + deferred actions including bindings and views updates are flushed at the + end. + + Normally you should not need to invoke this method yourself. However if + you are implementing raw event handlers when interfacing with other + libraries or plugins, you should probably wrap all of your code inside this + call. + + ```javascript + run(function() { + // code to be execute within a RunLoop + }); + ``` + + @class run + @namespace Ember + @static + @constructor + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} return value from invoking the passed function. + */ + __exports__["default"] = run; + function run() { + return apply(backburner, backburner.run, arguments); + } + + /** + If no run-loop is present, it creates a new one. If a run loop is + present it will queue itself to run on the existing run-loops action + queue. + + Please note: This is not for normal usage, and should be used sparingly. + + If invoked when not within a run loop: + + ```javascript + run.join(function() { + // creates a new run-loop + }); + ``` + + Alternatively, if called within an existing run loop: + + ```javascript + run(function() { + // creates a new run-loop + run.join(function() { + // joins with the existing run-loop, and queues for invocation on + // the existing run-loops action queue. + }); + }); + ``` + + @method join + @namespace Ember + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} Return value from invoking the passed function. Please note, + when called within an existing loop, no return value is possible. + */ + run.join = function(target, method /* args */) { + if (!run.currentRunLoop) { + return apply(Ember, run, arguments); + } + + var args = slice.call(arguments); + args.unshift('actions'); + apply(run, run.schedule, args); + }; + + /** + Provides a useful utility for when integrating with non-Ember libraries + that provide asynchronous callbacks. + + Ember utilizes a run-loop to batch and coalesce changes. This works by + marking the start and end of Ember-related Javascript execution. + + When using events such as a View's click handler, Ember wraps the event + handler in a run-loop, but when integrating with non-Ember libraries this + can be tedious. + + For example, the following is rather verbose but is the correct way to combine + third-party events and Ember code. + + ```javascript + var that = this; + jQuery(window).on('resize', function(){ + run(function(){ + that.handleResize(); + }); + }); + ``` + + To reduce the boilerplate, the following can be used to construct a + run-loop-wrapped callback handler. + + ```javascript + jQuery(window).on('resize', run.bind(this, this.handleResize)); + ``` + + @method bind + @namespace Ember + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} return value from invoking the passed function. Please note, + when called within an existing loop, no return value is possible. + @since 1.4.0 + */ + run.bind = function(target, method /* args*/) { + var args = slice.call(arguments); + return function() { + return apply(run, run.join, args.concat(slice.call(arguments))); + }; + }; + + run.backburner = backburner; + run.currentRunLoop = null; + run.queues = backburner.queueNames; + + /** + Begins a new RunLoop. Any deferred actions invoked after the begin will + be buffered until you invoke a matching call to `run.end()`. This is + a lower-level way to use a RunLoop instead of using `run()`. + + ```javascript + run.begin(); + // code to be execute within a RunLoop + run.end(); + ``` + + @method begin + @return {void} + */ + run.begin = function() { + backburner.begin(); + }; + + /** + Ends a RunLoop. This must be called sometime after you call + `run.begin()` to flush any deferred actions. This is a lower-level way + to use a RunLoop instead of using `run()`. + + ```javascript + run.begin(); + // code to be execute within a RunLoop + run.end(); + ``` + + @method end + @return {void} + */ + run.end = function() { + backburner.end(); + }; + + /** + Array of named queues. This array determines the order in which queues + are flushed at the end of the RunLoop. You can define your own queues by + simply adding the queue name to this array. Normally you should not need + to inspect or modify this property. + + @property queues + @type Array + @default ['sync', 'actions', 'destroy'] + */ + + /** + Adds the passed target/method and any optional arguments to the named + queue to be executed at the end of the RunLoop. If you have not already + started a RunLoop when calling this method one will be started for you + automatically. + + At the end of a RunLoop, any methods scheduled in this way will be invoked. + Methods will be invoked in an order matching the named queues defined in + the `run.queues` property. + + ```javascript + run.schedule('sync', this, function() { + // this will be executed in the first RunLoop queue, when bindings are synced + console.log("scheduled on sync queue"); + }); + + run.schedule('actions', this, function() { + // this will be executed in the 'actions' queue, after bindings have synced. + console.log("scheduled on actions queue"); + }); + + // Note the functions will be run in order based on the run queues order. + // Output would be: + // scheduled on sync queue + // scheduled on actions queue + ``` + + @method schedule + @param {String} queue The name of the queue to schedule against. + Default queues are 'sync' and 'actions' + @param {Object} [target] target object to use as the context when invoking a method. + @param {String|Function} method The method to invoke. If you pass a string it + will be resolved on the target object at the time the scheduled item is + invoked allowing you to change the target function. + @param {Object} [arguments*] Optional arguments to be passed to the queued method. + @return {void} + */ + run.schedule = function(queue, target, method) { + checkAutoRun(); + apply(backburner, backburner.schedule, arguments); + }; + + // Used by global test teardown + run.hasScheduledTimers = function() { + return backburner.hasTimers(); + }; + + // Used by global test teardown + run.cancelTimers = function () { + backburner.cancelTimers(); + }; + + /** + Immediately flushes any events scheduled in the 'sync' queue. Bindings + use this queue so this method is a useful way to immediately force all + bindings in the application to sync. + + You should call this method anytime you need any changed state to propagate + throughout the app immediately without repainting the UI (which happens + in the later 'render' queue added by the `ember-views` package). + + ```javascript + run.sync(); + ``` + + @method sync + @return {void} + */ + run.sync = function() { + if (backburner.currentInstance) { + backburner.currentInstance.queues.sync.flush(); + } + }; + + /** + Invokes the passed target/method and optional arguments after a specified + period of time. The last parameter of this method must always be a number + of milliseconds. + + You should use this method whenever you need to run some action after a + period of time instead of using `setTimeout()`. This method will ensure that + items that expire during the same script execution cycle all execute + together, which is often more efficient than using a real setTimeout. + + ```javascript + run.later(myContext, function() { + // code here will execute within a RunLoop in about 500ms with this == myContext + }, 500); + ``` + + @method later + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} wait Number of milliseconds to wait. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.later = function(target, method) { + return apply(backburner, backburner.later, arguments); + }; + + /** + Schedule a function to run one time during the current RunLoop. This is equivalent + to calling `scheduleOnce` with the "actions" queue. + + @method once + @param {Object} [target] The target of the method to invoke. + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.once = function(target, method) { + checkAutoRun(); + var args = slice.call(arguments); + args.unshift('actions'); + return apply(backburner, backburner.scheduleOnce, args); + }; + + /** + Schedules a function to run one time in a given queue of the current RunLoop. + Calling this method with the same queue/target/method combination will have + no effect (past the initial call). + + Note that although you can pass optional arguments these will not be + considered when looking for duplicates. New arguments will replace previous + calls. + + ```javascript + run(function() { + var sayHi = function() { console.log('hi'); } + run.scheduleOnce('afterRender', myContext, sayHi); + run.scheduleOnce('afterRender', myContext, sayHi); + // sayHi will only be executed once, in the afterRender queue of the RunLoop + }); + ``` + + Also note that passing an anonymous function to `run.scheduleOnce` will + not prevent additional calls with an identical anonymous function from + scheduling the items multiple times, e.g.: + + ```javascript + function scheduleIt() { + run.scheduleOnce('actions', myContext, function() { console.log("Closure"); }); + } + scheduleIt(); + scheduleIt(); + // "Closure" will print twice, even though we're using `run.scheduleOnce`, + // because the function we pass to it is anonymous and won't match the + // previously scheduled operation. + ``` + + Available queues, and their order, can be found at `run.queues` + + @method scheduleOnce + @param {String} [queue] The name of the queue to schedule against. Default queues are 'sync' and 'actions'. + @param {Object} [target] The target of the method to invoke. + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.scheduleOnce = function(queue, target, method) { + checkAutoRun(); + return apply(backburner, backburner.scheduleOnce, arguments); + }; + + /** + Schedules an item to run from within a separate run loop, after + control has been returned to the system. This is equivalent to calling + `run.later` with a wait time of 1ms. + + ```javascript + run.next(myContext, function() { + // code to be executed in the next run loop, + // which will be scheduled after the current one + }); + ``` + + Multiple operations scheduled with `run.next` will coalesce + into the same later run loop, along with any other operations + scheduled by `run.later` that expire right around the same + time that `run.next` operations will fire. + + Note that there are often alternatives to using `run.next`. + For instance, if you'd like to schedule an operation to happen + after all DOM element operations have completed within the current + run loop, you can make use of the `afterRender` run loop queue (added + by the `ember-views` package, along with the preceding `render` queue + where all the DOM element operations happen). Example: + + ```javascript + App.MyCollectionView = Ember.CollectionView.extend({ + didInsertElement: function() { + run.scheduleOnce('afterRender', this, 'processChildElements'); + }, + processChildElements: function() { + // ... do something with collectionView's child view + // elements after they've finished rendering, which + // can't be done within the CollectionView's + // `didInsertElement` hook because that gets run + // before the child elements have been added to the DOM. + } + }); + ``` + + One benefit of the above approach compared to using `run.next` is + that you will be able to perform DOM/CSS operations before unprocessed + elements are rendered to the screen, which may prevent flickering or + other artifacts caused by delaying processing until after rendering. + + The other major benefit to the above approach is that `run.next` + introduces an element of non-determinism, which can make things much + harder to test, due to its reliance on `setTimeout`; it's much harder + to guarantee the order of scheduled operations when they are scheduled + outside of the current run loop, i.e. with `run.next`. + + @method next + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.next = function() { + var args = slice.call(arguments); + args.push(1); + return apply(backburner, backburner.later, args); + }; + + /** + Cancels a scheduled item. Must be a value returned by `run.later()`, + `run.once()`, `run.next()`, `run.debounce()`, or + `run.throttle()`. + + ```javascript + var runNext = run.next(myContext, function() { + // will not be executed + }); + run.cancel(runNext); + + var runLater = run.later(myContext, function() { + // will not be executed + }, 500); + run.cancel(runLater); + + var runOnce = run.once(myContext, function() { + // will not be executed + }); + run.cancel(runOnce); + + var throttle = run.throttle(myContext, function() { + // will not be executed + }, 1, false); + run.cancel(throttle); + + var debounce = run.debounce(myContext, function() { + // will not be executed + }, 1); + run.cancel(debounce); + + var debounceImmediate = run.debounce(myContext, function() { + // will be executed since we passed in true (immediate) + }, 100, true); + // the 100ms delay until this method can be called again will be cancelled + run.cancel(debounceImmediate); + ``` + + @method cancel + @param {Object} timer Timer object to cancel + @return {Boolean} true if cancelled or false/undefined if it wasn't found + */ + run.cancel = function(timer) { + return backburner.cancel(timer); + }; + + /** + Delay calling the target method until the debounce period has elapsed + with no additional debounce calls. If `debounce` is called again before + the specified time has elapsed, the timer is reset and the entire period + must pass again before the target method is called. + + This method should be used when an event may be called multiple times + but the action should only be called once when the event is done firing. + A common example is for scroll events where you only want updates to + happen once scrolling has ceased. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'debounce'}; + + run.debounce(myContext, myFunc, 150); + + // less than 150ms passes + + run.debounce(myContext, myFunc, 150); + + // 150ms passes + // myFunc is invoked with context myContext + // console logs 'debounce ran.' one time. + ``` + + Immediate allows you to run the function immediately, but debounce + other calls for this function until the wait time has elapsed. If + `debounce` is called again before the specified time has elapsed, + the timer is reset and the entire period must pass again before + the method can be called again. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'debounce'}; + + run.debounce(myContext, myFunc, 150, true); + + // console logs 'debounce ran.' one time immediately. + // 100ms passes + + run.debounce(myContext, myFunc, 150, true); + + // 150ms passes and nothing else is logged to the console and + // the debouncee is no longer being watched + + run.debounce(myContext, myFunc, 150, true); + + // console logs 'debounce ran.' one time immediately. + // 150ms passes and nothing else is logged to the console and + // the debouncee is no longer being watched + + ``` + + @method debounce + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} wait Number of milliseconds to wait. + @param {Boolean} immediate Trigger the function on the leading instead + of the trailing edge of the wait interval. Defaults to false. + @return {Array} Timer information for use in cancelling, see `run.cancel`. + */ + run.debounce = function() { + return apply(backburner, backburner.debounce, arguments); + }; + + /** + Ensure that the target method is never called more frequently than + the specified spacing period. The target method is called immediately. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'throttle'}; + + run.throttle(myContext, myFunc, 150); + // myFunc is invoked with context myContext + // console logs 'throttle ran.' + + // 50ms passes + run.throttle(myContext, myFunc, 150); + + // 50ms passes + run.throttle(myContext, myFunc, 150); + + // 150ms passes + run.throttle(myContext, myFunc, 150); + // myFunc is invoked with context myContext + // console logs 'throttle ran.' + ``` + + @method throttle + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} spacing Number of milliseconds to space out requests. + @param {Boolean} immediate Trigger the function on the leading instead + of the trailing edge of the wait interval. Defaults to true. + @return {Array} Timer information for use in cancelling, see `run.cancel`. + */ + run.throttle = function() { + return apply(backburner, backburner.throttle, arguments); + }; + + // Make sure it's not an autorun during testing + function checkAutoRun() { + if (!run.currentRunLoop) { + Ember.assert("You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in an run", !Ember.testing); + } + } + + /** + Add a new named queue after the specified queue. + + The queue to add will only be added once. + + @method _addQueue + @param {String} name the name of the queue to add. + @param {String} after the name of the queue to add after. + @private + */ + run._addQueue = function(name, after) { + if (indexOf.call(run.queues, name) === -1) { + run.queues.splice(indexOf.call(run.queues, after)+1, 0, name); + } + }; + }); +define("ember-metal/set_properties", + ["ember-metal/property_events","ember-metal/property_set","ember-metal/keys","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var changeProperties = __dependency1__.changeProperties; + var set = __dependency2__.set; + var keys = __dependency3__["default"]; + + /** + Set a list of properties on an object. These properties are set inside + a single `beginPropertyChanges` and `endPropertyChanges` batch, so + observers will be buffered. + + ```javascript + var anObject = Ember.Object.create(); + + anObject.setProperties({ + firstName: 'Stanley', + lastName: 'Stuart', + age: 21 + }); + ``` + + @method setProperties + @param self + @param {Object} hash + @return self + */ + __exports__["default"] = function setProperties(self, hash) { + changeProperties(function() { + var props = keys(hash); + var prop; + + for (var i = 0, l = props.length; i < l; i++) { + prop = props[i]; + + set(self, prop, hash[prop]); + } + }); + return self; + } + }); +define("ember-metal/utils", + ["ember-metal/core","ember-metal/platform","ember-metal/array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var o_defineProperty = __dependency2__.defineProperty; + var canDefineNonEnumerableProperties = __dependency2__.canDefineNonEnumerableProperties; + var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; + var create = __dependency2__.create; + + var forEach = __dependency3__.forEach; + + /** + @module ember-metal + */ + + /** + Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from + jQuery master. We'll just bootstrap our own uuid now. + + @private + @return {Number} the uuid + */ + var _uuid = 0; + + /** + Generates a universally unique identifier. This method + is used internally by Ember for assisting with + the generation of GUID's and other unique identifiers + such as `bind-attr` data attributes. + + @public + @return {Number} [description] + */ + function uuid() { + return ++_uuid; + } + + __exports__.uuid = uuid;/** + Prefix used for guids through out Ember. + @private + @property GUID_PREFIX + @for Ember + @type String + @final + */ + var GUID_PREFIX = 'ember'; + + var o_create = create; + // Used for guid generation... + var numberCache = []; + var stringCache = {}; + + /** + Strongly hint runtimes to intern the provided string. + + When do I need to use this function? + + For the most part, never. Pre-mature optimization is bad, and often the + runtime does exactly what you need it to, and more often the trade-off isn't + worth it. + + Why? + + Runtimes store strings in at least 2 different representations: + Ropes and Symbols (interned strings). The Rope provides a memory efficient + data-structure for strings created from concatenation or some other string + manipulation like splitting. + + Unfortunately checking equality of different ropes can be quite costly as + runtimes must resort to clever string comparison algorithims. These + algorithims typically cost in proportion to the length of the string. + Luckily, this is where the Symbols (interned strings) shine. As Symbols are + unique by their string content, equality checks can be done by pointer + comparision. + + How do I know if my string is a rope or symbol? + + Typically (warning general sweeping statement, but truthy in runtimes at + present) static strings created as part of the JS source are interned. + Strings often used for comparisions can be interned at runtime if some + criteria are met. One of these criteria can be the size of the entire rope. + For example, in chrome 38 a rope longer then 12 characters will not + intern, nor will segments of that rope. + + Some numbers: http://jsperf.com/eval-vs-keys/8 + + Known Trick™ + + @private + @return {String} interned version of the provided string + */ + function intern(str) { + var obj = {}; + obj[str] = 1; + for (var key in obj) { + if (key === str) return key; + } + return str; + } + + /** + A unique key used to assign guids and other private metadata to objects. + If you inspect an object in your browser debugger you will often see these. + They can be safely ignored. + + On browsers that support it, these properties are added with enumeration + disabled so they won't show up when you iterate over your properties. + + @private + @property GUID_KEY + @for Ember + @type String + @final + */ + var GUID_KEY = intern('__ember' + (+ new Date())); + + var GUID_DESC = { + writable: false, + configurable: false, + enumerable: false, + value: null + }; + + /** + Generates a new guid, optionally saving the guid to the object that you + pass in. You will rarely need to use this method. Instead you should + call `Ember.guidFor(obj)`, which return an existing guid if available. + + @private + @method generateGuid + @for Ember + @param {Object} [obj] Object the guid will be used for. If passed in, the guid will + be saved on the object and reused whenever you pass the same object + again. + + If no object is passed, just generate a new guid. + @param {String} [prefix] Prefix to place in front of the guid. Useful when you want to + separate the guid into separate namespaces. + @return {String} the guid + */ + function generateGuid(obj, prefix) { + if (!prefix) prefix = GUID_PREFIX; + var ret = (prefix + uuid()); + if (obj) { + if (obj[GUID_KEY] === null) { + obj[GUID_KEY] = ret; + } else { + GUID_DESC.value = ret; + o_defineProperty(obj, GUID_KEY, GUID_DESC); + } + } + return ret; + } + + __exports__.generateGuid = generateGuid;/** + Returns a unique id for the object. If the object does not yet have a guid, + one will be assigned to it. You can call this on any object, + `Ember.Object`-based or not, but be aware that it will add a `_guid` + property. + + You can also use this method on DOM Element objects. + + @private + @method guidFor + @for Ember + @param {Object} obj any object, string, number, Element, or primitive + @return {String} the unique guid for this instance. + */ + function guidFor(obj) { + + // special cases where we don't want to add a key to object + if (obj === undefined) return "(undefined)"; + if (obj === null) return "(null)"; + + var ret; + var type = typeof obj; + + // Don't allow prototype changes to String etc. to change the guidFor + switch(type) { + case 'number': + ret = numberCache[obj]; + if (!ret) ret = numberCache[obj] = 'nu'+obj; + return ret; + + case 'string': + ret = stringCache[obj]; + if (!ret) ret = stringCache[obj] = 'st' + uuid(); + return ret; + + case 'boolean': + return obj ? '(true)' : '(false)'; + + default: + if (obj[GUID_KEY]) return obj[GUID_KEY]; + if (obj === Object) return '(Object)'; + if (obj === Array) return '(Array)'; + ret = GUID_PREFIX + uuid(); + + if (obj[GUID_KEY] === null) { + obj[GUID_KEY] = ret; + } else { + GUID_DESC.value = ret; + o_defineProperty(obj, GUID_KEY, GUID_DESC); + } + return ret; + } + } + + __exports__.guidFor = guidFor;// .......................................................... + // META + // + + var META_DESC = { + writable: true, + configurable: false, + enumerable: false, + value: null + }; + + function Meta(obj) { + this.descs = {}; + this.watching = {}; + this.cache = {}; + this.cacheMeta = {}; + this.source = obj; + } + + Meta.prototype = { + descs: null, + deps: null, + watching: null, + listeners: null, + cache: null, + cacheMeta: null, + source: null, + mixins: null, + bindings: null, + chains: null, + chainWatchers: null, + values: null, + proto: null + }; + + if (!canDefineNonEnumerableProperties) { + // on platforms that don't support enumerable false + // make meta fail jQuery.isPlainObject() to hide from + // jQuery.extend() by having a property that fails + // hasOwnProperty check. + Meta.prototype.__preventPlainObject__ = true; + + // Without non-enumerable properties, meta objects will be output in JSON + // unless explicitly suppressed + Meta.prototype.toJSON = function () { }; + } + + // Placeholder for non-writable metas. + var EMPTY_META = new Meta(null); + + + if (hasPropertyAccessors) { + EMPTY_META.values = {}; + } + + + /** + Retrieves the meta hash for an object. If `writable` is true ensures the + hash is writable for this object as well. + + The meta object contains information about computed property descriptors as + well as any watched properties and other information. You generally will + not access this information directly but instead work with higher level + methods that manipulate this hash indirectly. + + @method meta + @for Ember + @private + + @param {Object} obj The object to retrieve meta for + @param {Boolean} [writable=true] Pass `false` if you do not intend to modify + the meta hash, allowing the method to avoid making an unnecessary copy. + @return {Object} the meta hash for an object + */ + function meta(obj, writable) { + + var ret = obj['__ember_meta__']; + if (writable===false) return ret || EMPTY_META; + + if (!ret) { + if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); + + ret = new Meta(obj); + + + if (hasPropertyAccessors) { + ret.values = {}; + } + + + obj['__ember_meta__'] = ret; + + // make sure we don't accidentally try to create constructor like desc + ret.descs.constructor = null; + + } else if (ret.source !== obj) { + if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); + + ret = o_create(ret); + ret.descs = o_create(ret.descs); + ret.watching = o_create(ret.watching); + ret.cache = {}; + ret.cacheMeta = {}; + ret.source = obj; + + + if (hasPropertyAccessors) { + ret.values = o_create(ret.values); + } + + + obj['__ember_meta__'] = ret; + } + return ret; + } + + function getMeta(obj, property) { + var _meta = meta(obj, false); + return _meta[property]; + } + + __exports__.getMeta = getMeta;function setMeta(obj, property, value) { + var _meta = meta(obj, true); + _meta[property] = value; + return value; + } + + __exports__.setMeta = setMeta;/** + @deprecated + @private + + In order to store defaults for a class, a prototype may need to create + a default meta object, which will be inherited by any objects instantiated + from the class's constructor. + + However, the properties of that meta object are only shallow-cloned, + so if a property is a hash (like the event system's `listeners` hash), + it will by default be shared across all instances of that class. + + This method allows extensions to deeply clone a series of nested hashes or + other complex objects. For instance, the event system might pass + `['listeners', 'foo:change', 'ember157']` to `prepareMetaPath`, which will + walk down the keys provided. + + For each key, if the key does not exist, it is created. If it already + exists and it was inherited from its constructor, the constructor's + key is cloned. + + You can also pass false for `writable`, which will simply return + undefined if `prepareMetaPath` discovers any part of the path that + shared or undefined. + + @method metaPath + @for Ember + @param {Object} obj The object whose meta we are examining + @param {Array} path An array of keys to walk down + @param {Boolean} writable whether or not to create a new meta + (or meta property) if one does not already exist or if it's + shared with its constructor + */ + function metaPath(obj, path, writable) { + Ember.deprecate("Ember.metaPath is deprecated and will be removed from future releases."); + var _meta = meta(obj, writable); + var keyName, value; + + for (var i=0, l=path.length; i 1) { + watching[keyName]--; + } + } + + __exports__.unwatchKey = unwatchKey; + }); +define("ember-metal/watch_path", + ["ember-metal/utils","ember-metal/chains","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var meta = __dependency1__.meta; + var typeOf = __dependency1__.typeOf; + var ChainNode = __dependency2__.ChainNode; + + var metaFor = meta; + + // get the chains for the current object. If the current object has + // chains inherited from the proto they will be cloned and reconfigured for + // the current object. + function chainsFor(obj, meta) { + var m = meta || metaFor(obj); + var ret = m.chains; + if (!ret) { + ret = m.chains = new ChainNode(null, null, obj); + } else if (ret.value() !== obj) { + ret = m.chains = ret.copy(obj); + } + return ret; + } + + function watchPath(obj, keyPath, meta) { + // can't watch length on Array - it is special... + if (keyPath === 'length' && typeOf(obj) === 'array') { return; } + + var m = meta || metaFor(obj); + var watching = m.watching; + + if (!watching[keyPath]) { // activate watching first time + watching[keyPath] = 1; + chainsFor(obj, m).add(keyPath); + } else { + watching[keyPath] = (watching[keyPath] || 0) + 1; + } + } + + __exports__.watchPath = watchPath;function unwatchPath(obj, keyPath, meta) { + var m = meta || metaFor(obj); + var watching = m.watching; + + if (watching[keyPath] === 1) { + watching[keyPath] = 0; + chainsFor(obj, m).remove(keyPath); + } else if (watching[keyPath] > 1) { + watching[keyPath]--; + } + } + + __exports__.unwatchPath = unwatchPath; + }); +define("ember-metal/watching", + ["ember-metal/utils","ember-metal/chains","ember-metal/watch_key","ember-metal/watch_path","ember-metal/path_cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var meta = __dependency1__.meta; + var GUID_KEY = __dependency1__.GUID_KEY; + var typeOf = __dependency1__.typeOf; + var generateGuid = __dependency1__.generateGuid; + var removeChainWatcher = __dependency2__.removeChainWatcher; + var flushPendingChains = __dependency2__.flushPendingChains; + var watchKey = __dependency3__.watchKey; + var unwatchKey = __dependency3__.unwatchKey; + var watchPath = __dependency4__.watchPath; + var unwatchPath = __dependency4__.unwatchPath; + + var metaFor = meta; // utils.js + var isPath = __dependency5__.isPath; + + /** + Starts watching a property on an object. Whenever the property changes, + invokes `Ember.propertyWillChange` and `Ember.propertyDidChange`. This is the + primitive used by observers and dependent keys; usually you will never call + this method directly but instead use higher level methods like + `Ember.addObserver()` + + @private + @method watch + @for Ember + @param obj + @param {String} keyName + */ + function watch(obj, _keyPath, m) { + // can't watch length on Array - it is special... + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } + + if (!isPath(_keyPath)) { + watchKey(obj, _keyPath, m); + } else { + watchPath(obj, _keyPath, m); + } + } + + __exports__.watch = watch; + + function isWatching(obj, key) { + var meta = obj['__ember_meta__']; + return (meta && meta.watching[key]) > 0; + } + + __exports__.isWatching = isWatching;watch.flushPending = flushPendingChains; + + function unwatch(obj, _keyPath, m) { + // can't watch length on Array - it is special... + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } + + if (!isPath(_keyPath)) { + unwatchKey(obj, _keyPath, m); + } else { + unwatchPath(obj, _keyPath, m); + } + } + + __exports__.unwatch = unwatch;/** + Call on an object when you first beget it from another object. This will + setup any chained watchers on the object instance as needed. This method is + safe to call multiple times. + + @private + @method rewatch + @for Ember + @param obj + */ + function rewatch(obj) { + var m = obj['__ember_meta__'], chains = m && m.chains; + + // make sure the object has its own guid. + if (GUID_KEY in obj && !obj.hasOwnProperty(GUID_KEY)) { + generateGuid(obj); + } + + // make sure any chained watchers update. + if (chains && chains.value() !== obj) { + m.chains = chains.copy(obj); + } + } + + __exports__.rewatch = rewatch;var NODE_STACK = []; + + /** + Tears down the meta on an object so that it can be garbage collected. + Multiple calls will have no effect. + + @method destroy + @for Ember + @param {Object} obj the object to destroy + @return {void} + */ + function destroy(obj) { + var meta = obj['__ember_meta__'], node, nodes, key, nodeObject; + if (meta) { + obj['__ember_meta__'] = null; + // remove chainWatchers to remove circular references that would prevent GC + node = meta.chains; + if (node) { + NODE_STACK.push(node); + // process tree + while (NODE_STACK.length > 0) { + node = NODE_STACK.pop(); + // push children + nodes = node._chains; + if (nodes) { + for (key in nodes) { + if (nodes.hasOwnProperty(key)) { + NODE_STACK.push(nodes[key]); + } + } + } + // remove chainWatcher in node object + if (node._watching) { + nodeObject = node._object; + if (nodeObject) { + removeChainWatcher(nodeObject, node._key, node); + } + } + } + } + } + } + + __exports__.destroy = destroy; + }); +define("ember-routing-handlebars", + ["ember-metal/core","ember-handlebars","ember-routing/system/router","ember-routing-handlebars/helpers/shared","ember-routing-handlebars/helpers/link_to","ember-routing-handlebars/helpers/outlet","ember-routing-handlebars/helpers/render","ember-routing-handlebars/helpers/action","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + Ember Routing Handlebars + + @module ember + @submodule ember-routing-handlebars + @requires ember-views + */ + + var Ember = __dependency1__["default"]; + var EmberHandlebars = __dependency2__["default"]; + var Router = __dependency3__["default"]; + + var resolvePaths = __dependency4__.resolvePaths; + var resolveParams = __dependency4__.resolveParams; + + var deprecatedLinkToHelper = __dependency5__.deprecatedLinkToHelper; + var linkToHelper = __dependency5__.linkToHelper; + var LinkView = __dependency5__.LinkView; + var queryParamsHelper = __dependency5__.queryParamsHelper; + + var outletHelper = __dependency6__.outletHelper; + var OutletView = __dependency6__.OutletView; + + var renderHelper = __dependency7__["default"]; + + var ActionHelper = __dependency8__.ActionHelper; + var actionHelper = __dependency8__.actionHelper; + + Router.resolveParams = resolveParams; + Router.resolvePaths = resolvePaths; + + Ember.LinkView = LinkView; + EmberHandlebars.ActionHelper = ActionHelper; + EmberHandlebars.OutletView = OutletView; + + EmberHandlebars.registerHelper('render', renderHelper); + EmberHandlebars.registerHelper('action', actionHelper); + EmberHandlebars.registerHelper('outlet', outletHelper); + EmberHandlebars.registerHelper('link-to', linkToHelper); + EmberHandlebars.registerHelper('linkTo', deprecatedLinkToHelper); + EmberHandlebars.registerHelper('query-params', queryParamsHelper); + + __exports__["default"] = Ember; + }); +define("ember-routing-handlebars/helpers/action", + ["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/run_loop","ember-views/system/utils","ember-views/system/action_manager","ember-routing/system/router","ember-handlebars","ember-handlebars/ext","ember-handlebars/helpers/view","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Handlebars, uuid, FEATURES, assert, deprecate + var get = __dependency2__.get; + var forEach = __dependency3__.forEach; + var uuid = __dependency4__.uuid; + var run = __dependency5__["default"]; + + var isSimpleClick = __dependency6__.isSimpleClick; + var ActionManager = __dependency7__["default"]; + var EmberRouter = __dependency8__["default"]; + + var EmberHandlebars = __dependency9__["default"]; + var handlebarsGet = __dependency10__.handlebarsGet; + var viewHelper = __dependency11__.viewHelper; + var resolveParams = __dependency12__.resolveParams; + var resolvePath = __dependency12__.resolvePath; + + /** + @module ember + @submodule ember-routing + */ + + var SafeString = EmberHandlebars.SafeString; + var a_slice = Array.prototype.slice; + + function args(options, actionName) { + var ret = []; + if (actionName) { ret.push(actionName); } + + var types = options.options.types.slice(1); + var data = options.options.data; + + return ret.concat(resolveParams(options.context, options.params, { types: types, data: data })); + } + + var ActionHelper = {}; + + // registeredActions is re-exported for compatibility with older plugins + // that were using this undocumented API. + ActionHelper.registeredActions = ActionManager.registeredActions; + + __exports__.ActionHelper = ActionHelper; + + var keys = ["alt", "shift", "meta", "ctrl"]; + + var POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/; + + var isAllowedEvent = function(event, allowedKeys) { + if (typeof allowedKeys === "undefined") { + if (POINTER_EVENT_TYPE_REGEX.test(event.type)) { + return isSimpleClick(event); + } else { + allowedKeys = ''; + } + } + + if (allowedKeys.indexOf("any") >= 0) { + return true; + } + + var allowed = true; + + forEach.call(keys, function(key) { + if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) { + allowed = false; + } + }); + + return allowed; + }; + + function isKeyEvent(eventName) { + return ['keyUp', 'keyPress', 'keyDown'].indexOf(eventName) !== -1; + } + + function ignoreKeyEvent(eventName, event, keyCode) { + var any = 'any'; + keyCode = keyCode || any; + return isKeyEvent(eventName) && keyCode !== any && keyCode !== event.which.toString(); + } + + ActionHelper.registerAction = function(actionNameOrPath, options, allowedKeys) { + var actionId = uuid(); + + ActionManager.registeredActions[actionId] = { + eventName: options.eventName, + handler: function handleRegisteredAction(event) { + if (!isAllowedEvent(event, allowedKeys)) { return true; } + + if (options.preventDefault !== false) { + event.preventDefault(); + } + + if (options.bubbles === false) { + event.stopPropagation(); + } + + var target = options.target; + var parameters = options.parameters; + var eventName = options.eventName; + var actionName; + + + if (target.target) { + target = handlebarsGet(target.root, target.target, target.options); + } else { + target = target.root; + } + + if (options.boundProperty) { + actionName = resolveParams(parameters.context, [actionNameOrPath], { types: ['ID'], data: parameters.options.data })[0]; + + if (typeof actionName === 'undefined' || typeof actionName === 'function') { + Ember.deprecate("You specified a quoteless path to the {{action}} helper '" + actionNameOrPath + "' which did not resolve to an actionName. Perhaps you meant to use a quoted actionName? (e.g. {{action '" + actionNameOrPath + "'}})."); + actionName = actionNameOrPath; + } + } + + if (!actionName) { + actionName = actionNameOrPath; + } + + run(function runRegisteredAction() { + if (target.send) { + target.send.apply(target, args(parameters, actionName)); + } else { + Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function'); + target[actionName].apply(target, args(parameters)); + } + }); + } + }; + + options.view.on('willClearRender', function() { + delete ActionManager.registeredActions[actionId]; + }); + + return actionId; + }; + + /** + The `{{action}}` helper registers an HTML element within a template for DOM + event handling and forwards that interaction to the templates's controller + or supplied `target` option (see 'Specifying a Target'). + + If the controller does not implement the event, the event is sent + to the current route, and it bubbles up the route hierarchy from there. + + User interaction with that element will invoke the supplied action name on + the appropriate target. Specifying a non-quoted action name will result in + a bound property lookup at the time the event will be triggered. + + Given the following application Handlebars template on the page + + ```handlebars +
    + click me +
    + ``` + + And application code + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + actions: { + anActionName: function() { + } + } + }); + ``` + + Will result in the following rendered HTML + + ```html +
    +
    + click me +
    +
    + ``` + + Clicking "click me" will trigger the `anActionName` action of the + `App.ApplicationController`. In this case, no additional parameters will be passed. + + If you provide additional parameters to the helper: + + ```handlebars + + ``` + + Those parameters will be passed along as arguments to the JavaScript + function implementing the action. + + ### Event Propagation + + Events triggered through the action helper will automatically have + `.preventDefault()` called on them. You do not need to do so in your event + handlers. If you need to allow event propagation (to handle file inputs for + example) you can supply the `preventDefault=false` option to the `{{action}}` helper: + + ```handlebars +
    + + +
    + ``` + + To disable bubbling, pass `bubbles=false` to the helper: + + ```handlebars + + ``` + + If you need the default handler to trigger you should either register your + own event handler, or use event methods on your view class. See [Ember.View](/api/classes/Ember.View.html) + 'Responding to Browser Events' for more information. + + ### Specifying DOM event type + + By default the `{{action}}` helper registers for DOM `click` events. You can + supply an `on` option to the helper to specify a different DOM event name: + + ```handlebars +
    + click me +
    + ``` + + See `Ember.View` 'Responding to Browser Events' for a list of + acceptable DOM event names. + + NOTE: Because `{{action}}` depends on Ember's event dispatch system it will + only function if an `Ember.EventDispatcher` instance is available. An + `Ember.EventDispatcher` instance will be created when a new `Ember.Application` + is created. Having an instance of `Ember.Application` will satisfy this + requirement. + + ### Specifying whitelisted modifier keys + + By default the `{{action}}` helper will ignore click event with pressed modifier + keys. You can supply an `allowedKeys` option to specify which keys should not be ignored. + + ```handlebars +
    + click me +
    + ``` + + This way the `{{action}}` will fire when clicking with the alt key pressed down. + + Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys. + + ```handlebars +
    + click me with any key pressed +
    + ``` + + ### Specifying a Target + + There are several possible target objects for `{{action}}` helpers: + + In a typical Ember application, where views are managed through use of the + `{{outlet}}` helper, actions will bubble to the current controller, then + to the current route, and then up the route hierarchy. + + Alternatively, a `target` option can be provided to the helper to change + which object will receive the method call. This option must be a path + to an object, accessible in the current context: + + ```handlebars + {{! the application template }} +
    + click me +
    + ``` + + ```javascript + App.ApplicationView = Ember.View.extend({ + actions: { + anActionName: function(){} + } + }); + + ``` + + ### Additional Parameters + + You may specify additional parameters to the `{{action}}` helper. These + parameters are passed along as the arguments to the JavaScript function + implementing the action. + + ```handlebars + {{#each person in people}} +
    + click me +
    + {{/each}} + ``` + + Clicking "click me" will trigger the `edit` method on the current controller + with the value of `person` as a parameter. + + @method action + @for Ember.Handlebars.helpers + @param {String} actionName + @param {Object} [context]* + @param {Hash} options + */ + function actionHelper(actionName) { + var options = arguments[arguments.length - 1]; + var contexts = a_slice.call(arguments, 1, -1); + var hash = options.hash; + var controller = options.data.keywords.controller; + + // create a hash to pass along to registerAction + var action = { + eventName: hash.on || "click", + parameters: { + context: this, + options: options, + params: contexts + }, + view: options.data.view, + bubbles: hash.bubbles, + preventDefault: hash.preventDefault, + target: { options: options }, + withKeyCode: hash.withKeyCode, + boundProperty: options.types[0] === "ID" + }; + + if (hash.target) { + action.target.root = this; + action.target.target = hash.target; + } else if (controller) { + action.target.root = controller; + } + + var actionId = ActionHelper.registerAction(actionName, action, hash.allowedKeys); + return new SafeString('data-ember-action="' + actionId + '"'); + } + + __exports__.actionHelper = actionHelper; + }); +define("ember-routing-handlebars/helpers/link_to", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-runtime/system/lazy_load","ember-runtime/system/string","ember-runtime/system/object","ember-metal/keys","ember-views/system/utils","ember-views/views/component","ember-handlebars","ember-handlebars/helpers/view","ember-routing/system/router","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, Logger, Handlebars, warn, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var merge = __dependency4__["default"]; + var run = __dependency5__["default"]; + var computed = __dependency6__.computed; + + var onLoad = __dependency7__.onLoad; + var fmt = __dependency8__.fmt; + var EmberObject = __dependency9__["default"]; + var keys = __dependency10__["default"]; + var isSimpleClick = __dependency11__.isSimpleClick; + var EmberComponent = __dependency12__["default"]; + var EmberHandlebars = __dependency13__["default"]; + var viewHelper = __dependency14__.viewHelper; + var EmberRouter = __dependency15__["default"]; + var resolveParams = __dependency16__.resolveParams; + var resolvePaths = __dependency16__.resolvePaths; + var routeArgs = __dependency16__.routeArgs; + + /** + @module ember + @submodule ember-routing + */ + + var slice = [].slice; + + requireModule('ember-handlebars'); + + var numberOfContextsAcceptedByHandler = function(handler, handlerInfos) { + var req = 0; + for (var i = 0, l = handlerInfos.length; i < l; i++) { + req = req + handlerInfos[i].names.length; + if (handlerInfos[i].handler === handler) + break; + } + + return req; + }; + + var QueryParams = EmberObject.extend({ + values: null + }); + + function getResolvedPaths(options) { + + var types = options.options.types; + var data = options.options.data; + + return resolvePaths(options.context, options.params, { types: types, data: data }); + } + + /** + `Ember.LinkView` renders an element whose `click` event triggers a + transition of the application's instance of `Ember.Router` to + a supplied route by name. + + Instances of `LinkView` will most likely be created through + the `link-to` Handlebars helper, but properties of this class + can be overridden to customize application-wide behavior. + + @class LinkView + @namespace Ember + @extends Ember.View + @see {Handlebars.helpers.link-to} + **/ + var LinkView = Ember.LinkView = EmberComponent.extend({ + tagName: 'a', + + /** + @deprecated Use current-when instead. + @property currentWhen + */ + currentWhen: null, + + /** + Used to determine when this LinkView is active. + + @property currentWhen + */ + 'current-when': null, + + /** + Sets the `title` attribute of the `LinkView`'s HTML element. + + @property title + @default null + **/ + title: null, + + /** + Sets the `rel` attribute of the `LinkView`'s HTML element. + + @property rel + @default null + **/ + rel: null, + + /** + The CSS class to apply to `LinkView`'s element when its `active` + property is `true`. + + @property activeClass + @type String + @default active + **/ + activeClass: 'active', + + /** + The CSS class to apply to `LinkView`'s element when its `loading` + property is `true`. + + @property loadingClass + @type String + @default loading + **/ + loadingClass: 'loading', + + /** + The CSS class to apply to a `LinkView`'s element when its `disabled` + property is `true`. + + @property disabledClass + @type String + @default disabled + **/ + disabledClass: 'disabled', + _isDisabled: false, + + /** + Determines whether the `LinkView` will trigger routing via + the `replaceWith` routing strategy. + + @property replace + @type Boolean + @default false + **/ + replace: false, + + /** + By default the `{{link-to}}` helper will bind to the `href` and + `title` attributes. It's discourage that you override these defaults, + however you can push onto the array if needed. + + @property attributeBindings + @type Array | String + @default ['href', 'title', 'rel'] + **/ + attributeBindings: ['href', 'title', 'rel', 'tabindex'], + + /** + By default the `{{link-to}}` helper will bind to the `active`, `loading`, and + `disabled` classes. It is discouraged to override these directly. + + @property classNameBindings + @type Array + @default ['active', 'loading', 'disabled'] + **/ + classNameBindings: ['active', 'loading', 'disabled'], + + /** + By default the `{{link-to}}` helper responds to the `click` event. You + can override this globally by setting this property to your custom + event name. + + This is particularly useful on mobile when one wants to avoid the 300ms + click delay using some sort of custom `tap` event. + + @property eventName + @type String + @default click + */ + eventName: 'click', + + // this is doc'ed here so it shows up in the events + // section of the API documentation, which is where + // people will likely go looking for it. + /** + Triggers the `LinkView`'s routing behavior. If + `eventName` is changed to a value other than `click` + the routing behavior will trigger on that custom event + instead. + + @event click + **/ + + /** + An overridable method called when LinkView objects are instantiated. + + Example: + + ```javascript + App.MyLinkView = Ember.LinkView.extend({ + init: function() { + this._super(); + Ember.Logger.log('Event is ' + this.get('eventName')); + } + }); + ``` + + NOTE: If you do override `init` for a framework class like `Ember.View` or + `Ember.ArrayController`, be sure to call `this._super()` in your + `init` declaration! If you don't, Ember may not have an opportunity to + do important setup work, and you'll see strange behavior in your + application. + + @method init + */ + init: function() { + this._super.apply(this, arguments); + + Ember.deprecate('Using currentWhen with {{link-to}} is deprecated in favor of `current-when`.', !this.currentWhen); + + // Map desired event name to invoke function + var eventName = get(this, 'eventName'); + this.on(eventName, this, this._invoke); + }, + + /** + This method is invoked by observers installed during `init` that fire + whenever the params change + + @private + @method _paramsChanged + @since 1.3.0 + */ + _paramsChanged: function() { + this.notifyPropertyChange('resolvedParams'); + }, + + /** + This is called to setup observers that will trigger a rerender. + + @private + @method _setupPathObservers + @since 1.3.0 + **/ + _setupPathObservers: function(){ + var helperParameters = this.parameters; + var linkTextPath = helperParameters.options.linkTextPath; + var paths = getResolvedPaths(helperParameters); + var length = paths.length; + var path, i, normalizedPath; + + if (linkTextPath) { + normalizedPath = getNormalizedPath(linkTextPath, helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this.rerender); + } + + for(i=0; i < length; i++) { + path = paths[i]; + if (null === path) { + // A literal value was provided, not a path, so nothing to observe. + continue; + } + + normalizedPath = getNormalizedPath(path, helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged); + } + + var queryParamsObject = this.queryParamsObject; + if (queryParamsObject) { + var values = queryParamsObject.values; + + // Install observers for all of the hash options + // provided in the (query-params) subexpression. + for (var k in values) { + if (!values.hasOwnProperty(k)) { continue; } + + if (queryParamsObject.types[k] === 'ID') { + normalizedPath = getNormalizedPath(values[k], helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged); + } + } + } + }, + + afterRender: function(){ + this._super.apply(this, arguments); + this._setupPathObservers(); + }, + + /** + + Accessed as a classname binding to apply the `LinkView`'s `disabledClass` + CSS `class` to the element when the link is disabled. + + When `true` interactions with the element will not trigger route changes. + @property disabled + */ + disabled: computed(function computeLinkViewDisabled(key, value) { + if (value !== undefined) { this.set('_isDisabled', value); } + + return value ? get(this, 'disabledClass') : false; + }), + + /** + Accessed as a classname binding to apply the `LinkView`'s `activeClass` + CSS `class` to the element when the link is active. + + A `LinkView` is considered active when its `currentWhen` property is `true` + or the application's current route is the route the `LinkView` would trigger + transitions into. + + The `currentWhen` property can match against multiple routes by separating + route names using the ` ` (space) character. + + @property active + **/ + active: computed('loadedParams', function computeLinkViewActive() { + if (get(this, 'loading')) { return false; } + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + var contexts = loadedParams.models; + var currentWhen = this['current-when'] || this.currentWhen; + var isCurrentWhenSpecified = Boolean(currentWhen); + currentWhen = currentWhen || loadedParams.targetRouteName; + + function isActiveForRoute(routeName) { + var handlers = router.router.recognizer.handlersFor(routeName); + var leafName = handlers[handlers.length-1].handler; + var maximumContexts = numberOfContextsAcceptedByHandler(routeName, handlers); + + // NOTE: any ugliness in the calculation of activeness is largely + // due to the fact that we support automatic normalizing of + // `resource` -> `resource.index`, even though there might be + // dynamic segments / query params defined on `resource.index` + // which complicates (and makes somewhat ambiguous) the calculation + // of activeness for links that link to `resource` instead of + // directly to `resource.index`. + + // if we don't have enough contexts revert back to full route name + // this is because the leaf route will use one of the contexts + if (contexts.length > maximumContexts) { + routeName = leafName; + } + + var args = routeArgs(routeName, contexts, null); + var isActive = router.isActive.apply(router, args); + if (!isActive) { return false; } + + var emptyQueryParams = Ember.isEmpty(Ember.keys(loadedParams.queryParams)); + + if (!isCurrentWhenSpecified && !emptyQueryParams && isActive) { + var visibleQueryParams = {}; + merge(visibleQueryParams, loadedParams.queryParams); + router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + isActive = shallowEqual(visibleQueryParams, router.router.state.queryParams); + } + + return isActive; + } + + + currentWhen = currentWhen.split(' '); + for (var i = 0, len = currentWhen.length; i < len; i++) { + if (isActiveForRoute(currentWhen[i])) { + return get(this, 'activeClass'); + } + } + }), + + /** + Accessed as a classname binding to apply the `LinkView`'s `loadingClass` + CSS `class` to the element when the link is loading. + + A `LinkView` is considered loading when it has at least one + parameter whose value is currently null or undefined. During + this time, clicking the link will perform no transition and + emit a warning that the link is still in a loading state. + + @property loading + **/ + loading: computed('loadedParams', function computeLinkViewLoading() { + if (!get(this, 'loadedParams')) { return get(this, 'loadingClass'); } + }), + + /** + Returns the application's main router from the container. + + @private + @property router + **/ + router: computed(function() { + var controller = get(this, 'controller'); + if (controller && controller.container) { + return controller.container.lookup('router:main'); + } + }), + + /** + Event handler that invokes the link, activating the associated route. + + @private + @method _invoke + @param {Event} event + */ + _invoke: function(event) { + if (!isSimpleClick(event)) { return true; } + + if (this.preventDefault !== false) { + + var targetAttribute = get(this, 'target'); + if (!targetAttribute || targetAttribute === '_self') { + event.preventDefault(); + } + } + + if (this.bubbles === false) { event.stopPropagation(); } + + if (get(this, '_isDisabled')) { return false; } + + if (get(this, 'loading')) { + Ember.Logger.warn("This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid."); + return false; + } + + + var targetAttribute2 = get(this, 'target'); + if (targetAttribute2 && targetAttribute2 !== '_self') { + return false; + } + + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + + var transition = router._doTransition(loadedParams.targetRouteName, loadedParams.models, loadedParams.queryParams); + if (get(this, 'replace')) { + transition.method('replace'); + } + + // Schedule eager URL update, but after we've given the transition + // a chance to synchronously redirect. + // We need to always generate the URL instead of using the href because + // the href will include any rootURL set, but the router expects a URL + // without it! Note that we don't use the first level router because it + // calls location.formatURL(), which also would add the rootURL! + var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, transition.state.queryParams); + var url = router.router.generate.apply(router.router, args); + + run.scheduleOnce('routerTransitions', this, this._eagerUpdateUrl, transition, url); + }, + + /** + @private + @method _eagerUpdateUrl + @param transition + @param href + */ + _eagerUpdateUrl: function(transition, href) { + if (!transition.isActive || !transition.urlMethod) { + // transition was aborted, already ran to completion, + // or it has a null url-updated method. + return; + } + + if (href.indexOf('#') === 0) { + href = href.slice(1); + } + + // Re-use the routerjs hooks set up by the Ember router. + var routerjs = get(this, 'router.router'); + if (transition.urlMethod === 'update') { + routerjs.updateURL(href); + } else if (transition.urlMethod === 'replace') { + routerjs.replaceURL(href); + } + + // Prevent later update url refire. + transition.method(null); + }, + + /** + Computed property that returns an array of the + resolved parameters passed to the `link-to` helper, + e.g.: + + ```hbs + {{link-to a b '123' c}} + ``` + + will generate a `resolvedParams` of: + + ```js + [aObject, bObject, '123', cObject] + ``` + + @private + @property + @return {Array} + */ + resolvedParams: computed('router.url', function() { + var parameters = this.parameters; + var options = parameters.options; + var types = options.types; + var data = options.data; + var targetRouteName, models; + var onlyQueryParamsSupplied = (parameters.params.length === 0); + + if (onlyQueryParamsSupplied) { + var appController = this.container.lookup('controller:application'); + targetRouteName = get(appController, 'currentRouteName'); + models = []; + } else { + models = resolveParams(parameters.context, parameters.params, { types: types, data: data }); + targetRouteName = models.shift(); + } + + var suppliedQueryParams = getResolvedQueryParams(this, targetRouteName); + + return { + targetRouteName: targetRouteName, + models: models, + queryParams: suppliedQueryParams + }; + }), + + /** + Computed property that returns the current route name, + dynamic segments, and query params. Returns falsy if + for null/undefined params to indicate that the link view + is still in a loading state. + + @private + @property + @return {Array} An array with the route name and any dynamic segments + **/ + loadedParams: computed('resolvedParams', function computeLinkViewRouteArgs() { + var router = get(this, 'router'); + if (!router) { return; } + + var resolvedParams = get(this, 'resolvedParams'); + var namedRoute = resolvedParams.targetRouteName; + + if (!namedRoute) { return; } + + Ember.assert(fmt("The attempt to link-to route '%@' failed. " + + "The router did not find '%@' in its possible routes: '%@'", + [namedRoute, namedRoute, keys(router.router.recognizer.names).join("', '")]), + router.hasRoute(namedRoute)); + + if (!paramsAreLoaded(resolvedParams.models)) { return; } + + return resolvedParams; + }), + + queryParamsObject: null, + + /** + Sets the element's `href` attribute to the url for + the `LinkView`'s targeted route. + + If the `LinkView`'s `tagName` is changed to a value other + than `a`, this property will be ignored. + + @property href + **/ + href: computed('loadedParams', function computeLinkViewHref() { + if (get(this, 'tagName') !== 'a') { return; } + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + + if (!loadedParams) { + return get(this, 'loadingHref'); + } + + var visibleQueryParams = {}; + merge(visibleQueryParams, loadedParams.queryParams); + router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + + var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + var result = router.generate.apply(router, args); + return result; + }), + + /** + The default href value to use while a link-to is loading. + Only applies when tagName is 'a' + + @property loadingHref + @type String + @default # + */ + loadingHref: '#' + }); + + LinkView.toString = function() { return "LinkView"; }; + + + LinkView.reopen({ + attributeBindings: ['target'], + + /** + Sets the `target` attribute of the `LinkView`'s anchor element. + + @property target + @default null + **/ + target: null + }); + + + /** + The `{{link-to}}` helper renders a link to the supplied + `routeName` passing an optionally supplied model to the + route as its `model` context of the route. The block + for `{{link-to}}` becomes the innerHTML of the rendered + element: + + ```handlebars + {{#link-to 'photoGallery'}} + Great Hamster Photos + {{/link-to}} + ``` + + ```html + + Great Hamster Photos + + ``` + + ### Supplying a tagName + By default `{{link-to}}` renders an `` element. This can + be overridden for a single use of `{{link-to}}` by supplying + a `tagName` option: + + ```handlebars + {{#link-to 'photoGallery' tagName="li"}} + Great Hamster Photos + {{/link-to}} + ``` + + ```html +
  • + Great Hamster Photos +
  • + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Disabling the `link-to` helper + By default `{{link-to}}` is enabled. + any passed value to `disabled` helper property will disable the `link-to` helper. + + static use: the `disabled` option: + + ```handlebars + {{#link-to 'photoGallery' disabled=true}} + Great Hamster Photos + {{/link-to}} + ``` + + dynamic use: the `disabledWhen` option: + + ```handlebars + {{#link-to 'photoGallery' disabledWhen=controller.someProperty}} + Great Hamster Photos + {{/link-to}} + ``` + + any passed value to `disabled` will disable it except `undefined`. + to ensure that only `true` disable the `link-to` helper you can + override the global behaviour of `Ember.LinkView`. + + ```javascript + Ember.LinkView.reopen({ + disabled: Ember.computed(function(key, value) { + if (value !== undefined) { + this.set('_isDisabled', value === true); + } + return value === true ? get(this, 'disabledClass') : false; + }) + }); + ``` + + see "Overriding Application-wide Defaults" for more. + + ### Handling `href` + `{{link-to}}` will use your application's Router to + fill the element's `href` property with a url that + matches the path to the supplied `routeName` for your + routers's configured `Location` scheme, which defaults + to Ember.HashLocation. + + ### Handling current route + `{{link-to}}` will apply a CSS class name of 'active' + when the application's current route matches + the supplied routeName. For example, if the application's + current route is 'photoGallery.recent' the following + use of `{{link-to}}`: + + ```handlebars + {{#link-to 'photoGallery.recent'}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + will result in + + ```html +
    + Great Hamster Photos + + ``` + + The CSS class name used for active classes can be customized + for a single use of `{{link-to}}` by passing an `activeClass` + option: + + ```handlebars + {{#link-to 'photoGallery.recent' activeClass="current-url"}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + ```html + + Great Hamster Photos + + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Supplying a model + An optional model argument can be used for routes whose + paths contain dynamic segments. This argument will become + the model context of the linked route: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhoto}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + ### Supplying multiple models + For deep-linking to route paths that contain multiple + dynamic segments, multiple model arguments can be used. + As the router transitions through the route path, each + supplied model argument will become the context for the + route with the dynamic segments: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}, function() { + this.route("comment", {path: "comments/:comment_id"}); + }); + }); + ``` + This argument will become the model context of the linked route: + + ```handlebars + {{#link-to 'photoGallery.comment' aPhoto comment}} + {{comment.body}} + {{/link-to}} + ``` + + ```html + + A+++ would snuggle again. + + ``` + + ### Supplying an explicit dynamic segment value + If you don't have a model object available to pass to `{{link-to}}`, + an optional string or integer argument can be passed for routes whose + paths contain dynamic segments. This argument will become the value + of the dynamic segment: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhotoId}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + When transitioning into the linked route, the `model` hook will + be triggered with parameters including this passed identifier. + + ### Allowing Default Action + + By default the `{{link-to}}` helper prevents the default browser action + by calling `preventDefault()` as this sort of action bubbling is normally + handled internally and we do not want to take the browser to a new URL (for + example). + + If you need to override this behavior specify `preventDefault=false` in + your template: + + ```handlebars + {{#link-to 'photoGallery' aPhotoId preventDefault=false}} + {{aPhotoId.title}} + {{/link-to}} + ``` + + ### Overriding attributes + You can override any given property of the Ember.LinkView + that is generated by the `{{link-to}}` helper by passing + key/value pairs, like so: + + ```handlebars + {{#link-to aPhoto tagName='li' title='Following this link will change your life' classNames='pic sweet'}} + Uh-mazing! + {{/link-to}} + ``` + + See [Ember.LinkView](/api/classes/Ember.LinkView.html) for a + complete list of overrideable properties. Be sure to also + check out inherited properties of `LinkView`. + + ### Overriding Application-wide Defaults + ``{{link-to}}`` creates an instance of Ember.LinkView + for rendering. To override options for your entire + application, reopen Ember.LinkView and supply the + desired values: + + ``` javascript + Ember.LinkView.reopen({ + activeClass: "is-active", + tagName: 'li' + }) + ``` + + It is also possible to override the default event in + this manner: + + ``` javascript + Ember.LinkView.reopen({ + eventName: 'customEventName' + }); + ``` + + @method link-to + @for Ember.Handlebars.helpers + @param {String} routeName + @param {Object} [context]* + @param [options] {Object} Handlebars key/value pairs of options, you can override any property of Ember.LinkView + @return {String} HTML string + @see {Ember.LinkView} + */ + function linkToHelper(name) { + var options = slice.call(arguments, -1)[0]; + var params = slice.call(arguments, 0, -1); + var hash = options.hash; + + Ember.assert("You must provide one or more parameters to the link-to helper.", params.length); + + if (params[params.length - 1] instanceof QueryParams) { + hash.queryParamsObject = params.pop(); + } + + hash.disabledBinding = hash.disabledWhen; + + if (!options.fn) { + var linkTitle = params.shift(); + var linkType = options.types.shift(); + var context = this; + if (linkType === 'ID') { + options.linkTextPath = linkTitle; + options.fn = function() { + return EmberHandlebars.getEscaped(context, linkTitle, options); + }; + } else { + options.fn = function() { + return linkTitle; + }; + } + } + + hash.parameters = { + context: this, + options: options, + params: params + }; + + options.helperName = options.helperName || 'link-to'; + + return viewHelper.call(this, LinkView, options); + } + + /** + @method query-params + @for Ember.Handlebars.helpers + @param {Object} hash takes a hash of query parameters + @return {String} HTML string + */ + function queryParamsHelper(options) { + Ember.assert(fmt("The `query-params` helper only accepts hash parameters, e.g. (query-params queryParamPropertyName='%@') as opposed to just (query-params '%@')", [options, options]), arguments.length === 1); + + return QueryParams.create({ + values: options.hash, + types: options.hashTypes + }); + } + + __exports__.queryParamsHelper = queryParamsHelper;/** + See [link-to](/api/classes/Ember.Handlebars.helpers.html#method_link-to) + + @method linkTo + @for Ember.Handlebars.helpers + @deprecated + @param {String} routeName + @param {Object} [context]* + @return {String} HTML string + */ + function deprecatedLinkToHelper() { + Ember.warn("The 'linkTo' view helper is deprecated in favor of 'link-to'"); + return linkToHelper.apply(this, arguments); + } + + function getResolvedQueryParams(linkView, targetRouteName) { + var helperParameters = linkView.parameters; + var queryParamsObject = linkView.queryParamsObject; + var resolvedQueryParams = {}; + + if (!queryParamsObject) { return resolvedQueryParams; } + var rawParams = queryParamsObject.values; + + for (var key in rawParams) { + if (!rawParams.hasOwnProperty(key)) { continue; } + + var value = rawParams[key]; + var type = queryParamsObject.types[key]; + + if (type === 'ID') { + var normalizedPath = getNormalizedPath(value, helperParameters); + value = EmberHandlebars.get(normalizedPath.root, normalizedPath.path, helperParameters.options); + } + resolvedQueryParams[key] = value; + } + return resolvedQueryParams; + } + + function getNormalizedPath(path, helperParameters) { + return EmberHandlebars.normalizePath(helperParameters.context, path, helperParameters.options.data); + } + + function paramsAreLoaded(params) { + for (var i = 0, len = params.length; i < len; ++i) { + var param = params[i]; + if (param === null || typeof param === 'undefined') { + return false; + } + } + return true; + } + + function shallowEqual(a, b) { + var k; + for (k in a) { + if (a.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + for (k in b) { + if (b.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + return true; + } + + __exports__.LinkView = LinkView; + __exports__.deprecatedLinkToHelper = deprecatedLinkToHelper; + __exports__.linkToHelper = linkToHelper; + }); +define("ember-routing-handlebars/helpers/outlet", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-views/views/container_view","ember-handlebars/views/metamorph_view","ember-handlebars/helpers/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var onLoad = __dependency4__.onLoad; + var ContainerView = __dependency5__["default"]; + var _Metamorph = __dependency6__._Metamorph; + var viewHelper = __dependency7__.viewHelper; + + /** + @module ember + @submodule ember-routing + */ + + /** + @module ember + @submodule ember-routing + */ + + var OutletView = ContainerView.extend(_Metamorph); + __exports__.OutletView = OutletView; + /** + The `outlet` helper is a placeholder that the router will fill in with + the appropriate template based on the current state of the application. + + ``` handlebars + {{outlet}} + ``` + + By default, a template based on Ember's naming conventions will be rendered + into the `outlet` (e.g. `App.PostsRoute` will render the `posts` template). + + You can render a different template by using the `render()` method in the + route's `renderTemplate` hook. The following will render the `favoritePost` + template into the `outlet`. + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost'); + } + }); + ``` + + You can create custom named outlets for more control. + + ``` handlebars + {{outlet 'favoritePost'}} + {{outlet 'posts'}} + ``` + + Then you can define what template is rendered into each outlet in your + route. + + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost', { outlet: 'favoritePost' }); + this.render('posts', { outlet: 'posts' }); + } + }); + ``` + + You can specify the view that the outlet uses to contain and manage the + templates rendered into it. + + ``` handlebars + {{outlet view='sectionContainer'}} + ``` + + ``` javascript + App.SectionContainer = Ember.ContainerView.extend({ + tagName: 'section', + classNames: ['special'] + }); + ``` + + @method outlet + @for Ember.Handlebars.helpers + @param {String} property the property on the controller + that holds the view for this outlet + @return {String} HTML string + */ + function outletHelper(property, options) { + var outletSource; + var container; + var viewName; + var viewClass; + var viewFullName; + + if (property && property.data && property.data.isRenderData) { + options = property; + property = 'main'; + } + + container = options.data.view.container; + + outletSource = options.data.view; + while (!outletSource.get('template.isTop')) { + outletSource = outletSource.get('_parentView'); + } + + // provide controller override + viewName = options.hash.view; + + if (viewName) { + viewFullName = 'view:' + viewName; + Ember.assert("Using a quoteless view parameter with {{outlet}} is not supported. Please update to quoted usage '{{outlet \"" + viewName + "\"}}.", options.hashTypes.view !== 'ID'); + Ember.assert("The view name you supplied '" + viewName + "' did not resolve to a view.", container.has(viewFullName)); + } + + viewClass = viewName ? container.lookupFactory(viewFullName) : options.hash.viewClass || OutletView; + + options.data.view.set('outletSource', outletSource); + options.hash.currentViewBinding = '_view.outletSource._outlets.' + property; + + options.helperName = options.helperName || 'outlet'; + + return viewHelper.call(this, viewClass, options); + } + + __exports__.outletHelper = outletHelper; + }); +define("ember-routing-handlebars/helpers/render", + ["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-routing/system/generate_controller","ember-handlebars/ext","ember-handlebars/helpers/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // assert, deprecate + var EmberError = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var camelize = __dependency5__.camelize; + var generateControllerFactory = __dependency6__.generateControllerFactory; + var generateController = __dependency6__["default"]; + var handlebarsGet = __dependency7__.handlebarsGet; + var ViewHelper = __dependency8__.ViewHelper; + + + /** + @module ember + @submodule ember-routing + */ + + /** + Calling ``{{render}}`` from within a template will insert another + template that matches the provided name. The inserted template will + access its properties on its own controller (rather than the controller + of the parent template). + + If a view class with the same name exists, the view class also will be used. + + Note: A given controller may only be used *once* in your app in this manner. + A singleton instance of the controller will be created for you. + + Example: + + ```javascript + App.NavigationController = Ember.Controller.extend({ + who: "world" + }); + ``` + + ```handlebars + + Hello, {{who}}. + ``` + + ```handelbars + +

    My great app

    + {{render "navigation"}} + ``` + + ```html +

    My great app

    +
    + Hello, world. +
    + ``` + + Optionally you may provide a second argument: a property path + that will be bound to the `model` property of the controller. + + If a `model` property path is specified, then a new instance of the + controller will be created and `{{render}}` can be used multiple times + with the same name. + + For example if you had this `author` template. + + ```handlebars +
    + Written by {{firstName}} {{lastName}}. + Total Posts: {{postCount}} +
    + ``` + + You could render it inside the `post` template using the `render` helper. + + ```handlebars +
    +

    {{title}}

    +
    {{body}}
    + {{render "author" author}} +
    + ``` + + @method render + @for Ember.Handlebars.helpers + @param {String} name + @param {Object?} contextString + @param {Hash} options + @return {String} HTML string + */ + __exports__["default"] = function renderHelper(name, contextString, options) { + var length = arguments.length; + var contextProvided = length === 3; + var container, router, controller, view, context, lookupOptions; + + container = (options || contextString).data.keywords.controller.container; + router = container.lookup('router:main'); + + if (length === 2) { + // use the singleton controller + options = contextString; + contextString = undefined; + Ember.assert("You can only use the {{render}} helper once without a model object as its second argument, as in {{render \"post\" post}}.", !router || !router._lookupActiveView(name)); + } else if (length === 3) { + // create a new controller + context = handlebarsGet(options.contexts[1], contextString, options); + } else { + throw new EmberError("You must pass a templateName to render"); + } + + Ember.deprecate("Using a quoteless parameter with {{render}} is deprecated. Please update to quoted usage '{{render \"" + name + "\"}}.", options.types[0] !== 'ID'); + + // # legacy namespace + name = name.replace(/\//g, '.'); + // \ legacy slash as namespace support + + + view = container.lookup('view:' + name) || container.lookup('view:default'); + + // provide controller override + var controllerName = options.hash.controller || name; + var controllerFullName = 'controller:' + controllerName; + + if (options.hash.controller) { + Ember.assert("The controller name you supplied '" + controllerName + "' did not resolve to a controller.", container.has(controllerFullName)); + } + + var parentController = options.data.keywords.controller; + + // choose name + if (length > 2) { + var factory = container.lookupFactory(controllerFullName) || + generateControllerFactory(container, controllerName, context); + + controller = factory.create({ + model: context, + parentController: parentController, + target: parentController + }); + + view.one('willDestroyElement', function() { + controller.destroy(); + }); + } else { + controller = container.lookup(controllerFullName) || + generateController(container, controllerName); + + controller.setProperties({ + target: parentController, + parentController: parentController + }); + } + + var root = options.contexts[1]; + + if (root) { + view.registerObserver(root, contextString, function() { + controller.set('model', handlebarsGet(root, contextString, options)); + }); + } + + options.hash.viewName = camelize(name); + + var templateName = 'template:' + name; + Ember.assert("You used `{{render '" + name + "'}}`, but '" + name + "' can not be found as either a template or a view.", container.has("view:" + name) || container.has(templateName) || options.fn); + options.hash.template = container.lookup(templateName); + + options.hash.controller = controller; + + if (router && !context) { + router._connectActiveView(name, view); + } + + options.helperName = options.helperName || ('render "' + name + '"'); + + ViewHelper.instanceHelper(this, view, options); + } + }); +define("ember-routing-handlebars/helpers/shared", + ["ember-metal/property_get","ember-metal/array","ember-runtime/mixins/controller","ember-handlebars/ext","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var map = __dependency2__.map; + var ControllerMixin = __dependency3__["default"]; + var handlebarsResolve = __dependency4__.resolveParams; + var handlebarsGet = __dependency4__.handlebarsGet; + var typeOf = __dependency5__.typeOf; + var get = __dependency1__.get; + + function routeArgs(targetRouteName, models, queryParams) { + var args = []; + if (typeOf(targetRouteName) === 'string') { + args.push('' + targetRouteName); + } + args.push.apply(args, models); + args.push({ queryParams: queryParams }); + return args; + } + + __exports__.routeArgs = routeArgs;function getActiveTargetName(router) { + var handlerInfos = router.activeTransition ? + router.activeTransition.state.handlerInfos : + router.state.handlerInfos; + return handlerInfos[handlerInfos.length - 1].name; + } + + __exports__.getActiveTargetName = getActiveTargetName;function resolveParams(context, params, options) { + return map.call(resolvePaths(context, params, options), function(path, i) { + if (null === path) { + // Param was string/number, not a path, so just return raw string/number. + return params[i]; + } else { + return handlebarsGet(context, path, options); + } + }); + } + + __exports__.resolveParams = resolveParams;function stashParamNames(router, handlerInfos) { + if (handlerInfos._namesStashed) { return; } + + // This helper exists because router.js/route-recognizer.js awkwardly + // keeps separate a handlerInfo's list of parameter names depending + // on whether a URL transition or named transition is happening. + // Hopefully we can remove this in the future. + var targetRouteName = handlerInfos[handlerInfos.length-1].name; + var recogHandlers = router.router.recognizer.handlersFor(targetRouteName); + var dynamicParent = null; + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + var names = recogHandlers[i].names; + + if (names.length) { + dynamicParent = handlerInfo; + } + + handlerInfo._names = names; + + var route = handlerInfo.handler; + route._stashNames(handlerInfo, dynamicParent); + } + + handlerInfos._namesStashed = true; + } + + __exports__.stashParamNames = stashParamNames;function resolvePaths(context, params, options) { + var resolved = handlebarsResolve(context, params, options); + var types = options.types; + + return map.call(resolved, function(object, i) { + if (types[i] === 'ID') { + return unwrap(object, params[i]); + } else { + return null; + } + }); + + function unwrap(object, path) { + if (path === 'controller') { return path; } + + if (ControllerMixin.detect(object)) { + return unwrap(get(object, 'model'), path ? path + '.model' : 'model'); + } else { + return path; + } + } + } + + __exports__.resolvePaths = resolvePaths; + }); +define("ember-routing", + ["ember-handlebars","ember-metal/core","ember-routing/ext/run_loop","ember-routing/ext/controller","ember-routing/ext/view","ember-routing/location/api","ember-routing/location/none_location","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/system/generate_controller","ember-routing/system/controller_for","ember-routing/system/dsl","ember-routing/system/router","ember-routing/system/route","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { + "use strict"; + /** + Ember Routing + + @module ember + @submodule ember-routing + @requires ember-views + */ + + var EmberHandlebars = __dependency1__["default"]; + var Ember = __dependency2__["default"]; + + // ES6TODO: Cleanup modules with side-effects below + + var EmberLocation = __dependency6__["default"]; + var NoneLocation = __dependency7__["default"]; + var HashLocation = __dependency8__["default"]; + var HistoryLocation = __dependency9__["default"]; + var AutoLocation = __dependency10__["default"]; + + var generateControllerFactory = __dependency11__.generateControllerFactory; + var generateController = __dependency11__["default"]; + var controllerFor = __dependency12__["default"]; + var RouterDSL = __dependency13__["default"]; + var Router = __dependency14__["default"]; + var Route = __dependency15__["default"]; + + Ember.Location = EmberLocation; + Ember.AutoLocation = AutoLocation; + Ember.HashLocation = HashLocation; + Ember.HistoryLocation = HistoryLocation; + Ember.NoneLocation = NoneLocation; + + Ember.controllerFor = controllerFor; + Ember.generateControllerFactory = generateControllerFactory; + Ember.generateController = generateController; + Ember.RouterDSL = RouterDSL; + Ember.Router = Router; + Ember.Route = Route; + + __exports__["default"] = Ember; + }); +define("ember-routing/ext/controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/merge","ember-metal/enumerable_utils","ember-runtime/mixins/controller","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, deprecate + var get = __dependency2__.get; + var set = __dependency3__.set; + var computed = __dependency4__.computed; + var typeOf = __dependency5__.typeOf; + var meta = __dependency5__.meta; + var merge = __dependency6__["default"]; + var map = __dependency7__.map; + + var ControllerMixin = __dependency8__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + ControllerMixin.reopen({ + concatenatedProperties: ['queryParams', '_pCacheMeta'], + + init: function() { + this._super.apply(this, arguments); + listenForQueryParamChanges(this); + }, + + /** + @property queryParams + @public + */ + queryParams: null, + + /** + @property _qpDelegate + @private + */ + _qpDelegate: null, + + /** + @property _normalizedQueryParams + @private + */ + _normalizedQueryParams: computed(function() { + var m = meta(this); + if (m.proto !== this) { + return get(m.proto, '_normalizedQueryParams'); + } + + var queryParams = get(this, 'queryParams'); + if (queryParams._qpMap) { + return queryParams._qpMap; + } + + var qpMap = queryParams._qpMap = {}; + + for (var i = 0, len = queryParams.length; i < len; ++i) { + accumulateQueryParamDescriptors(queryParams[i], qpMap); + } + + return qpMap; + }), + + /** + @property _cacheMeta + @private + */ + _cacheMeta: computed(function() { + var m = meta(this); + if (m.proto !== this) { + return get(m.proto, '_cacheMeta'); + } + + var cacheMeta = {}; + var qpMap = get(this, '_normalizedQueryParams'); + for (var prop in qpMap) { + if (!qpMap.hasOwnProperty(prop)) { continue; } + + var qp = qpMap[prop]; + var scope = qp.scope; + var parts; + + if (scope === 'controller') { + parts = []; + } + + cacheMeta[prop] = { + parts: parts, // provided by route if 'model' scope + values: null, // provided by route + scope: scope, + prefix: "", + def: get(this, prop) + }; + } + + return cacheMeta; + }), + + /** + @method _updateCacheParams + @private + */ + _updateCacheParams: function(params) { + var cacheMeta = get(this, '_cacheMeta'); + for (var prop in cacheMeta) { + if (!cacheMeta.hasOwnProperty(prop)) { continue; } + var propMeta = cacheMeta[prop]; + propMeta.values = params; + + var cacheKey = this._calculateCacheKey(propMeta.prefix, propMeta.parts, propMeta.values); + var cache = this._bucketCache; + + if (cache) { + var value = cache.lookup(cacheKey, prop, propMeta.def); + set(this, prop, value); + } + } + }, + + /** + @method _qpChanged + @private + */ + _qpChanged: function(controller, _prop) { + var prop = _prop.substr(0, _prop.length-3); + var cacheMeta = get(controller, '_cacheMeta'); + var propCache = cacheMeta[prop]; + var cacheKey = controller._calculateCacheKey(propCache.prefix || "", propCache.parts, propCache.values); + var value = get(controller, prop); + + // 1. Update model-dep cache + var cache = this._bucketCache; + if (cache) { + controller._bucketCache.stash(cacheKey, prop, value); + } + + // 2. Notify a delegate (e.g. to fire a qp transition) + var delegate = controller._qpDelegate; + if (delegate) { + delegate(controller, prop); + } + }, + + /** + @method _calculateCacheKey + @private + */ + _calculateCacheKey: function(prefix, _parts, values) { + var parts = _parts || [], suffixes = ""; + for (var i = 0, len = parts.length; i < len; ++i) { + var part = parts[i]; + var value = get(values, part); + suffixes += "::" + part + ":" + value; + } + return prefix + suffixes.replace(ALL_PERIODS_REGEX, '-'); + }, + + /** + Transition the application into another route. The route may + be either a single route or route path: + + ```javascript + aController.transitionToRoute('blogPosts'); + aController.transitionToRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.transitionToRoute('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + aController.transitionToRoute('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + aController.transitionToRoute('blogComment', aPost, aComment); + aController.transitionToRoute('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + aController.transitionToRoute('/'); + aController.transitionToRoute('/blog/post/1/comment/13'); + ``` + + See also [replaceRoute](/api/classes/Ember.ControllerMixin.html#method_replaceRoute). + + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used + while transitioning to the route. + @for Ember.ControllerMixin + @method transitionToRoute + */ + transitionToRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'); + var method = target.transitionToRoute || target.transitionTo; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method transitionTo + */ + transitionTo: function() { + Ember.deprecate("transitionTo is deprecated. Please use transitionToRoute."); + return this.transitionToRoute.apply(this, arguments); + }, + + /** + Transition into another route while replacing the current URL, if possible. + This will replace the current history entry instead of adding a new one. + Beside that, it is identical to `transitionToRoute` in all other respects. + + ```javascript + aController.replaceRoute('blogPosts'); + aController.replaceRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.replaceRoute('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + aController.replaceRoute('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + aController.replaceRoute('blogComment', aPost, aComment); + aController.replaceRoute('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + aController.replaceRoute('/'); + aController.replaceRoute('/blog/post/1/comment/13'); + ``` + + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used + while transitioning to the route. + @for Ember.ControllerMixin + @method replaceRoute + */ + replaceRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'); + var method = target.replaceRoute || target.replaceWith; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method replaceWith + */ + replaceWith: function() { + Ember.deprecate("replaceWith is deprecated. Please use replaceRoute."); + return this.replaceRoute.apply(this, arguments); + } + }); + + var ALL_PERIODS_REGEX = /\./g; + + function accumulateQueryParamDescriptors(_desc, accum) { + var desc = _desc, tmp; + if (typeOf(desc) === 'string') { + tmp = {}; + tmp[desc] = { as: null }; + desc = tmp; + } + + for (var key in desc) { + if (!desc.hasOwnProperty(key)) { return; } + + var singleDesc = desc[key]; + if (typeOf(singleDesc) === 'string') { + singleDesc = { as: singleDesc }; + } + + tmp = accum[key] || { as: null, scope: 'model' }; + merge(tmp, singleDesc); + + accum[key] = tmp; + } + } + + function listenForQueryParamChanges(controller) { + var qpMap = get(controller, '_normalizedQueryParams'); + for (var prop in qpMap) { + if (!qpMap.hasOwnProperty(prop)) { continue; } + controller.addObserver(prop + '.[]', controller, controller._qpChanged); + } + } + + + __exports__["default"] = ControllerMixin; + }); +define("ember-routing/ext/run_loop", + ["ember-metal/run_loop"], + function(__dependency1__) { + "use strict"; + var run = __dependency1__["default"]; + + /** + @module ember + @submodule ember-views + */ + + // Add a new named queue after the 'actions' queue (where RSVP promises + // resolve), which is used in router transitions to prevent unnecessary + // loading state entry if all context promises resolve on the + // 'actions' queue first. + + var queues = run.queues; + run._addQueue('routerTransitions', 'actions'); + }); +define("ember-routing/ext/view", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-views/views/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var run = __dependency3__["default"]; + var EmberView = __dependency4__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + EmberView.reopen({ + + /** + Sets the private `_outlets` object on the view. + + @method init + */ + init: function() { + set(this, '_outlets', {}); + this._super(); + }, + + /** + Manually fill any of a view's `{{outlet}}` areas with the + supplied view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // The html for myView now looks like: + //
    Child view:
    + + var FooView = Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + }); + var fooView = FooView.create(); + myView.connectOutlet('main', fooView); + // The html for myView now looks like: + //
    Child view: + //

    Foo

    + //
    + ``` + @method connectOutlet + @param {String} outletName A unique name for the outlet + @param {Object} view An Ember.View + */ + connectOutlet: function(outletName, view) { + if (this._pendingDisconnections) { + delete this._pendingDisconnections[outletName]; + } + + if (this._hasEquivalentView(outletName, view)) { + view.destroy(); + return; + } + + var outlets = get(this, '_outlets'); + var container = get(this, 'container'); + var router = container && container.lookup('router:main'); + var renderedName = get(view, 'renderedName'); + + set(outlets, outletName, view); + + if (router && renderedName) { + router._connectActiveView(renderedName, view); + } + }, + + /** + Determines if the view has already been created by checking if + the view has the same constructor, template, and context as the + view in the `_outlets` object. + + @private + @method _hasEquivalentView + @param {String} outletName The name of the outlet we are checking + @param {Object} view An Ember.View + @return {Boolean} + */ + _hasEquivalentView: function(outletName, view) { + var existingView = get(this, '_outlets.'+outletName); + return existingView && + existingView.constructor === view.constructor && + existingView.get('template') === view.get('template') && + existingView.get('context') === view.get('context'); + }, + + /** + Removes an outlet from the view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // myView's html: + //
    Child view:
    + + var FooView = Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + }); + var fooView = FooView.create(); + myView.connectOutlet('main', fooView); + // myView's html: + //
    Child view: + //

    Foo

    + //
    + + myView.disconnectOutlet('main'); + // myView's html: + //
    Child view:
    + ``` + + @method disconnectOutlet + @param {String} outletName The name of the outlet to be removed + */ + disconnectOutlet: function(outletName) { + if (!this._pendingDisconnections) { + this._pendingDisconnections = {}; + } + this._pendingDisconnections[outletName] = true; + run.once(this, '_finishDisconnections'); + }, + + /** + Gets an outlet that is pending disconnection and then + nullifys the object on the `_outlet` object. + + @private + @method _finishDisconnections + */ + _finishDisconnections: function() { + if (this.isDestroyed) return; // _outlets will be gone anyway + var outlets = get(this, '_outlets'); + var pendingDisconnections = this._pendingDisconnections; + this._pendingDisconnections = null; + + for (var outletName in pendingDisconnections) { + set(outlets, outletName, null); + } + } + }); + + __exports__["default"] = EmberView; + }); +define("ember-routing/location/api", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // deprecate, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.Location returns an instance of the correct implementation of + the `location` API. + + ## Implementations + + You can pass an implementation name (`hash`, `history`, `none`) to force a + particular implementation to be used in your application. + + ### HashLocation + + Using `HashLocation` results in URLs with a `#` (hash sign) separating the + server side URL portion of the URL from the portion that is used by Ember. + This relies upon the `hashchange` event existing in the browser. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'hash' + }); + ``` + + This will result in a posts.new url of `/#/posts/new`. + + ### HistoryLocation + + Using `HistoryLocation` results in URLs that are indistinguishable from a + standard URL. This relies upon the browser's `history` API. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'history' + }); + ``` + + This will result in a posts.new url of `/posts/new`. + + Keep in mind that your server must serve the Ember app at all the routes you + define. + + ### AutoLocation + + Using `AutoLocation`, the router will use the best Location class supported by + the browser it is running in. + + Browsers that support the `history` API will use `HistoryLocation`, those that + do not, but still support the `hashchange` event will use `HashLocation`, and + in the rare case neither is supported will use `NoneLocation`. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'auto' + }); + ``` + + This will result in a posts.new url of `/posts/new` for modern browsers that + support the `history` api or `/#/posts/new` for older ones, like Internet + Explorer 9 and below. + + When a user visits a link to your application, they will be automatically + upgraded or downgraded to the appropriate `Location` class, with the URL + transformed accordingly, if needed. + + Keep in mind that since some of your users will use `HistoryLocation`, your + server must serve the Ember app at all the routes you define. + + ### NoneLocation + + Using `NoneLocation` causes Ember to not store the applications URL state + in the actual URL. This is generally used for testing purposes, and is one + of the changes made when calling `App.setupForTesting()`. + + ## Location API + + Each location implementation must provide the following methods: + + * implementation: returns the string name used to reference the implementation. + * getURL: returns the current URL. + * setURL(path): sets the current URL. + * replaceURL(path): replace the current URL (optional). + * onUpdateURL(callback): triggers the callback when the URL changes. + * formatURL(url): formats `url` to be placed into `href` attribute. + + Calling setURL or replaceURL will not trigger onUpdateURL callbacks. + + @class Location + @namespace Ember + @static + */ + __exports__["default"] = { + /** + This is deprecated in favor of using the container to lookup the location + implementation as desired. + + For example: + + ```javascript + // Given a location registered as follows: + container.register('location:history-test', HistoryTestLocation); + + // You could create a new instance via: + container.lookup('location:history-test'); + ``` + + @method create + @param {Object} options + @return {Object} an instance of an implementation of the `location` API + @deprecated Use the container to lookup the location implementation that you + need. + */ + create: function(options) { + var implementation = options && options.implementation; + Ember.assert("Ember.Location.create: you must specify a 'implementation' option", !!implementation); + + var implementationClass = this.implementations[implementation]; + Ember.assert("Ember.Location.create: " + implementation + " is not a valid implementation", !!implementationClass); + + return implementationClass.create.apply(implementationClass, arguments); + }, + + /** + This is deprecated in favor of using the container to register the + location implementation as desired. + + Example: + + ```javascript + Application.initializer({ + name: "history-test-location", + + initialize: function(container, application) { + application.register('location:history-test', HistoryTestLocation); + } + }); + ``` + + @method registerImplementation + @param {String} name + @param {Object} implementation of the `location` API + @deprecated Register your custom location implementation with the + container directly. + */ + registerImplementation: function(name, implementation) { + Ember.deprecate('Using the Ember.Location.registerImplementation is no longer supported. Register your custom location implementation with the container instead.', false); + + this.implementations[name] = implementation; + }, + + implementations: {}, + _location: window.location, + + /** + Returns the current `location.hash` by parsing location.href since browsers + inconsistently URL-decode `location.hash`. + + https://bugzilla.mozilla.org/show_bug.cgi?id=483304 + + @private + @method getHash + @since 1.4.0 + */ + _getHash: function () { + // AutoLocation has it at _location, HashLocation at .location. + // Being nice and not changing + var href = (this._location || this.location).href; + var hashIndex = href.indexOf('#'); + + if (hashIndex === -1) { + return ''; + } else { + return href.substr(hashIndex); + } + } + }; + }); +define("ember-routing/location/auto_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-routing/location/api","ember-routing/location/history_location","ember-routing/location/hash_location","ember-routing/location/none_location","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES + var get = __dependency2__.get; + var set = __dependency3__.set; + + var EmberLocation = __dependency4__["default"]; + var HistoryLocation = __dependency5__["default"]; + var HashLocation = __dependency6__["default"]; + var NoneLocation = __dependency7__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.AutoLocation will select the best location option based off browser + support with the priority order: history, hash, none. + + Clean pushState paths accessed by hashchange-only browsers will be redirected + to the hash-equivalent and vice versa so future transitions are consistent. + + Keep in mind that since some of your users will use `HistoryLocation`, your + server must serve the Ember app at all the routes you define. + + @class AutoLocation + @namespace Ember + @static + */ + __exports__["default"] = { + + /** + @private + + This property is used by router:main to know whether to cancel the routing + setup process, which is needed while we redirect the browser. + + @since 1.5.1 + @property cancelRouterSetup + @default false + */ + cancelRouterSetup: false, + + /** + @private + + Will be pre-pended to path upon state change. + + @since 1.5.1 + @property rootURL + @default '/' + */ + rootURL: '/', + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _window + @default window + */ + _window: window, + + /** + @private + + Attached for mocking in tests + + @property location + @default window.location + */ + _location: window.location, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _history + @default window.history + */ + _history: window.history, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _HistoryLocation + @default Ember.HistoryLocation + */ + _HistoryLocation: HistoryLocation, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _HashLocation + @default Ember.HashLocation + */ + _HashLocation: HashLocation, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _NoneLocation + @default Ember.NoneLocation + */ + _NoneLocation: NoneLocation, + + /** + @private + + Returns location.origin or builds it if device doesn't support it. + + @method _getOrigin + */ + _getOrigin: function () { + var location = this._location; + var origin = location.origin; + + // Older browsers, especially IE, don't have origin + if (!origin) { + origin = location.protocol + '//' + location.hostname; + + if (location.port) { + origin += ':' + location.port; + } + } + + return origin; + }, + + /** + @private + + We assume that if the history object has a pushState method, the host should + support HistoryLocation. + + @method _getSupportsHistory + */ + _getSupportsHistory: function () { + // Boosted from Modernizr: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js + // The stock browser on Android 2.2 & 2.3 returns positive on history support + // Unfortunately support is really buggy and there is no clean way to detect + // these bugs, so we fall back to a user agent sniff :( + var userAgent = this._window.navigator.userAgent; + + // We only want Android 2, stock browser, and not Chrome which identifies + // itself as 'Mobile Safari' as well + if (userAgent.indexOf('Android 2') !== -1 && + userAgent.indexOf('Mobile Safari') !== -1 && + userAgent.indexOf('Chrome') === -1) { + return false; + } + + return !!(this._history && 'pushState' in this._history); + }, + + /** + @private + + IE8 running in IE7 compatibility mode gives false positive, so we must also + check documentMode. + + @method _getSupportsHashChange + */ + _getSupportsHashChange: function () { + var _window = this._window; + var documentMode = _window.document.documentMode; + + return ('onhashchange' in _window && (documentMode === undefined || documentMode > 7 )); + }, + + /** + @private + + Redirects the browser using location.replace, prepending the locatin.origin + to prevent phishing attempts + + @method _replacePath + */ + _replacePath: function (path) { + this._location.replace(this._getOrigin() + path); + }, + + /** + @since 1.5.1 + @private + @method _getRootURL + */ + _getRootURL: function () { + return this.rootURL; + }, + + /** + @private + + Returns the current `location.pathname`, normalized for IE inconsistencies. + + @method _getPath + */ + _getPath: function () { + var pathname = this._location.pathname; + // Various versions of IE/Opera don't always return a leading slash + if (pathname.charAt(0) !== '/') { + pathname = '/' + pathname; + } + + return pathname; + }, + + /** + @private + + Returns normalized location.hash as an alias to Ember.Location._getHash + + @since 1.5.1 + @method _getHash + */ + _getHash: EmberLocation._getHash, + + /** + @private + + Returns location.search + + @since 1.5.1 + @method _getQuery + */ + _getQuery: function () { + return this._location.search; + }, + + /** + @private + + Returns the full pathname including query and hash + + @method _getFullPath + */ + _getFullPath: function () { + return this._getPath() + this._getQuery() + this._getHash(); + }, + + /** + @private + + Returns the current path as it should appear for HistoryLocation supported + browsers. This may very well differ from the real current path (e.g. if it + starts off as a hashed URL) + + @method _getHistoryPath + */ + _getHistoryPath: function () { + var rootURL = this._getRootURL(); + var path = this._getPath(); + var hash = this._getHash(); + var query = this._getQuery(); + var rootURLIndex = path.indexOf(rootURL); + var routeHash, hashParts; + + Ember.assert('Path ' + path + ' does not start with the provided rootURL ' + rootURL, rootURLIndex === 0); + + // By convention, Ember.js routes using HashLocation are required to start + // with `#/`. Anything else should NOT be considered a route and should + // be passed straight through, without transformation. + if (hash.substr(0, 2) === '#/') { + // There could be extra hash segments after the route + hashParts = hash.substr(1).split('#'); + // The first one is always the route url + routeHash = hashParts.shift(); + + // If the path already has a trailing slash, remove the one + // from the hashed route so we don't double up. + if (path.slice(-1) === '/') { + routeHash = routeHash.substr(1); + } + + // This is the "expected" final order + path += routeHash; + path += query; + + if (hashParts.length) { + path += '#' + hashParts.join('#'); + } + } else { + path += query; + path += hash; + } + + return path; + }, + + /** + @private + + Returns the current path as it should appear for HashLocation supported + browsers. This may very well differ from the real current path. + + @method _getHashPath + */ + _getHashPath: function () { + var rootURL = this._getRootURL(); + var path = rootURL; + var historyPath = this._getHistoryPath(); + var routePath = historyPath.substr(rootURL.length); + + if (routePath !== '') { + if (routePath.charAt(0) !== '/') { + routePath = '/' + routePath; + } + + path += '#' + routePath; + } + + return path; + }, + + /** + Selects the best location option based off browser support and returns an + instance of that Location class. + + @see Ember.AutoLocation + @method create + */ + create: function (options) { + if (options && options.rootURL) { + Ember.assert('rootURL must end with a trailing forward slash e.g. "/app/"', options.rootURL.charAt(options.rootURL.length-1) === '/'); + this.rootURL = options.rootURL; + } + + var historyPath, hashPath; + var cancelRouterSetup = false; + var implementationClass = this._NoneLocation; + var currentPath = this._getFullPath(); + + if (this._getSupportsHistory()) { + historyPath = this._getHistoryPath(); + + // Since we support history paths, let's be sure we're using them else + // switch the location over to it. + if (currentPath === historyPath) { + implementationClass = this._HistoryLocation; + } else { + + if (currentPath.substr(0, 2) === '/#') { + this._history.replaceState({ path: historyPath }, null, historyPath); + implementationClass = this._HistoryLocation; + } else { + cancelRouterSetup = true; + this._replacePath(historyPath); + } + } + + } else if (this._getSupportsHashChange()) { + hashPath = this._getHashPath(); + + // Be sure we're using a hashed path, otherwise let's switch over it to so + // we start off clean and consistent. We'll count an index path with no + // hash as "good enough" as well. + if (currentPath === hashPath || (currentPath === '/' && hashPath === '/#/')) { + implementationClass = this._HashLocation; + } else { + // Our URL isn't in the expected hash-supported format, so we want to + // cancel the router setup and replace the URL to start off clean + cancelRouterSetup = true; + this._replacePath(hashPath); + } + } + + var implementation = implementationClass.create.apply(implementationClass, arguments); + + if (cancelRouterSetup) { + set(implementation, 'cancelRouterSetup', true); + } + + return implementation; + } + }; + }); +define("ember-routing/location/hash_location", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/object","ember-routing/location/api","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var run = __dependency3__["default"]; + var guidFor = __dependency4__.guidFor; + + var EmberObject = __dependency5__["default"]; + var EmberLocation = __dependency6__["default"]; + var jQuery = __dependency7__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + `Ember.HashLocation` implements the location API using the browser's + hash. At present, it relies on a `hashchange` event existing in the + browser. + + @class HashLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'hash', + + init: function() { + set(this, 'location', get(this, '_location') || window.location); + }, + + /** + @private + + Returns normalized location.hash + + @since 1.5.1 + @method getHash + */ + getHash: EmberLocation._getHash, + + /** + Returns the current `location.hash`, minus the '#' at the front. + + @private + @method getURL + */ + getURL: function() { + return this.getHash().substr(1); + }, + + /** + Set the `location.hash` and remembers what was set. This prevents + `onUpdateURL` callbacks from triggering when the hash was set by + `HashLocation`. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + get(this, 'location').hash = path; + set(this, 'lastSetURL', path); + }, + + /** + Uses location.replace to update the url without a page reload + or history modification. + + @private + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + get(this, 'location').replace('#' + path); + set(this, 'lastSetURL', path); + }, + + /** + Register a callback to be invoked when the hash changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var self = this; + var guid = guidFor(this); + + jQuery(window).on('hashchange.ember-location-'+guid, function() { + run(function() { + var path = self.getURL(); + if (get(self, 'lastSetURL') === path) { return; } + + set(self, 'lastSetURL', null); + + callback(path); + }); + }); + }, + + /** + Given a URL, formats it to be placed into the page as part + of an element's `href` attribute. + + This is used, for example, when using the {{action}} helper + to generate a URL based on an event. + + @private + @method formatURL + @param url {String} + */ + formatURL: function(url) { + return '#' + url; + }, + + /** + Cleans up the HashLocation event listener. + + @private + @method willDestroy + */ + willDestroy: function() { + var guid = guidFor(this); + + jQuery(window).off('hashchange.ember-location-'+guid); + } + }); + }); +define("ember-routing/location/history_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-runtime/system/object","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + + var EmberObject = __dependency5__["default"]; + var jQuery = __dependency6__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + var popstateFired = false; + var supportsHistoryState = window.history && 'state' in window.history; + + /** + Ember.HistoryLocation implements the location API using the browser's + history.pushState API. + + @class HistoryLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'history', + + init: function() { + set(this, 'location', get(this, 'location') || window.location); + set(this, 'baseURL', jQuery('base').attr('href') || ''); + }, + + /** + Used to set state on first call to setURL + + @private + @method initState + */ + initState: function() { + set(this, 'history', get(this, 'history') || window.history); + this.replaceState(this.formatURL(this.getURL())); + }, + + /** + Will be pre-pended to path upon state change + + @property rootURL + @default '/' + */ + rootURL: '/', + + /** + Returns the current `location.pathname` without `rootURL` or `baseURL` + + @private + @method getURL + @return url {String} + */ + getURL: function() { + var rootURL = get(this, 'rootURL'); + var location = get(this, 'location'); + var path = location.pathname; + var baseURL = get(this, 'baseURL'); + + rootURL = rootURL.replace(/\/$/, ''); + baseURL = baseURL.replace(/\/$/, ''); + + var url = path.replace(baseURL, '').replace(rootURL, ''); + var search = location.search || ''; + + url += search; + + return url; + }, + + /** + Uses `history.pushState` to update the url without a page reload. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (!state || state.path !== path) { + this.pushState(path); + } + }, + + /** + Uses `history.replaceState` to update the url without a page reload + or history modification. + + @private + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (!state || state.path !== path) { + this.replaceState(path); + } + }, + + /** + Get the current `history.state`. Checks for if a polyfill is + required and if so fetches this._historyState. The state returned + from getState may be null if an iframe has changed a window's + history. + + @private + @method getState + @return state {Object} + */ + getState: function() { + return supportsHistoryState ? get(this, 'history').state : this._historyState; + }, + + /** + Pushes a new state. + + @private + @method pushState + @param path {String} + */ + pushState: function(path) { + var state = { path: path }; + + get(this, 'history').pushState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + Replaces the current state. + + @private + @method replaceState + @param path {String} + */ + replaceState: function(path) { + var state = { path: path }; + + get(this, 'history').replaceState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + Register a callback to be invoked whenever the browser + history changes, including using forward and back buttons. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var guid = guidFor(this); + var self = this; + + jQuery(window).on('popstate.ember-location-'+guid, function(e) { + // Ignore initial page load popstate event in Chrome + if (!popstateFired) { + popstateFired = true; + if (self.getURL() === self._previousURL) { return; } + } + callback(self.getURL()); + }); + }, + + /** + Used when using `{{action}}` helper. The url is always appended to the rootURL. + + @private + @method formatURL + @param url {String} + @return formatted url {String} + */ + formatURL: function(url) { + var rootURL = get(this, 'rootURL'); + var baseURL = get(this, 'baseURL'); + + if (url !== '') { + rootURL = rootURL.replace(/\/$/, ''); + baseURL = baseURL.replace(/\/$/, ''); + } else if(baseURL.match(/^\//) && rootURL.match(/^\//)) { + baseURL = baseURL.replace(/\/$/, ''); + } + + return baseURL + rootURL + url; + }, + + /** + Cleans up the HistoryLocation event listener. + + @private + @method willDestroy + */ + willDestroy: function() { + var guid = guidFor(this); + + jQuery(window).off('popstate.ember-location-'+guid); + } + }); + }); +define("ember-routing/location/none_location", + ["ember-metal/property_get","ember-metal/property_set","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var EmberObject = __dependency3__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.NoneLocation does not interact with the browser. It is useful for + testing, or when you need to manage state with your Router, but temporarily + don't want it to muck with the URL (for example when you embed your + application in a larger page). + + @class NoneLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'none', + path: '', + + /** + Returns the current path. + + @private + @method getURL + @return {String} path + */ + getURL: function() { + return get(this, 'path'); + }, + + /** + Set the path and remembers what was set. Using this method + to change the path will not invoke the `updateURL` callback. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + set(this, 'path', path); + }, + + /** + Register a callback to be invoked when the path changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + this.updateCallback = callback; + }, + + /** + Sets the path and calls the `updateURL` callback. + + @private + @method handleURL + @param callback {Function} + */ + handleURL: function(url) { + set(this, 'path', url); + this.updateCallback(url); + }, + + /** + Given a URL, formats it to be placed into the page as part + of an element's `href` attribute. + + This is used, for example, when using the {{action}} helper + to generate a URL based on an event. + + @private + @method formatURL + @param url {String} + @return {String} url + */ + formatURL: function(url) { + // The return value is not overly meaningful, but we do not want to throw + // errors when test code renders templates containing {{action href=true}} + // helpers. + return url; + } + }); + }); +define("ember-routing/system/cache", + ["ember-runtime/system/object","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + + __exports__["default"] = EmberObject.extend({ + init: function() { + this.cache = {}; + }, + has: function(bucketKey) { + return bucketKey in this.cache; + }, + stash: function(bucketKey, key, value) { + var bucket = this.cache[bucketKey]; + if (!bucket) { + bucket = this.cache[bucketKey] = {}; + } + bucket[key] = value; + }, + lookup: function(bucketKey, prop, defaultValue) { + var cache = this.cache; + if (!(bucketKey in cache)) { + return defaultValue; + } + var bucket = cache[bucketKey]; + if (prop in bucket) { + return bucket[prop]; + } else { + return defaultValue; + } + }, + cache: null + }); + }); +define("ember-routing/system/controller_for", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-routing + */ + + /** + + Finds a controller instance. + + @for Ember + @method controllerFor + @private + */ + __exports__["default"] = function controllerFor(container, controllerName, lookupOptions) { + return container.lookup('controller:' + controllerName, lookupOptions); + } + }); +define("ember-routing/system/dsl", + ["ember-metal/core","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, assert + + /** + @module ember + @submodule ember-routing + */ + + function DSL(name) { + this.parent = name; + this.matches = []; + } + __exports__["default"] = DSL; + + DSL.prototype = { + route: function(name, options, callback) { + if (arguments.length === 2 && typeof options === 'function') { + callback = options; + options = {}; + } + + if (arguments.length === 1) { + options = {}; + } + + var type = options.resetNamespace === true ? 'resource' : 'route'; + Ember.assert("'basic' cannot be used as a " + type + " name.", name !== 'basic'); + + + if (typeof options.path !== 'string') { + options.path = "/" + name; + } + + if (canNest(this) && options.resetNamespace !== true) { + name = this.parent + "." + name; + } + + if (callback) { + var dsl = new DSL(name); + route(dsl, 'loading'); + route(dsl, 'error', { path: "/_unused_dummy_error_path_route_" + name + "/:error" }); + + if (callback) { callback.call(dsl); } + + this.push(options.path, name, dsl.generate()); + } else { + this.push(options.path, name, null); + } + + }, + + push: function(url, name, callback) { + var parts = name.split('.'); + if (url === "" || url === "/" || parts[parts.length-1] === "index") { this.explicitIndex = true; } + + this.matches.push([url, name, callback]); + }, + + resource: function(name, options, callback) { + if (arguments.length === 2 && typeof options === 'function') { + callback = options; + options = {}; + } + + if (arguments.length === 1) { + options = {}; + } + + options.resetNamespace = true; + this.route(name, options, callback); + }, + + generate: function() { + var dslMatches = this.matches; + + if (!this.explicitIndex) { + route(this, "index", { path: "/" }); + } + + return function(match) { + for (var i=0, l=dslMatches.length; i " + fullName, { fullName: fullName }); + } + + return instance; + } + }); +define("ember-routing/system/route", + ["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/get_properties","ember-metal/enumerable_utils","ember-metal/is_none","ember-metal/computed","ember-metal/merge","ember-metal/utils","ember-metal/run_loop","ember-metal/keys","ember-runtime/copy","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/mixins/action_handler","ember-routing/system/generate_controller","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, K, A, deprecate, assert, Logger + var EmberError = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var getProperties = __dependency5__["default"]; + var forEach = __dependency6__.forEach; + var replace = __dependency6__.replace; + var isNone = __dependency7__.isNone; + var computed = __dependency8__.computed; + var merge = __dependency9__["default"]; + var isArray = __dependency10__.isArray; + var typeOf = __dependency10__.typeOf; + var run = __dependency11__["default"]; + var keys = __dependency12__["default"]; + var copy = __dependency13__["default"]; + var classify = __dependency14__.classify; + var fmt = __dependency14__.fmt; + var EmberObject = __dependency15__["default"]; + var ActionHandler = __dependency16__["default"]; + var generateController = __dependency17__["default"]; + var stashParamNames = __dependency18__.stashParamNames; + + /** + @module ember + @submodule ember-routing + */ + + /** + The `Ember.Route` class is used to define individual routes. Refer to + the [routing guide](http://emberjs.com/guides/routing/) for documentation. + + @class Route + @namespace Ember + @extends Ember.Object + @uses Ember.ActionHandler + */ + var Route = EmberObject.extend(ActionHandler, { + /** + Configuration hash for this route's queryParams. The possible + configuration options and their defaults are as follows + (assuming a query param whose URL key is `page`): + + ```js + queryParams: { + page: { + // By default, controller query param properties don't + // cause a full transition when they are changed, but + // rather only cause the URL to update. Setting + // `refreshModel` to true will cause an "in-place" + // transition to occur, whereby the model hooks for + // this route (and any child routes) will re-fire, allowing + // you to reload models (e.g., from the server) using the + // updated query param values. + refreshModel: false, + + // By default, changes to controller query param properties + // cause the URL to update via `pushState`, which means an + // item will be added to the browser's history, allowing + // you to use the back button to restore the app to the + // previous state before the query param property was changed. + // Setting `replace` to true will use `replaceState` (or its + // hash location equivalent), which causes no browser history + // item to be added. This options name and default value are + // the same as the `link-to` helper's `replace` option. + replace: false + } + } + ``` + + @property queryParams + @for Ember.Route + @type Hash + */ + queryParams: {}, + + /** + @private + + @property _qp + */ + _qp: computed(function() { + var controllerName = this.controllerName || this.routeName; + var controllerClass = this.container.lookupFactory('controller:' + controllerName); + + if (!controllerClass) { + return defaultQPMeta; + } + + var controllerProto = controllerClass.proto(); + var qpProps = get(controllerProto, '_normalizedQueryParams'); + var cacheMeta = get(controllerProto, '_cacheMeta'); + + var qps = [], map = {}, self = this; + for (var propName in qpProps) { + if (!qpProps.hasOwnProperty(propName)) { continue; } + + var desc = qpProps[propName]; + var urlKey = desc.as || this.serializeQueryParamKey(propName); + var defaultValue = get(controllerProto, propName); + + if (isArray(defaultValue)) { + defaultValue = Ember.A(defaultValue.slice()); + } + + var type = typeOf(defaultValue); + var defaultValueSerialized = this.serializeQueryParam(defaultValue, urlKey, type); + var fprop = controllerName + ':' + propName; + var qp = { + def: defaultValue, + sdef: defaultValueSerialized, + type: type, + urlKey: urlKey, + prop: propName, + fprop: fprop, + ctrl: controllerName, + cProto: controllerProto, + svalue: defaultValueSerialized, + cacheType: desc.scope, + route: this, + cacheMeta: cacheMeta[propName] + }; + + map[propName] = map[urlKey] = map[fprop] = qp; + qps.push(qp); + } + + return { + qps: qps, + map: map, + states: { + active: function(controller, prop) { + return self._activeQPChanged(controller, map[prop]); + }, + allowOverrides: function(controller, prop) { + return self._updatingQPChanged(controller, map[prop]); + }, + changingKeys: function(controller, prop) { + return self._updateSerializedQPValue(controller, map[prop]); + } + } + }; + }), + + /** + @private + + @property _names + */ + _names: null, + + /** + @private + + @method _stashNames + */ + _stashNames: function(_handlerInfo, dynamicParent) { + var handlerInfo = _handlerInfo; + if (this._names) { return; } + var names = this._names = handlerInfo._names; + + if (!names.length) { + handlerInfo = dynamicParent; + names = handlerInfo && handlerInfo._names || []; + } + + var qps = get(this, '_qp.qps'); + var len = qps.length; + + var namePaths = new Array(names.length); + for (var a = 0, nlen = names.length; a < nlen; ++a) { + namePaths[a] = handlerInfo.name + '.' + names[a]; + } + + for (var i = 0; i < len; ++i) { + var qp = qps[i]; + var cacheMeta = qp.cacheMeta; + if (cacheMeta.scope === 'model') { + cacheMeta.parts = namePaths; + } + cacheMeta.prefix = qp.ctrl; + } + }, + + /** + @private + + @property _updateSerializedQPValue + */ + _updateSerializedQPValue: function(controller, qp) { + var value = get(controller, qp.prop); + qp.svalue = this.serializeQueryParam(value, qp.urlKey, qp.type); + }, + + /** + @private + + @property _activeQPChanged + */ + _activeQPChanged: function(controller, qp) { + var value = get(controller, qp.prop); + this.router._queuedQPChanges[qp.fprop] = value; + run.once(this, this._fireQueryParamTransition); + }, + + /** + @private + @method _updatingQPChanged + */ + _updatingQPChanged: function(controller, qp) { + var router = this.router; + if (!router._qpUpdates) { + router._qpUpdates = {}; + } + router._qpUpdates[qp.urlKey] = true; + }, + + mergedProperties: ['events', 'queryParams'], + + /** + @method paramsFor + */ + paramsFor: function(name) { + var route = this.container.lookup('route:' + name); + + if (!route) { + return {}; + } + + var transition = this.router.router.activeTransition; + var state = transition ? transition.state : this.router.router.state; + + var params = {}; + merge(params, state.params[name]); + merge(params, getQueryParamsFor(route, state)); + + return params; + }, + + /** + @method serializeQueryParamKey + */ + serializeQueryParamKey: function(controllerPropertyName) { + return controllerPropertyName; + }, + + /** + @method serializeQueryParam + */ + serializeQueryParam: function(value, urlKey, defaultValueType) { + // urlKey isn't used here, but anyone overriding + // can use it to provide serialization specific + // to a certain query param. + if (defaultValueType === 'array') { + return JSON.stringify(value); + } + return '' + value; + }, + + /** + @method deserializeQueryParam + */ + deserializeQueryParam: function(value, urlKey, defaultValueType) { + // urlKey isn't used here, but anyone overriding + // can use it to provide deserialization specific + // to a certain query param. + + // Use the defaultValueType of the default value (the initial value assigned to a + // controller query param property), to intelligently deserialize and cast. + if (defaultValueType === 'boolean') { + return (value === 'true') ? true : false; + } else if (defaultValueType === 'number') { + return (Number(value)).valueOf(); + } else if (defaultValueType === 'array') { + return Ember.A(JSON.parse(value)); + } + return value; + }, + + + /** + @private + @property _fireQueryParamTransition + */ + _fireQueryParamTransition: function() { + this.transitionTo({ queryParams: this.router._queuedQPChanges }); + this.router._queuedQPChanges = {}; + }, + + /** + A hook you can use to reset controller values either when the model + changes or the route is exiting. + + ```js + App.ArticlesRoute = Ember.Route.extend({ + // ... + + resetController: function (controller, isExiting, transition) { + if (isExiting) { + controller.set('page', 1); + } + } + }); + ``` + + @method resetController + @param {Controller} controller instance + @param {Boolean} isExiting + @param {Object} transition + @since 1.7.0 + */ + resetController: Ember.K, + + /** + @private + + @method exit + */ + exit: function() { + this.deactivate(); + this.teardownViews(); + }, + + /** + @private + + @method _reset + @since 1.7.0 + */ + _reset: function(isExiting, transition) { + var controller = this.controller; + + controller._qpDelegate = get(this, '_qp.states.inactive'); + + this.resetController(controller, isExiting, transition); + }, + + /** + @private + + @method enter + */ + enter: function() { + this.activate(); + }, + + /** + The name of the view to use by default when rendering this routes template. + + When rendering a template, the route will, by default, determine the + template and view to use from the name of the route itself. If you need to + define a specific view, set this property. + + This is useful when multiple routes would benefit from using the same view + because it doesn't require a custom `renderTemplate` method. For example, + the following routes will all render using the `App.PostsListView` view: + + ```js + var PostsList = Ember.Route.extend({ + viewName: 'postsList' + }); + + App.PostsIndexRoute = PostsList.extend(); + App.PostsArchivedRoute = PostsList.extend(); + ``` + + @property viewName + @type String + @default null + @since 1.4.0 + */ + viewName: null, + + /** + The name of the template to use by default when rendering this routes + template. + + This is similar with `viewName`, but is useful when you just want a custom + template without a view. + + ```js + var PostsList = Ember.Route.extend({ + templateName: 'posts/list' + }); + + App.PostsIndexRoute = PostsList.extend(); + App.PostsArchivedRoute = PostsList.extend(); + ``` + + @property templateName + @type String + @default null + @since 1.4.0 + */ + templateName: null, + + /** + The name of the controller to associate with this route. + + By default, Ember will lookup a route's controller that matches the name + of the route (i.e. `App.PostController` for `App.PostRoute`). However, + if you would like to define a specific controller to use, you can do so + using this property. + + This is useful in many ways, as the controller specified will be: + + * passed to the `setupController` method. + * used as the controller for the view being rendered by the route. + * returned from a call to `controllerFor` for the route. + + @property controllerName + @type String + @default null + @since 1.4.0 + */ + controllerName: null, + + /** + The `willTransition` action is fired at the beginning of any + attempted transition with a `Transition` object as the sole + argument. This action can be used for aborting, redirecting, + or decorating the transition from the currently active routes. + + A good example is preventing navigation when a form is + half-filled out: + + ```js + App.ContactFormRoute = Ember.Route.extend({ + actions: { + willTransition: function(transition) { + if (this.controller.get('userHasEnteredData')) { + this.controller.displayNavigationConfirm(); + transition.abort(); + } + } + } + }); + ``` + + You can also redirect elsewhere by calling + `this.transitionTo('elsewhere')` from within `willTransition`. + Note that `willTransition` will not be fired for the + redirecting `transitionTo`, since `willTransition` doesn't + fire when there is already a transition underway. If you want + subsequent `willTransition` actions to fire for the redirecting + transition, you must first explicitly call + `transition.abort()`. + + @event willTransition + @param {Transition} transition + */ + + /** + The `didTransition` action is fired after a transition has + successfully been completed. This occurs after the normal model + hooks (`beforeModel`, `model`, `afterModel`, `setupController`) + have resolved. The `didTransition` action has no arguments, + however, it can be useful for tracking page views or resetting + state on the controller. + + ```js + App.LoginRoute = Ember.Route.extend({ + actions: { + didTransition: function() { + this.controller.get('errors.base').clear(); + return true; // Bubble the didTransition event + } + } + }); + ``` + + @event didTransition + @since 1.2.0 + */ + + /** + The `loading` action is fired on the route when a route's `model` + hook returns a promise that is not already resolved. The current + `Transition` object is the first parameter and the route that + triggered the loading event is the second parameter. + + ```js + App.ApplicationRoute = Ember.Route.extend({ + actions: { + loading: function(transition, route) { + var view = Ember.View.create({ + classNames: ['app-loading'] + }) + .append(); + + this.router.one('didTransition', function () { + view.destroy(); + }); + return true; // Bubble the loading event + } + } + }); + ``` + + @event loading + @param {Transition} transition + @param {Ember.Route} route The route that triggered the loading event + @since 1.2.0 + */ + + /** + When attempting to transition into a route, any of the hooks + may return a promise that rejects, at which point an `error` + action will be fired on the partially-entered routes, allowing + for per-route error handling logic, or shared error handling + logic defined on a parent route. + + Here is an example of an error handler that will be invoked + for rejected promises from the various hooks on the route, + as well as any unhandled errors from child routes: + + ```js + App.AdminRoute = Ember.Route.extend({ + beforeModel: function() { + return Ember.RSVP.reject("bad things!"); + }, + + actions: { + error: function(error, transition) { + // Assuming we got here due to the error in `beforeModel`, + // we can expect that error === "bad things!", + // but a promise model rejecting would also + // call this hook, as would any errors encountered + // in `afterModel`. + + // The `error` hook is also provided the failed + // `transition`, which can be stored and later + // `.retry()`d if desired. + + this.transitionTo('login'); + } + } + }); + ``` + + `error` actions that bubble up all the way to `ApplicationRoute` + will fire a default error handler that logs the error. You can + specify your own global default error handler by overriding the + `error` handler on `ApplicationRoute`: + + ```js + App.ApplicationRoute = Ember.Route.extend({ + actions: { + error: function(error, transition) { + this.controllerFor('banner').displayError(error.message); + } + } + }); + ``` + @event error + @param {Error} error + @param {Transition} transition + */ + + /** + The controller associated with this route. + + Example + + ```javascript + App.FormRoute = Ember.Route.extend({ + actions: { + willTransition: function(transition) { + if (this.controller.get('userHasEnteredData') && + !confirm("Are you sure you want to abandon progress?")) { + transition.abort(); + } else { + // Bubble the `willTransition` action so that + // parent routes can decide whether or not to abort. + return true; + } + } + } + }); + ``` + + @property controller + @type Ember.Controller + @since 1.6.0 + */ + + _actions: { + + queryParamsDidChange: function(changed, totalPresent, removed) { + var totalChanged = keys(changed).concat(keys(removed)); + for (var i = 0, len = totalChanged.length; i < len; ++i) { + var urlKey = totalChanged[i]; + var options = get(this.queryParams, urlKey) || {}; + if (get(options, 'refreshModel')) { + this.refresh(); + } + } + + return true; + }, + + finalizeQueryParamChange: function(params, finalParams, transition) { + if (this.routeName !== 'application') { return true; } + + // Transition object is absent for intermediate transitions. + if (!transition) { return; } + + var handlerInfos = transition.state.handlerInfos; + var router = this.router; + var qpMeta = router._queryParamsFor(handlerInfos[handlerInfos.length-1].name); + var changes = router._qpUpdates; + var replaceUrl; + + stashParamNames(router, handlerInfos); + + for (var i = 0, len = qpMeta.qps.length; i < len; ++i) { + var qp = qpMeta.qps[i]; + var route = qp.route; + var controller = route.controller; + var presentKey = qp.urlKey in params && qp.urlKey; + + // Do a reverse lookup to see if the changed query + // param URL key corresponds to a QP property on + // this controller. + var value, svalue; + if (changes && qp.urlKey in changes) { + // Value updated in/before setupController + value = get(controller, qp.prop); + svalue = route.serializeQueryParam(value, qp.urlKey, qp.type); + } else { + if (presentKey) { + svalue = params[presentKey]; + value = route.deserializeQueryParam(svalue, qp.urlKey, qp.type); + } else { + // No QP provided; use default value. + svalue = qp.sdef; + value = copyDefaultValue(qp.def); + } + } + + controller._qpDelegate = get(this, '_qp.states.inactive'); + + var thisQueryParamChanged = (svalue !== qp.svalue); + if (thisQueryParamChanged) { + var options = get(route, 'queryParams.' + qp.urlKey) || {}; + + if (transition.queryParamsOnly && replaceUrl !== false) { + var replaceConfigValue = get(options, 'replace'); + if (replaceConfigValue) { + replaceUrl = true; + } else if (replaceConfigValue === false) { + // Explicit pushState wins over any other replaceStates. + replaceUrl = false; + } + } + + set(controller, qp.prop, value); + } + + // Stash current serialized value of controller. + qp.svalue = svalue; + + var thisQueryParamHasDefaultValue = (qp.sdef === svalue); + if (!thisQueryParamHasDefaultValue) { + finalParams.push({ + value: svalue, + visible: true, + key: presentKey || qp.urlKey + }); + } + } + + if (replaceUrl) { + transition.method('replace'); + } + + forEach(qpMeta.qps, function(qp) { + var routeQpMeta = get(qp.route, '_qp'); + var finalizedController = qp.route.controller; + finalizedController._qpDelegate = get(routeQpMeta, 'states.active'); + }); + + router._qpUpdates = null; + } + }, + + /** + @deprecated + + Please use `actions` instead. + @method events + */ + events: null, + + /** + This hook is executed when the router completely exits this route. It is + not executed when the model for the route changes. + + @method deactivate + */ + deactivate: Ember.K, + + /** + This hook is executed when the router enters the route. It is not executed + when the model for the route changes. + + @method activate + */ + activate: Ember.K, + + /** + Transition the application into another route. The route may + be either a single route or route path: + + ```javascript + this.transitionTo('blogPosts'); + this.transitionTo('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + this.transitionTo('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + this.transitionTo('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + this.transitionTo('blogComment', aPost, aComment); + this.transitionTo('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + this.transitionTo('/'); + this.transitionTo('/blog/post/1/comment/13'); + ``` + + See also 'replaceWith'. + + Simple Transition Example + + ```javascript + App.Router.map(function() { + this.route("index"); + this.route("secret"); + this.route("fourOhFour", { path: "*:"}); + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + moveToSecret: function(context){ + if (authorized()){ + this.transitionTo('secret', context); + } + this.transitionTo('fourOhFour'); + } + } + }); + ``` + + Transition to a nested route + + ```javascript + App.Router.map(function() { + this.resource('articles', { path: '/articles' }, function() { + this.route('new'); + }); + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + transitionToNewArticle: function() { + this.transitionTo('articles.new'); + } + } + }); + ``` + + Multiple Models Example + + ```javascript + App.Router.map(function() { + this.route("index"); + this.resource('breakfast', {path:':breakfastId'}, function(){ + this.resource('cereal', {path: ':cerealId'}); + }); + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + moveToChocolateCereal: function(){ + var cereal = { cerealId: "ChocolateYumminess"}, + breakfast = {breakfastId: "CerealAndMilk"}; + + this.transitionTo('cereal', breakfast, cereal); + } + } + }); + ``` + + @method transitionTo + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used while + transitioning to the route. + @return {Transition} the transition object associated with this + attempted transition + */ + transitionTo: function(name, context) { + var router = this.router; + return router.transitionTo.apply(router, arguments); + }, + + /** + Perform a synchronous transition into another route without attempting + to resolve promises, update the URL, or abort any currently active + asynchronous transitions (i.e. regular transitions caused by + `transitionTo` or URL changes). + + This method is handy for performing intermediate transitions on the + way to a final destination route, and is called internally by the + default implementations of the `error` and `loading` handlers. + + @method intermediateTransitionTo + @param {String} name the name of the route + @param {...Object} models the model(s) to be used while transitioning + to the route. + @since 1.2.0 + */ + intermediateTransitionTo: function() { + var router = this.router; + router.intermediateTransitionTo.apply(router, arguments); + }, + + /** + Refresh the model on this route and any child routes, firing the + `beforeModel`, `model`, and `afterModel` hooks in a similar fashion + to how routes are entered when transitioning in from other route. + The current route params (e.g. `article_id`) will be passed in + to the respective model hooks, and if a different model is returned, + `setupController` and associated route hooks will re-fire as well. + + An example usage of this method is re-querying the server for the + latest information using the same parameters as when the route + was first entered. + + Note that this will cause `model` hooks to fire even on routes + that were provided a model object when the route was initially + entered. + + @method refresh + @return {Transition} the transition object associated with this + attempted transition + @since 1.4.0 + */ + refresh: function() { + return this.router.router.refresh(this); + }, + + /** + Transition into another route while replacing the current URL, if possible. + This will replace the current history entry instead of adding a new one. + Beside that, it is identical to `transitionTo` in all other respects. See + 'transitionTo' for additional information regarding multiple models. + + Example + + ```javascript + App.Router.map(function() { + this.route("index"); + this.route("secret"); + }); + + App.SecretRoute = Ember.Route.extend({ + afterModel: function() { + if (!authorized()){ + this.replaceWith('index'); + } + } + }); + ``` + + @method replaceWith + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used while + transitioning to the route. + @return {Transition} the transition object associated with this + attempted transition + */ + replaceWith: function() { + var router = this.router; + return router.replaceWith.apply(router, arguments); + }, + + /** + Sends an action to the router, which will delegate it to the currently + active route hierarchy per the bubbling rules explained under `actions`. + + Example + + ```javascript + App.Router.map(function() { + this.route("index"); + }); + + App.ApplicationRoute = Ember.Route.extend({ + actions: { + track: function(arg) { + console.log(arg, 'was clicked'); + } + } + }); + + App.IndexRoute = Ember.Route.extend({ + actions: { + trackIfDebug: function(arg) { + if (debug) { + this.send('track', arg); + } + } + } + }); + ``` + + @method send + @param {String} name the name of the action to trigger + @param {...*} args + */ + send: function() { + return this.router.send.apply(this.router, arguments); + }, + + /** + This hook is the entry point for router.js + + @private + @method setup + */ + setup: function(context, transition) { + var controllerName = this.controllerName || this.routeName; + var controller = this.controllerFor(controllerName, true); + + if (!controller) { + controller = this.generateController(controllerName, context); + } + + // Assign the route's controller so that it can more easily be + // referenced in action handlers + this.controller = controller; + + if (this.setupControllers) { + Ember.deprecate("Ember.Route.setupControllers is deprecated. Please use Ember.Route.setupController(controller, model) instead."); + this.setupControllers(controller, context); + } else { + var states = get(this, '_qp.states'); + if (transition) { + // Update the model dep values used to calculate cache keys. + stashParamNames(this.router, transition.state.handlerInfos); + controller._qpDelegate = states.changingKeys; + controller._updateCacheParams(transition.params); + } + controller._qpDelegate = states.allowOverrides; + + if (transition) { + var qpValues = getQueryParamsFor(this, transition.state); + controller.setProperties(qpValues); + } + + this.setupController(controller, context, transition); + } + + if (this.renderTemplates) { + Ember.deprecate("Ember.Route.renderTemplates is deprecated. Please use Ember.Route.renderTemplate(controller, model) instead."); + this.renderTemplates(context); + } else { + this.renderTemplate(controller, context); + } + }, + + /** + This hook is the first of the route entry validation hooks + called when an attempt is made to transition into a route + or one of its children. It is called before `model` and + `afterModel`, and is appropriate for cases when: + + 1) A decision can be made to redirect elsewhere without + needing to resolve the model first. + 2) Any async operations need to occur first before the + model is attempted to be resolved. + + This hook is provided the current `transition` attempt + as a parameter, which can be used to `.abort()` the transition, + save it for a later `.retry()`, or retrieve values set + on it from a previous hook. You can also just call + `this.transitionTo` to another route to implicitly + abort the `transition`. + + You can return a promise from this hook to pause the + transition until the promise resolves (or rejects). This could + be useful, for instance, for retrieving async code from + the server that is required to enter a route. + + ```js + App.PostRoute = Ember.Route.extend({ + beforeModel: function(transition) { + if (!App.Post) { + return Ember.$.getScript('/models/post.js'); + } + } + }); + ``` + + If `App.Post` doesn't exist in the above example, + `beforeModel` will use jQuery's `getScript`, which + returns a promise that resolves after the server has + successfully retrieved and executed the code from the + server. Note that if an error were to occur, it would + be passed to the `error` hook on `Ember.Route`, but + it's also possible to handle errors specific to + `beforeModel` right from within the hook (to distinguish + from the shared error handling behavior of the `error` + hook): + + ```js + App.PostRoute = Ember.Route.extend({ + beforeModel: function(transition) { + if (!App.Post) { + var self = this; + return Ember.$.getScript('post.js').then(null, function(e) { + self.transitionTo('help'); + + // Note that the above transitionTo will implicitly + // halt the transition. If you were to return + // nothing from this promise reject handler, + // according to promise semantics, that would + // convert the reject into a resolve and the + // transition would continue. To propagate the + // error so that it'd be handled by the `error` + // hook, you would have to either + return Ember.RSVP.reject(e); + }); + } + } + }); + ``` + + @method beforeModel + @param {Transition} transition + @param {Object} queryParams the active query params for this route + @return {Promise} if the value returned from this hook is + a promise, the transition will pause until the transition + resolves. Otherwise, non-promise return values are not + utilized in any way. + */ + beforeModel: Ember.K, + + /** + This hook is called after this route's model has resolved. + It follows identical async/promise semantics to `beforeModel` + but is provided the route's resolved model in addition to + the `transition`, and is therefore suited to performing + logic that can only take place after the model has already + resolved. + + ```js + App.PostsRoute = Ember.Route.extend({ + afterModel: function(posts, transition) { + if (posts.get('length') === 1) { + this.transitionTo('post.show', posts.get('firstObject')); + } + } + }); + ``` + + Refer to documentation for `beforeModel` for a description + of transition-pausing semantics when a promise is returned + from this hook. + + @method afterModel + @param {Object} resolvedModel the value returned from `model`, + or its resolved value if it was a promise + @param {Transition} transition + @param {Object} queryParams the active query params for this handler + @return {Promise} if the value returned from this hook is + a promise, the transition will pause until the transition + resolves. Otherwise, non-promise return values are not + utilized in any way. + */ + afterModel: Ember.K, + + /** + A hook you can implement to optionally redirect to another route. + + If you call `this.transitionTo` from inside of this hook, this route + will not be entered in favor of the other hook. + + `redirect` and `afterModel` behave very similarly and are + called almost at the same time, but they have an important + distinction in the case that, from one of these hooks, a + redirect into a child route of this route occurs: redirects + from `afterModel` essentially invalidate the current attempt + to enter this route, and will result in this route's `beforeModel`, + `model`, and `afterModel` hooks being fired again within + the new, redirecting transition. Redirects that occur within + the `redirect` hook, on the other hand, will _not_ cause + these hooks to be fired again the second time around; in + other words, by the time the `redirect` hook has been called, + both the resolved model and attempted entry into this route + are considered to be fully validated. + + @method redirect + @param {Object} model the model for this route + @param {Transition} transition the transition object associated with the current transition + */ + redirect: Ember.K, + + /** + Called when the context is changed by router.js. + + @private + @method contextDidChange + */ + contextDidChange: function() { + this.currentModel = this.context; + }, + + /** + A hook you can implement to convert the URL into the model for + this route. + + ```js + App.Router.map(function() { + this.resource('post', {path: '/posts/:post_id'}); + }); + ``` + + The model for the `post` route is `App.Post.find(params.post_id)`. + + By default, if your route has a dynamic segment ending in `_id`: + + * The model class is determined from the segment (`post_id`'s + class is `App.Post`) + * The find method is called on the model class with the value of + the dynamic segment. + + Note that for routes with dynamic segments, this hook is not always + executed. If the route is entered through a transition (e.g. when + using the `link-to` Handlebars helper or the `transitionTo` method + of routes), and a model context is already provided this hook + is not called. + + A model context does not include a primitive string or number, + which does cause the model hook to be called. + + Routes without dynamic segments will always execute the model hook. + + ```js + // no dynamic segment, model hook always called + this.transitionTo('posts'); + + // model passed in, so model hook not called + thePost = store.find('post', 1); + this.transitionTo('post', thePost); + + // integer passed in, model hook is called + this.transitionTo('post', 1); + ``` + + + This hook follows the asynchronous/promise semantics + described in the documentation for `beforeModel`. In particular, + if a promise returned from `model` fails, the error will be + handled by the `error` hook on `Ember.Route`. + + Example + + ```js + App.PostRoute = Ember.Route.extend({ + model: function(params) { + return App.Post.find(params.post_id); + } + }); + ``` + + @method model + @param {Object} params the parameters extracted from the URL + @param {Transition} transition + @param {Object} queryParams the query params for this route + @return {Object|Promise} the model for this route. If + a promise is returned, the transition will pause until + the promise resolves, and the resolved value of the promise + will be used as the model for this route. + */ + model: function(params, transition) { + var match, name, sawParams, value; + + var queryParams = get(this, '_qp.map'); + + for (var prop in params) { + if (prop === 'queryParams' || (queryParams && prop in queryParams)) { + continue; + } + + if (match = prop.match(/^(.*)_id$/)) { + name = match[1]; + value = params[prop]; + } + sawParams = true; + } + + if (!name && sawParams) { return copy(params); } + else if (!name) { + if (transition.resolveIndex < 1) { return; } + + var parentModel = transition.state.handlerInfos[transition.resolveIndex-1].context; + + return parentModel; + } + + return this.findModel(name, value); + }, + + /** + @private + @method deserialize + @param {Object} params the parameters extracted from the URL + @param {Transition} transition + @return {Object|Promise} the model for this route. + + Router.js hook. + */ + deserialize: function(params, transition) { + return this.model(this.paramsFor(this.routeName), transition); + }, + + /** + + @method findModel + @param {String} type the model type + @param {Object} value the value passed to find + */ + findModel: function(){ + var store = get(this, 'store'); + return store.find.apply(store, arguments); + }, + + /** + Store property provides a hook for data persistence libraries to inject themselves. + + By default, this store property provides the exact same functionality previously + in the model hook. + + Currently, the required interface is: + + `store.find(modelName, findArguments)` + + @method store + @param {Object} store + */ + store: computed(function(){ + var container = this.container; + var routeName = this.routeName; + var namespace = get(this, 'router.namespace'); + + return { + find: function(name, value) { + var modelClass = container.lookupFactory('model:' + name); + + Ember.assert("You used the dynamic segment " + name + "_id in your route " + + routeName + ", but " + namespace + "." + classify(name) + + " did not exist and you did not override your route's `model` " + + "hook.", modelClass); + + if (!modelClass) { return; } + + Ember.assert(classify(name) + ' has no method `find`.', typeof modelClass.find === 'function'); + + return modelClass.find(value); + } + }; + }), + + /** + A hook you can implement to convert the route's model into parameters + for the URL. + + ```js + App.Router.map(function() { + this.resource('post', {path: '/posts/:post_id'}); + }); + + App.PostRoute = Ember.Route.extend({ + model: function(params) { + // the server returns `{ id: 12 }` + return jQuery.getJSON("/posts/" + params.post_id); + }, + + serialize: function(model) { + // this will make the URL `/posts/12` + return { post_id: model.id }; + } + }); + ``` + + The default `serialize` method will insert the model's `id` into the + route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'. + If the route has multiple dynamic segments or does not contain '_id', `serialize` + will return `Ember.getProperties(model, params)` + + This method is called when `transitionTo` is called with a context + in order to populate the URL. + + @method serialize + @param {Object} model the route's model + @param {Array} params an Array of parameter names for the current + route (in the example, `['post_id']`. + @return {Object} the serialized parameters + */ + serialize: function(model, params) { + if (params.length < 1) { return; } + if (!model) { return; } + + var name = params[0], object = {}; + + if (/_id$/.test(name) && params.length === 1) { + object[name] = get(model, "id"); + } else { + object = getProperties(model, params); + } + + return object; + }, + + /** + A hook you can use to setup the controller for the current route. + + This method is called with the controller for the current route and the + model supplied by the `model` hook. + + By default, the `setupController` hook sets the `model` property of + the controller to the `model`. + + If you implement the `setupController` hook in your Route, it will + prevent this default behavior. If you want to preserve that behavior + when implementing your `setupController` function, make sure to call + `_super`: + + ```js + App.PhotosRoute = Ember.Route.extend({ + model: function() { + return App.Photo.find(); + }, + + setupController: function (controller, model) { + // Call _super for default behavior + this._super(controller, model); + // Implement your custom setup after + this.controllerFor('application').set('showingPhotos', true); + } + }); + ``` + + This means that your template will get a proxy for the model as its + context, and you can act as though the model itself was the context. + + The provided controller will be one resolved based on the name + of this route. + + If no explicit controller is defined, Ember will automatically create + an appropriate controller for the model. + + * if the model is an `Ember.Array` (including record arrays from Ember + Data), the controller is an `Ember.ArrayController`. + * otherwise, the controller is an `Ember.ObjectController`. + + As an example, consider the router: + + ```js + App.Router.map(function() { + this.resource('post', {path: '/posts/:post_id'}); + }); + ``` + + For the `post` route, a controller named `App.PostController` would + be used if it is defined. If it is not defined, an `Ember.ObjectController` + instance would be used. + + Example + + ```js + App.PostRoute = Ember.Route.extend({ + setupController: function(controller, model) { + controller.set('model', model); + } + }); + ``` + + @method setupController + @param {Controller} controller instance + @param {Object} model + */ + setupController: function(controller, context, transition) { + if (controller && (context !== undefined)) { + set(controller, 'model', context); + } + }, + + /** + Returns the controller for a particular route or name. + + The controller instance must already have been created, either through entering the + associated route or using `generateController`. + + ```js + App.PostRoute = Ember.Route.extend({ + setupController: function(controller, post) { + this._super(controller, post); + this.controllerFor('posts').set('currentPost', post); + } + }); + ``` + + @method controllerFor + @param {String} name the name of the route or controller + @return {Ember.Controller} + */ + controllerFor: function(name, _skipAssert) { + var container = this.container; + var route = container.lookup('route:'+name); + var controller; + + if (route && route.controllerName) { + name = route.controllerName; + } + + controller = container.lookup('controller:' + name); + + // NOTE: We're specifically checking that skipAssert is true, because according + // to the old API the second parameter was model. We do not want people who + // passed a model to skip the assertion. + Ember.assert("The controller named '"+name+"' could not be found. Make sure " + + "that this route exists and has already been entered at least " + + "once. If you are accessing a controller not associated with a " + + "route, make sure the controller class is explicitly defined.", + controller || _skipAssert === true); + + return controller; + }, + + /** + Generates a controller for a route. + + If the optional model is passed then the controller type is determined automatically, + e.g., an ArrayController for arrays. + + Example + + ```js + App.PostRoute = Ember.Route.extend({ + setupController: function(controller, post) { + this._super(controller, post); + this.generateController('posts', post); + } + }); + ``` + + @method generateController + @param {String} name the name of the controller + @param {Object} model the model to infer the type of the controller (optional) + */ + generateController: function(name, model) { + var container = this.container; + + model = model || this.modelFor(name); + + return generateController(container, name, model); + }, + + /** + Returns the model of a parent (or any ancestor) route + in a route hierarchy. During a transition, all routes + must resolve a model object, and if a route + needs access to a parent route's model in order to + resolve a model (or just reuse the model from a parent), + it can call `this.modelFor(theNameOfParentRoute)` to + retrieve it. + + Example + + ```js + App.Router.map(function() { + this.resource('post', { path: '/post/:post_id' }, function() { + this.resource('comments'); + }); + }); + + App.CommentsRoute = Ember.Route.extend({ + afterModel: function() { + this.set('post', this.modelFor('post')); + } + }); + ``` + + @method modelFor + @param {String} name the name of the route + @return {Object} the model object + */ + modelFor: function(name) { + var route = this.container.lookup('route:' + name); + var transition = this.router ? this.router.router.activeTransition : null; + + // If we are mid-transition, we want to try and look up + // resolved parent contexts on the current transitionEvent. + if (transition) { + var modelLookupName = (route && route.routeName) || name; + if (transition.resolvedModels.hasOwnProperty(modelLookupName)) { + return transition.resolvedModels[modelLookupName]; + } + } + + return route && route.currentModel; + }, + + /** + A hook you can use to render the template for the current route. + + This method is called with the controller for the current route and the + model supplied by the `model` hook. By default, it renders the route's + template, configured with the controller for the route. + + This method can be overridden to set up and render additional or + alternative templates. + + ```js + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function(controller, model) { + var favController = this.controllerFor('favoritePost'); + + // Render the `favoritePost` template into + // the outlet `posts`, and display the `favoritePost` + // controller. + this.render('favoritePost', { + outlet: 'posts', + controller: favController + }); + } + }); + ``` + + @method renderTemplate + @param {Object} controller the route's controller + @param {Object} model the route's model + */ + renderTemplate: function(controller, model) { + this.render(); + }, + + /** + `render` is used to render a template into a region of another template + (indicated by an `{{outlet}}`). `render` is used both during the entry + phase of routing (via the `renderTemplate` hook) and later in response to + user interaction. + + For example, given the following minimal router and templates: + + ```js + Router.map(function() { + this.resource('photos'); + }); + ``` + + ```handlebars + +
    + {{outlet "anOutletName"}} +
    + ``` + + ```handlebars + +

    Photos

    + ``` + + You can render `photos.hbs` into the `"anOutletName"` outlet of + `application.hbs` by calling `render`: + + ```js + // posts route + Ember.Route.extend({ + renderTemplate: function(){ + this.render('posts', { + into: 'application', + outlet: 'anOutletName' + }) + } + }); + ``` + + `render` additionally allows you to supply which `view`, `controller`, and + `model` objects should be loaded and associated with the rendered template. + + + ```js + // posts route + Ember.Route.extend({ + renderTemplate: function(controller, model){ + this.render('posts', { // the template to render, referenced by name + into: 'application', // the template to render into, referenced by name + outlet: 'anOutletName', // the outlet inside `options.template` to render into. + view: 'aViewName', // the view to use for this template, referenced by name + controller: 'someControllerName', // the controller to use for this template, referenced by name + model: model // the model to set on `options.controller`. + }) + } + }); + ``` + + The string values provided for the template name, view, and controller + will eventually pass through to the resolver for lookup. See + Ember.Resolver for how these are mapped to JavaScript objects in your + application. + + Not all options need to be passed to `render`. Default values will be used + based on the name of the route specified in the router or the Route's + `controllerName`, `viewName` and and `templateName` properties. + + For example: + + ```js + // router + Router.map(function() { + this.route('index'); + this.resource('post', {path: '/posts/:post_id'}); + }); + ``` + + ```js + // post route + PostRoute = App.Route.extend({ + renderTemplate: function() { + this.render(); // all defaults apply + } + }); + ``` + + The name of the `PostRoute`, defined by the router, is `post`. + + The following equivalent default options will be applied when + the Route calls `render`: + + ```js + // + this.render('post', { // the template name associated with 'post' Route + into: 'application', // the parent route to 'post' Route + outlet: 'main', // {{outlet}} and {{outlet 'main' are synonymous}}, + view: 'post', // the view associated with the 'post' Route + controller: 'post', // the controller associated with the 'post' Route + }) + ``` + + By default the controller's `model` will be the route's model, so it does not + need to be passed unless you wish to change which model is being used. + + @method render + @param {String} name the name of the template to render + @param {Object} [options] the options + @param {String} [options.into] the template to render into, + referenced by name. Defaults to the parent template + @param {String} [options.outlet] the outlet inside `options.template` to render into. + Defaults to 'main' + @param {String} [options.controller] the controller to use for this template, + referenced by name. Defaults to the Route's paired controller + @param {String} [options.model] the model object to set on `options.controller` + Defaults to the return value of the Route's model hook + */ + render: function(name, options) { + Ember.assert("The name in the given arguments is undefined", arguments.length > 0 ? !isNone(arguments[0]) : true); + + var namePassed = typeof name === 'string' && !!name; + + if (typeof name === 'object' && !options) { + options = name; + name = this.routeName; + } + + options = options || {}; + options.namePassed = namePassed; + + var templateName; + + if (name) { + name = name.replace(/\//g, '.'); + templateName = name; + } else { + name = this.routeName; + templateName = this.templateName || name; + } + + var viewName = options.view || namePassed && name || this.viewName || name; + + var container = this.container; + var view = container.lookup('view:' + viewName); + var template = view ? view.get('template') : null; + + if (!template) { + template = container.lookup('template:' + templateName); + } + + if (!view && !template) { + Ember.assert("Could not find \"" + name + "\" template or view.", Ember.isEmpty(arguments[0])); + if (get(this.router, 'namespace.LOG_VIEW_LOOKUPS')) { + Ember.Logger.info("Could not find \"" + name + "\" template or view. Nothing will be rendered", { fullName: 'template:' + name }); + } + return; + } + + options = normalizeOptions(this, name, template, options); + view = setupView(view, container, options); + + if (options.outlet === 'main') { this.lastRenderedTemplate = name; } + + appendView(this, view, options); + }, + + /** + Disconnects a view that has been rendered into an outlet. + + You may pass any or all of the following options to `disconnectOutlet`: + + * `outlet`: the name of the outlet to clear (default: 'main') + * `parentView`: the name of the view containing the outlet to clear + (default: the view rendered by the parent route) + + Example: + + ```js + App.ApplicationRoute = App.Route.extend({ + actions: { + showModal: function(evt) { + this.render(evt.modalName, { + outlet: 'modal', + into: 'application' + }); + }, + hideModal: function(evt) { + this.disconnectOutlet({ + outlet: 'modal', + parentView: 'application' + }); + } + } + }); + ``` + + Alternatively, you can pass the `outlet` name directly as a string. + + Example: + + ```js + hideModal: function(evt) { + this.disconnectOutlet('modal'); + } + ``` + + @method disconnectOutlet + @param {Object|String} options the options hash or outlet name + */ + disconnectOutlet: function(options) { + if (!options || typeof options === "string") { + var outletName = options; + options = {}; + options.outlet = outletName; + } + options.parentView = options.parentView ? options.parentView.replace(/\//g, '.') : parentTemplate(this); + options.outlet = options.outlet || 'main'; + + var parentView = this.router._lookupActiveView(options.parentView); + if (parentView) { parentView.disconnectOutlet(options.outlet); } + }, + + willDestroy: function() { + this.teardownViews(); + }, + + /** + @private + + @method teardownViews + */ + teardownViews: function() { + // Tear down the top level view + if (this.teardownTopLevelView) { this.teardownTopLevelView(); } + + // Tear down any outlets rendered with 'into' + var teardownOutletViews = this.teardownOutletViews || []; + forEach(teardownOutletViews, function(teardownOutletView) { + teardownOutletView(); + }); + + delete this.teardownTopLevelView; + delete this.teardownOutletViews; + delete this.lastRenderedTemplate; + } + }); + + var defaultQPMeta = { + qps: [], + map: {}, + states: {} + }; + + function parentRoute(route) { + var handlerInfo = handlerInfoFor(route, route.router.router.state.handlerInfos, -1); + return handlerInfo && handlerInfo.handler; + } + + function handlerInfoFor(route, handlerInfos, _offset) { + if (!handlerInfos) { return; } + + var offset = _offset || 0, current; + for (var i=0, l=handlerInfos.length; i " + routeName, { fullName: routeName }); + } + } + + handler.routeName = name; + return handler; + }; + }, + + _setupRouter: function(router, location) { + var lastURL, emberRouter = this; + + router.getHandler = this._getHandlerFunction(); + + var doUpdateURL = function() { + location.setURL(lastURL); + }; + + router.updateURL = function(path) { + lastURL = path; + run.once(doUpdateURL); + }; + + if (location.replaceURL) { + var doReplaceURL = function() { + location.replaceURL(lastURL); + }; + + router.replaceURL = function(path) { + lastURL = path; + run.once(doReplaceURL); + }; + } + + router.didTransition = function(infos) { + emberRouter.didTransition(infos); + }; + }, + + _serializeQueryParams: function(targetRouteName, queryParams) { + var groupedByUrlKey = {}; + + forEachQueryParam(this, targetRouteName, queryParams, function(key, value, qp) { + var urlKey = qp.urlKey; + if (!groupedByUrlKey[urlKey]) { + groupedByUrlKey[urlKey] = []; + } + groupedByUrlKey[urlKey].push({ + qp: qp, + value: value + }); + delete queryParams[key]; + }); + + for (var key in groupedByUrlKey) { + var qps = groupedByUrlKey[key]; + if (qps.length > 1) { + var qp0 = qps[0].qp, qp1=qps[1].qp; + Ember.assert(fmt("You're not allowed to have more than one controller property map to the same query param key, but both `%@` and `%@` map to `%@`. You can fix this by mapping one of the controller properties to a different query param key via the `as` config option, e.g. `%@: { as: 'other-%@' }`", [qp0.fprop, qp1.fprop, qp0.urlKey, qp0.prop, qp0.prop]), false); + } + var qp = qps[0].qp; + queryParams[qp.urlKey] = qp.route.serializeQueryParam(qps[0].value, qp.urlKey, qp.type); + } + }, + + _deserializeQueryParams: function(targetRouteName, queryParams) { + forEachQueryParam(this, targetRouteName, queryParams, function(key, value, qp) { + delete queryParams[key]; + queryParams[qp.prop] = qp.route.deserializeQueryParam(value, qp.urlKey, qp.type); + }); + }, + + _pruneDefaultQueryParamValues: function(targetRouteName, queryParams) { + var qps = this._queryParamsFor(targetRouteName); + for (var key in queryParams) { + var qp = qps.map[key]; + if (qp && qp.sdef === queryParams[key]) { + delete queryParams[key]; + } + } + }, + + _doTransition: function(_targetRouteName, models, _queryParams) { + var targetRouteName = _targetRouteName || getActiveTargetName(this.router); + Ember.assert("The route " + targetRouteName + " was not found", targetRouteName && this.router.hasRoute(targetRouteName)); + + var queryParams = {}; + merge(queryParams, _queryParams); + this._prepareQueryParams(targetRouteName, models, queryParams); + + var transitionArgs = routeArgs(targetRouteName, models, queryParams); + var transitionPromise = this.router.transitionTo.apply(this.router, transitionArgs); + + listenForTransitionErrors(transitionPromise); + + return transitionPromise; + }, + + _prepareQueryParams: function(targetRouteName, models, queryParams) { + this._hydrateUnsuppliedQueryParams(targetRouteName, models, queryParams); + this._serializeQueryParams(targetRouteName, queryParams); + this._pruneDefaultQueryParamValues(targetRouteName, queryParams); + }, + + /** + Returns a merged query params meta object for a given route. + Useful for asking a route what its known query params are. + */ + _queryParamsFor: function(leafRouteName) { + if (this._qpCache[leafRouteName]) { + return this._qpCache[leafRouteName]; + } + + var map = {}, qps = [], qpCache = this._qpCache[leafRouteName] = { + map: map, + qps: qps + }; + + var routerjs = this.router; + var recogHandlerInfos = routerjs.recognizer.handlersFor(leafRouteName); + + for (var i = 0, len = recogHandlerInfos.length; i < len; ++i) { + var recogHandler = recogHandlerInfos[i]; + var route = routerjs.getHandler(recogHandler.handler); + var qpMeta = get(route, '_qp'); + + if (!qpMeta) { continue; } + + merge(map, qpMeta.map); + qps.push.apply(qps, qpMeta.qps); + } + + return { + qps: qps, + map: map + }; + }, + + /* + becomeResolved: function(payload, resolvedContext) { + var params = this.serialize(resolvedContext); + + if (payload) { + this.stashResolvedModel(payload, resolvedContext); + payload.params = payload.params || {}; + payload.params[this.name] = params; + } + + return this.factory('resolved', { + context: resolvedContext, + name: this.name, + handler: this.handler, + params: params + }); + }, + */ + + _hydrateUnsuppliedQueryParams: function(leafRouteName, contexts, queryParams) { + var state = calculatePostTransitionState(this, leafRouteName, contexts); + var handlerInfos = state.handlerInfos; + var appCache = this._bucketCache; + + stashParamNames(this, handlerInfos); + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var route = handlerInfos[i].handler; + var qpMeta = get(route, '_qp'); + + for (var j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) { + var qp = qpMeta.qps[j]; + var presentProp = qp.prop in queryParams && qp.prop || + qp.fprop in queryParams && qp.fprop; + + if (presentProp) { + if (presentProp !== qp.fprop) { + queryParams[qp.fprop] = queryParams[presentProp]; + delete queryParams[presentProp]; + } + } else { + var controllerProto = qp.cProto; + var cacheMeta = get(controllerProto, '_cacheMeta'); + + var cacheKey = controllerProto._calculateCacheKey(qp.ctrl, cacheMeta[qp.prop].parts, state.params); + queryParams[qp.fprop] = appCache.lookup(cacheKey, qp.prop, qp.def); + } + } + } + }, + + _scheduleLoadingEvent: function(transition, originRoute) { + this._cancelLoadingEvent(); + this._loadingStateTimer = run.scheduleOnce('routerTransitions', this, '_fireLoadingEvent', transition, originRoute); + }, + + _fireLoadingEvent: function(transition, originRoute) { + if (!this.router.activeTransition) { + // Don't fire an event if we've since moved on from + // the transition that put us in a loading state. + return; + } + + transition.trigger(true, 'loading', transition, originRoute); + }, + + _cancelLoadingEvent: function () { + if (this._loadingStateTimer) { + run.cancel(this._loadingStateTimer); + } + this._loadingStateTimer = null; + } + }); + + /* + Helper function for iterating root-ward, starting + from (but not including) the provided `originRoute`. + + Returns true if the last callback fired requested + to bubble upward. + + @private + */ + function forEachRouteAbove(originRoute, transition, callback) { + var handlerInfos = transition.state.handlerInfos; + var originRouteFound = false; + var handlerInfo, route; + + for (var i = handlerInfos.length - 1; i >= 0; --i) { + handlerInfo = handlerInfos[i]; + route = handlerInfo.handler; + + if (!originRouteFound) { + if (originRoute === route) { + originRouteFound = true; + } + continue; + } + + if (callback(route, handlerInfos[i + 1].handler) !== true) { + return false; + } + } + return true; + } + + // These get invoked when an action bubbles above ApplicationRoute + // and are not meant to be overridable. + var defaultActionHandlers = { + + willResolveModel: function(transition, originRoute) { + originRoute.router._scheduleLoadingEvent(transition, originRoute); + }, + + error: function(error, transition, originRoute) { + // Attempt to find an appropriate error substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childErrorRouteName = findChildRouteName(route, childRoute, 'error'); + if (childErrorRouteName) { + router.intermediateTransitionTo(childErrorRouteName, error); + return; + } + return true; + }); + + if (tryTopLevel) { + // Check for top-level error state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_error')) { + router.intermediateTransitionTo('application_error', error); + return; + } + } + + logError(error, 'Error while processing route: ' + transition.targetName); + }, + + loading: function(transition, originRoute) { + // Attempt to find an appropriate loading substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childLoadingRouteName = findChildRouteName(route, childRoute, 'loading'); + + if (childLoadingRouteName) { + router.intermediateTransitionTo(childLoadingRouteName); + return; + } + + // Don't bubble above pivot route. + if (transition.pivotHandler !== route) { + return true; + } + }); + + if (tryTopLevel) { + // Check for top-level loading state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_loading')) { + router.intermediateTransitionTo('application_loading'); + return; + } + } + } + }; + + function logError(error, initialMessage) { + var errorArgs = []; + + if (initialMessage) { errorArgs.push(initialMessage); } + + if (error) { + if (error.message) { errorArgs.push(error.message); } + if (error.stack) { errorArgs.push(error.stack); } + + if (typeof error === "string") { errorArgs.push(error); } + } + + Ember.Logger.error.apply(this, errorArgs); + } + + function findChildRouteName(parentRoute, originatingChildRoute, name) { + var router = parentRoute.router; + var childName; + var targetChildRouteName = originatingChildRoute.routeName.split('.').pop(); + var namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.'; + + + // Second, try general loading state, e.g. 'loading' + childName = namespace + name; + if (routeHasBeenDefined(router, childName)) { + return childName; + } + } + + function routeHasBeenDefined(router, name) { + var container = router.container; + return router.hasRoute(name) && + (container.has('template:' + name) || container.has('route:' + name)); + } + + function triggerEvent(handlerInfos, ignoreFailure, args) { + var name = args.shift(); + + if (!handlerInfos) { + if (ignoreFailure) { return; } + throw new EmberError("Can't trigger action '" + name + "' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call `.send()` on the `Transition` object passed to the `model/beforeModel/afterModel` hooks."); + } + + var eventWasHandled = false; + var handlerInfo, handler; + + for (var i = handlerInfos.length - 1; i >= 0; i--) { + handlerInfo = handlerInfos[i]; + handler = handlerInfo.handler; + + if (handler._actions && handler._actions[name]) { + if (handler._actions[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (defaultActionHandlers[name]) { + defaultActionHandlers[name].apply(null, args); + return; + } + + if (!eventWasHandled && !ignoreFailure) { + throw new EmberError("Nothing handled the action '" + name + "'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble."); + } + } + + function calculatePostTransitionState(emberRouter, leafRouteName, contexts) { + var routerjs = emberRouter.router; + var state = routerjs.applyIntent(leafRouteName, contexts); + var handlerInfos = state.handlerInfos; + var params = state.params; + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + if (!handlerInfo.isResolved) { + handlerInfo = handlerInfo.becomeResolved(null, handlerInfo.context); + } + params[handlerInfo.name] = handlerInfo.params; + } + return state; + } + + function updatePaths(router) { + var appController = router.container.lookup('controller:application'); + + if (!appController) { + // appController might not exist when top-level loading/error + // substates have been entered since ApplicationRoute hasn't + // actually been entered at that point. + return; + } + + var infos = router.router.currentHandlerInfos; + var path = EmberRouter._routePath(infos); + + if (!('currentPath' in appController)) { + defineProperty(appController, 'currentPath'); + } + + set(appController, 'currentPath', path); + + if (!('currentRouteName' in appController)) { + defineProperty(appController, 'currentRouteName'); + } + + set(appController, 'currentRouteName', infos[infos.length - 1].name); + } + + EmberRouter.reopenClass({ + router: null, + + /** + The `Router.map` function allows you to define mappings from URLs to routes + and resources in your application. These mappings are defined within the + supplied callback function using `this.resource` and `this.route`. + + ```javascript + App.Router.map(function({ + this.route('about'); + this.resource('article'); + })); + ``` + + For more detailed examples please see + [the guides](http://emberjs.com/guides/routing/defining-your-routes/). + + @method map + @param callback + */ + map: function(callback) { + var router = this.router; + if (!router) { + router = new Router(); + + + router._triggerWillChangeContext = Ember.K; + router._triggerWillLeave = Ember.K; + + + router.callbacks = []; + router.triggerEvent = triggerEvent; + this.reopenClass({ router: router }); + } + + var dsl = EmberRouterDSL.map(function() { + this.resource('application', { path: "/" }, function() { + for (var i=0; i < router.callbacks.length; i++) { + router.callbacks[i].call(this); + } + callback.call(this); + }); + }); + + router.callbacks.push(callback); + router.map(dsl.generate()); + return router; + }, + + _routePath: function(handlerInfos) { + var path = []; + + // We have to handle coalescing resource names that + // are prefixed with their parent's names, e.g. + // ['foo', 'foo.bar.baz'] => 'foo.bar.baz', not 'foo.foo.bar.baz' + + function intersectionMatches(a1, a2) { + for (var i = 0, len = a1.length; i < len; ++i) { + if (a1[i] !== a2[i]) { + return false; + } + } + return true; + } + + var name, nameParts, oldNameParts; + for (var i=1, l=handlerInfos.length; i 0) - (diff < 0); + } + + /** + This will compare two javascript values of possibly different types. + It will tell you which one is greater than the other by returning: + + - -1 if the first is smaller than the second, + - 0 if both are equal, + - 1 if the first is greater than the second. + + The order is calculated based on `Ember.ORDER_DEFINITION`, if types are different. + In case they have the same type an appropriate comparison for this type is made. + + ```javascript + Ember.compare('hello', 'hello'); // 0 + Ember.compare('abc', 'dfg'); // -1 + Ember.compare(2, 1); // 1 + ``` + + @method compare + @for Ember + @param {Object} v First value to compare + @param {Object} w Second value to compare + @return {Number} -1 if v < w, 0 if v = w and 1 if v > w. + */ + __exports__["default"] = function compare(v, w) { + if (v === w) { + return 0; + } + + var type1 = typeOf(v); + var type2 = typeOf(w); + + if (Comparable) { + if (type1 ==='instance' && Comparable.detect(v.constructor)) { + return v.constructor.compare(v, w); + } + + if (type2 === 'instance' && Comparable.detect(w.constructor)) { + return 1 - w.constructor.compare(w, v); + } + } + + var res = spaceship(TYPE_ORDER[type1], TYPE_ORDER[type2]); + if (res !== 0) { + return res; + } + + // types are equal - so we have to check values now + switch (type1) { + case 'boolean': + case 'number': + return spaceship(v,w); + + case 'string': + return spaceship(v.localeCompare(w), 0); + + case 'array': + var vLen = v.length; + var wLen = w.length; + var len = Math.min(vLen, wLen); + + for (var i = 0; i < len; i++) { + var r = compare(v[i], w[i]); + if (r !== 0) { + return r; + } + } + + // all elements are equal now + // shorter array should be ordered first + return spaceship(vLen, wLen); + + case 'instance': + if (Comparable && Comparable.detect(v)) { + return v.compare(v, w); + } + return 0; + + case 'date': + return spaceship(v.getTime(), w.getTime()); + + default: + return 0; + } + } + }); +define("ember-runtime/computed/array_computed", + ["ember-metal/core","ember-runtime/computed/reduce_computed","ember-metal/enumerable_utils","ember-metal/platform","ember-metal/observer","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var reduceComputed = __dependency2__.reduceComputed; + var ReduceComputedProperty = __dependency2__.ReduceComputedProperty; + var forEach = __dependency3__.forEach; + var o_create = __dependency4__.create; + var addObserver = __dependency5__.addObserver; + var EmberError = __dependency6__["default"]; + + var a_slice = [].slice; + + function ArrayComputedProperty() { + var cp = this; + + ReduceComputedProperty.apply(this, arguments); + + this.func = (function(reduceFunc) { + return function (propertyName) { + if (!cp._hasInstanceMeta(this, propertyName)) { + // When we recompute an array computed property, we need already + // retrieved arrays to be updated; we can't simply empty the cache and + // hope the array is re-retrieved. + forEach(cp._dependentKeys, function(dependentKey) { + addObserver(this, dependentKey, function() { + cp.recomputeOnce.call(this, propertyName); + }); + }, this); + } + + return reduceFunc.apply(this, arguments); + }; + })(this.func); + + return this; + } + + ArrayComputedProperty.prototype = o_create(ReduceComputedProperty.prototype); + + ArrayComputedProperty.prototype.initialValue = function () { + return Ember.A(); + }; + + ArrayComputedProperty.prototype.resetValue = function (array) { + array.clear(); + return array; + }; + + // This is a stopgap to keep the reference counts correct with lazy CPs. + ArrayComputedProperty.prototype.didChange = function (obj, keyName) { + return; + }; + + /** + Creates a computed property which operates on dependent arrays and + is updated with "one at a time" semantics. When items are added or + removed from the dependent array(s) an array computed only operates + on the change instead of re-evaluating the entire array. This should + return an array, if you'd like to use "one at a time" semantics and + compute some value other then an array look at + `Ember.reduceComputed`. + + If there are more than one arguments the first arguments are + considered to be dependent property keys. The last argument is + required to be an options object. The options object can have the + following three properties. + + `initialize` - An optional initialize function. Typically this will be used + to set up state on the instanceMeta object. + + `removedItem` - A function that is called each time an element is + removed from the array. + + `addedItem` - A function that is called each time an element is + added to the array. + + + The `initialize` function has the following signature: + + ```javascript + function(array, changeMeta, instanceMeta) + ``` + + `array` - The initial value of the arrayComputed, an empty array. + + `changeMeta` - An object which contains meta information about the + computed. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + + The `removedItem` and `addedItem` functions both have the following signature: + + ```javascript + function(accumulatedValue, item, changeMeta, instanceMeta) + ``` + + `accumulatedValue` - The value returned from the last time + `removedItem` or `addedItem` was called or an empty array. + + `item` - the element added or removed from the array + + `changeMeta` - An object which contains meta information about the + change. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + - `index` the index of the added or removed item + - `item` the added or removed item: this is exactly the same as + the second arg + - `arrayChanged` the array that triggered the change. Can be + useful when depending on multiple arrays. + + For property changes triggered on an item property change (when + depKey is something like `someArray.@each.someProperty`), + `changeMeta` will also contain the following property: + + - `previousValues` an object whose keys are the properties that changed on + the item, and whose values are the item's previous values. + + `previousValues` is important Ember coalesces item property changes via + Ember.run.once. This means that by the time removedItem gets called, item has + the new values, but you may need the previous value (eg for sorting & + filtering). + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + The `removedItem` and `addedItem` functions should return the accumulated + value. It is acceptable to not return anything (ie return undefined) + to invalidate the computation. This is generally not a good idea for + arrayComputed but it's used in eg max and min. + + Example + + ```javascript + Ember.computed.map = function(dependentKey, callback) { + var options = { + addedItem: function(array, item, changeMeta, instanceMeta) { + var mapped = callback(item); + array.insertAt(changeMeta.index, mapped); + return array; + }, + removedItem: function(array, item, changeMeta, instanceMeta) { + array.removeAt(changeMeta.index, 1); + return array; + } + }; + + return Ember.arrayComputed(dependentKey, options); + }; + ``` + + @method arrayComputed + @for Ember + @param {String} [dependentKeys*] + @param {Object} options + @return {Ember.ComputedProperty} + */ + function arrayComputed (options) { + var args; + + if (arguments.length > 1) { + args = a_slice.call(arguments, 0, -1); + options = a_slice.call(arguments, -1)[0]; + } + + if (typeof options !== 'object') { + throw new EmberError('Array Computed Property declared without an options hash'); + } + + var cp = new ArrayComputedProperty(options); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + __exports__.arrayComputed = arrayComputed; + __exports__.ArrayComputedProperty = ArrayComputedProperty; + }); +define("ember-runtime/computed/reduce_computed", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/property_events","ember-metal/expand_properties","ember-metal/observer","ember-metal/computed","ember-metal/platform","ember-metal/enumerable_utils","ember-runtime/system/tracked_array","ember-runtime/mixins/array","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var e_get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var metaFor = __dependency4__.meta; + var EmberError = __dependency5__["default"]; + var propertyWillChange = __dependency6__.propertyWillChange; + var propertyDidChange = __dependency6__.propertyDidChange; + var expandProperties = __dependency7__["default"]; + var addObserver = __dependency8__.addObserver; + var observersFor = __dependency8__.observersFor; + var removeObserver = __dependency8__.removeObserver; + var addBeforeObserver = __dependency8__.addBeforeObserver; + var removeBeforeObserver = __dependency8__.removeBeforeObserver; + var ComputedProperty = __dependency9__.ComputedProperty; + var cacheFor = __dependency9__.cacheFor; + var o_create = __dependency10__.create; + var forEach = __dependency11__.forEach; + var TrackedArray = __dependency12__["default"]; + var EmberArray = __dependency13__["default"]; + var run = __dependency14__["default"]; + var isArray = __dependency4__.isArray; + + var cacheSet = cacheFor.set; + var cacheGet = cacheFor.get; + var cacheRemove = cacheFor.remove; + var a_slice = [].slice; + // Here we explicitly don't allow `@each.foo`; it would require some special + // testing, but there's no particular reason why it should be disallowed. + var eachPropertyPattern = /^(.*)\.@each\.(.*)/; + var doubleEachPropertyPattern = /(.*\.@each){2,}/; + var arrayBracketPattern = /\.\[\]$/; + + function get(obj, key) { + if (key === '@this') { + return obj; + } + + return e_get(obj, key); + } + + /* + Tracks changes to dependent arrays, as well as to properties of items in + dependent arrays. + + @class DependentArraysObserver + */ + function DependentArraysObserver(callbacks, cp, instanceMeta, context, propertyName, sugarMeta) { + // user specified callbacks for `addedItem` and `removedItem` + this.callbacks = callbacks; + + // the computed property: remember these are shared across instances + this.cp = cp; + + // the ReduceComputedPropertyInstanceMeta this DependentArraysObserver is + // associated with + this.instanceMeta = instanceMeta; + + // A map of array guids to dependentKeys, for the given context. We track + // this because we want to set up the computed property potentially before the + // dependent array even exists, but when the array observer fires, we lack + // enough context to know what to update: we can recover that context by + // getting the dependentKey. + this.dependentKeysByGuid = {}; + + // a map of dependent array guids -> TrackedArray instances. We use + // this to lazily recompute indexes for item property observers. + this.trackedArraysByGuid = {}; + + // We suspend observers to ignore replacements from `reset` when totally + // recomputing. Unfortunately we cannot properly suspend the observers + // because we only have the key; instead we make the observers no-ops + this.suspended = false; + + // This is used to coalesce item changes from property observers within a + // single item. + this.changedItems = {}; + // This is used to coalesce item changes for multiple items that depend on + // some shared state. + this.changedItemCount = 0; + } + + function ItemPropertyObserverContext (dependentArray, index, trackedArray) { + Ember.assert('Internal error: trackedArray is null or undefined', trackedArray); + + this.dependentArray = dependentArray; + this.index = index; + this.item = dependentArray.objectAt(index); + this.trackedArray = trackedArray; + this.beforeObserver = null; + this.observer = null; + this.destroyed = false; + } + + DependentArraysObserver.prototype = { + setValue: function (newValue) { + this.instanceMeta.setValue(newValue, true); + }, + + getValue: function () { + return this.instanceMeta.getValue(); + }, + + setupObservers: function (dependentArray, dependentKey) { + this.dependentKeysByGuid[guidFor(dependentArray)] = dependentKey; + + dependentArray.addArrayObserver(this, { + willChange: 'dependentArrayWillChange', + didChange: 'dependentArrayDidChange' + }); + + if (this.cp._itemPropertyKeys[dependentKey]) { + this.setupPropertyObservers(dependentKey, this.cp._itemPropertyKeys[dependentKey]); + } + }, + + teardownObservers: function (dependentArray, dependentKey) { + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; + + delete this.dependentKeysByGuid[guidFor(dependentArray)]; + + this.teardownPropertyObservers(dependentKey, itemPropertyKeys); + + dependentArray.removeArrayObserver(this, { + willChange: 'dependentArrayWillChange', + didChange: 'dependentArrayDidChange' + }); + }, + + suspendArrayObservers: function (callback, binding) { + var oldSuspended = this.suspended; + this.suspended = true; + callback.call(binding); + this.suspended = oldSuspended; + }, + + setupPropertyObservers: function (dependentKey, itemPropertyKeys) { + var dependentArray = get(this.instanceMeta.context, dependentKey); + var length = get(dependentArray, 'length'); + var observerContexts = new Array(length); + + this.resetTransformations(dependentKey, observerContexts); + + forEach(dependentArray, function (item, index) { + var observerContext = this.createPropertyObserverContext(dependentArray, index, this.trackedArraysByGuid[dependentKey]); + observerContexts[index] = observerContext; + + forEach(itemPropertyKeys, function (propertyKey) { + addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); + addObserver(item, propertyKey, this, observerContext.observer); + }, this); + }, this); + }, + + teardownPropertyObservers: function (dependentKey, itemPropertyKeys) { + var dependentArrayObserver = this; + var trackedArray = this.trackedArraysByGuid[dependentKey]; + var beforeObserver, observer, item; + + if (!trackedArray) { return; } + + trackedArray.apply(function (observerContexts, offset, operation) { + if (operation === TrackedArray.DELETE) { return; } + + forEach(observerContexts, function (observerContext) { + observerContext.destroyed = true; + beforeObserver = observerContext.beforeObserver; + observer = observerContext.observer; + item = observerContext.item; + + forEach(itemPropertyKeys, function (propertyKey) { + removeBeforeObserver(item, propertyKey, dependentArrayObserver, beforeObserver); + removeObserver(item, propertyKey, dependentArrayObserver, observer); + }); + }); + }); + }, + + createPropertyObserverContext: function (dependentArray, index, trackedArray) { + var observerContext = new ItemPropertyObserverContext(dependentArray, index, trackedArray); + + this.createPropertyObserver(observerContext); + + return observerContext; + }, + + createPropertyObserver: function (observerContext) { + var dependentArrayObserver = this; + + observerContext.beforeObserver = function (obj, keyName) { + return dependentArrayObserver.itemPropertyWillChange(obj, keyName, observerContext.dependentArray, observerContext); + }; + + observerContext.observer = function (obj, keyName) { + return dependentArrayObserver.itemPropertyDidChange(obj, keyName, observerContext.dependentArray, observerContext); + }; + }, + + resetTransformations: function (dependentKey, observerContexts) { + this.trackedArraysByGuid[dependentKey] = new TrackedArray(observerContexts); + }, + + trackAdd: function (dependentKey, index, newItems) { + var trackedArray = this.trackedArraysByGuid[dependentKey]; + + if (trackedArray) { + trackedArray.addItems(index, newItems); + } + }, + + trackRemove: function (dependentKey, index, removedCount) { + var trackedArray = this.trackedArraysByGuid[dependentKey]; + + if (trackedArray) { + return trackedArray.removeItems(index, removedCount); + } + + return []; + }, + + updateIndexes: function (trackedArray, array) { + var length = get(array, 'length'); + // OPTIMIZE: we could stop updating once we hit the object whose observer + // fired; ie partially apply the transformations + trackedArray.apply(function (observerContexts, offset, operation, operationIndex) { + // we don't even have observer contexts for removed items, even if we did, + // they no longer have any index in the array + if (operation === TrackedArray.DELETE) { return; } + if (operationIndex === 0 && operation === TrackedArray.RETAIN && observerContexts.length === length && offset === 0) { + // If we update many items we don't want to walk the array each time: we + // only need to update the indexes at most once per run loop. + return; + } + + forEach(observerContexts, function (context, index) { + context.index = index + offset; + }); + }); + }, + + dependentArrayWillChange: function (dependentArray, index, removedCount, addedCount) { + if (this.suspended) { return; } + + var removedItem = this.callbacks.removedItem; + var changeMeta; + var guid = guidFor(dependentArray); + var dependentKey = this.dependentKeysByGuid[guid]; + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; + var length = get(dependentArray, 'length'); + var normalizedIndex = normalizeIndex(index, length, 0); + var normalizedRemoveCount = normalizeRemoveCount(normalizedIndex, length, removedCount); + var item, itemIndex, sliceIndex, observerContexts; + + observerContexts = this.trackRemove(dependentKey, normalizedIndex, normalizedRemoveCount); + + function removeObservers(propertyKey) { + observerContexts[sliceIndex].destroyed = true; + removeBeforeObserver(item, propertyKey, this, observerContexts[sliceIndex].beforeObserver); + removeObserver(item, propertyKey, this, observerContexts[sliceIndex].observer); + } + + for (sliceIndex = normalizedRemoveCount - 1; sliceIndex >= 0; --sliceIndex) { + itemIndex = normalizedIndex + sliceIndex; + if (itemIndex >= length) { break; } + + item = dependentArray.objectAt(itemIndex); + + forEach(itemPropertyKeys, removeObservers, this); + + changeMeta = new ChangeMeta(dependentArray, item, itemIndex, this.instanceMeta.propertyName, this.cp, normalizedRemoveCount); + this.setValue(removedItem.call( + this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); + } + }, + + dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) { + if (this.suspended) { return; } + + var addedItem = this.callbacks.addedItem; + var guid = guidFor(dependentArray); + var dependentKey = this.dependentKeysByGuid[guid]; + var observerContexts = new Array(addedCount); + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey]; + var length = get(dependentArray, 'length'); + var normalizedIndex = normalizeIndex(index, length, addedCount); + var endIndex = normalizedIndex + addedCount; + var changeMeta, observerContext; + + forEach(dependentArray.slice(normalizedIndex, endIndex), function (item, sliceIndex) { + if (itemPropertyKeys) { + observerContext = this.createPropertyObserverContext(dependentArray, normalizedIndex + sliceIndex, + this.trackedArraysByGuid[dependentKey]); + observerContexts[sliceIndex] = observerContext; + + forEach(itemPropertyKeys, function (propertyKey) { + addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); + addObserver(item, propertyKey, this, observerContext.observer); + }, this); + } + + changeMeta = new ChangeMeta(dependentArray, item, normalizedIndex + sliceIndex, this.instanceMeta.propertyName, this.cp, addedCount); + this.setValue(addedItem.call( + this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); + }, this); + + this.trackAdd(dependentKey, normalizedIndex, observerContexts); + }, + + itemPropertyWillChange: function (obj, keyName, array, observerContext) { + var guid = guidFor(obj); + + if (!this.changedItems[guid]) { + this.changedItems[guid] = { + array: array, + observerContext: observerContext, + obj: obj, + previousValues: {} + }; + } + + ++this.changedItemCount; + this.changedItems[guid].previousValues[keyName] = get(obj, keyName); + }, + + itemPropertyDidChange: function (obj, keyName, array, observerContext) { + if (--this.changedItemCount === 0) { + this.flushChanges(); + } + }, + + flushChanges: function () { + var changedItems = this.changedItems; + var key, c, changeMeta; + + for (key in changedItems) { + c = changedItems[key]; + if (c.observerContext.destroyed) { continue; } + + this.updateIndexes(c.observerContext.trackedArray, c.observerContext.dependentArray); + + changeMeta = new ChangeMeta(c.array, c.obj, c.observerContext.index, this.instanceMeta.propertyName, this.cp, changedItems.length, c.previousValues); + this.setValue( + this.callbacks.removedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); + this.setValue( + this.callbacks.addedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); + } + + this.changedItems = {}; + } + }; + + function normalizeIndex(index, length, newItemsOffset) { + if (index < 0) { + return Math.max(0, length + index); + } else if (index < length) { + return index; + } else /* index > length */ { + return Math.min(length - newItemsOffset, index); + } + } + + function normalizeRemoveCount(index, length, removedCount) { + return Math.min(removedCount, length - index); + } + + function ChangeMeta(dependentArray, item, index, propertyName, property, changedCount, previousValues){ + this.arrayChanged = dependentArray; + this.index = index; + this.item = item; + this.propertyName = propertyName; + this.property = property; + this.changedCount = changedCount; + + if (previousValues) { + // previous values only available for item property changes + this.previousValues = previousValues; + } + } + + function addItems(dependentArray, callbacks, cp, propertyName, meta) { + forEach(dependentArray, function (item, index) { + meta.setValue( callbacks.addedItem.call( + this, meta.getValue(), item, new ChangeMeta(dependentArray, item, index, propertyName, cp, dependentArray.length), meta.sugarMeta)); + }, this); + } + + function reset(cp, propertyName) { + var callbacks = cp._callbacks(); + var hadMeta = cp._hasInstanceMeta(this, propertyName); + var meta = cp._instanceMeta(this, propertyName); + + if (hadMeta) { meta.setValue(cp.resetValue(meta.getValue())); } + + if (cp.options.initialize) { + cp.options.initialize.call(this, meta.getValue(), { + property: cp, + propertyName: propertyName + }, meta.sugarMeta); + } + } + + function partiallyRecomputeFor(obj, dependentKey) { + if (arrayBracketPattern.test(dependentKey)) { + return false; + } + + var value = get(obj, dependentKey); + return EmberArray.detect(value); + } + + function ReduceComputedPropertyInstanceMeta(context, propertyName, initialValue) { + this.context = context; + this.propertyName = propertyName; + this.cache = metaFor(context).cache; + this.dependentArrays = {}; + this.sugarMeta = {}; + this.initialValue = initialValue; + } + + ReduceComputedPropertyInstanceMeta.prototype = { + getValue: function () { + var value = cacheGet(this.cache, this.propertyName); + + if (value !== undefined) { + return value; + } else { + return this.initialValue; + } + }, + + setValue: function(newValue, triggerObservers) { + // This lets sugars force a recomputation, handy for very simple + // implementations of eg max. + if (newValue === cacheGet(this.cache, this.propertyName)) { + return; + } + + if (triggerObservers) { + propertyWillChange(this.context, this.propertyName); + } + + if (newValue === undefined) { + cacheRemove(this.cache, this.propertyName); + } else { + cacheSet(this.cache, this.propertyName, newValue); + } + + if (triggerObservers) { + propertyDidChange(this.context, this.propertyName); + } + } + }; + + /** + A computed property whose dependent keys are arrays and which is updated with + "one at a time" semantics. + + @class ReduceComputedProperty + @namespace Ember + @extends Ember.ComputedProperty + @constructor + */ + + __exports__.ReduceComputedProperty = ReduceComputedProperty; + // TODO: default export + + function ReduceComputedProperty(options) { + var cp = this; + + this.options = options; + this._dependentKeys = null; + // A map of dependentKey -> [itemProperty, ...] that tracks what properties of + // items in the array we must track to update this property. + this._itemPropertyKeys = {}; + this._previousItemPropertyKeys = {}; + + this.readOnly(); + this.cacheable(); + + this.recomputeOnce = function(propertyName) { + // What we really want to do is coalesce by . + // We need a form of `scheduleOnce` that accepts an arbitrary token to + // coalesce by, in addition to the target and method. + run.once(this, recompute, propertyName); + }; + + var recompute = function(propertyName) { + var dependentKeys = cp._dependentKeys; + var meta = cp._instanceMeta(this, propertyName); + var callbacks = cp._callbacks(); + + reset.call(this, cp, propertyName); + + meta.dependentArraysObserver.suspendArrayObservers(function () { + forEach(cp._dependentKeys, function (dependentKey) { + Ember.assert( + 'dependent array ' + dependentKey + ' must be an `Ember.Array`. ' + + 'If you are not extending arrays, you will need to wrap native arrays with `Ember.A`', + !(isArray(get(this, dependentKey)) && !EmberArray.detect(get(this, dependentKey)))); + + if (!partiallyRecomputeFor(this, dependentKey)) { return; } + + var dependentArray = get(this, dependentKey); + var previousDependentArray = meta.dependentArrays[dependentKey]; + + if (dependentArray === previousDependentArray) { + // The array may be the same, but our item property keys may have + // changed, so we set them up again. We can't easily tell if they've + // changed: the array may be the same object, but with different + // contents. + if (cp._previousItemPropertyKeys[dependentKey]) { + delete cp._previousItemPropertyKeys[dependentKey]; + meta.dependentArraysObserver.setupPropertyObservers(dependentKey, cp._itemPropertyKeys[dependentKey]); + } + } else { + meta.dependentArrays[dependentKey] = dependentArray; + + if (previousDependentArray) { + meta.dependentArraysObserver.teardownObservers(previousDependentArray, dependentKey); + } + + if (dependentArray) { + meta.dependentArraysObserver.setupObservers(dependentArray, dependentKey); + } + } + }, this); + }, this); + + forEach(cp._dependentKeys, function(dependentKey) { + if (!partiallyRecomputeFor(this, dependentKey)) { return; } + + var dependentArray = get(this, dependentKey); + + if (dependentArray) { + addItems.call(this, dependentArray, callbacks, cp, propertyName, meta); + } + }, this); + }; + + + this.func = function (propertyName) { + Ember.assert('Computed reduce values require at least one dependent key', cp._dependentKeys); + + recompute.call(this, propertyName); + + return cp._instanceMeta(this, propertyName).getValue(); + }; + } + + ReduceComputedProperty.prototype = o_create(ComputedProperty.prototype); + + function defaultCallback(computedValue) { + return computedValue; + } + + ReduceComputedProperty.prototype._callbacks = function () { + if (!this.callbacks) { + var options = this.options; + + this.callbacks = { + removedItem: options.removedItem || defaultCallback, + addedItem: options.addedItem || defaultCallback + }; + } + + return this.callbacks; + }; + + ReduceComputedProperty.prototype._hasInstanceMeta = function (context, propertyName) { + return !!metaFor(context).cacheMeta[propertyName]; + }; + + ReduceComputedProperty.prototype._instanceMeta = function (context, propertyName) { + var cacheMeta = metaFor(context).cacheMeta; + var meta = cacheMeta[propertyName]; + + if (!meta) { + meta = cacheMeta[propertyName] = new ReduceComputedPropertyInstanceMeta(context, propertyName, this.initialValue()); + meta.dependentArraysObserver = new DependentArraysObserver(this._callbacks(), this, meta, context, propertyName, meta.sugarMeta); + } + + return meta; + }; + + ReduceComputedProperty.prototype.initialValue = function () { + if (typeof this.options.initialValue === 'function') { + return this.options.initialValue(); + } + else { + return this.options.initialValue; + } + }; + + ReduceComputedProperty.prototype.resetValue = function (value) { + return this.initialValue(); + }; + + ReduceComputedProperty.prototype.itemPropertyKey = function (dependentArrayKey, itemPropertyKey) { + this._itemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey] || []; + this._itemPropertyKeys[dependentArrayKey].push(itemPropertyKey); + }; + + ReduceComputedProperty.prototype.clearItemPropertyKeys = function (dependentArrayKey) { + if (this._itemPropertyKeys[dependentArrayKey]) { + this._previousItemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey]; + this._itemPropertyKeys[dependentArrayKey] = []; + } + }; + + ReduceComputedProperty.prototype.property = function () { + var cp = this; + var args = a_slice.call(arguments); + var propertyArgs = {}; + var match, dependentArrayKey, itemPropertyKey; + + forEach(args, function (dependentKey) { + if (doubleEachPropertyPattern.test(dependentKey)) { + throw new EmberError('Nested @each properties not supported: ' + dependentKey); + } else if (match = eachPropertyPattern.exec(dependentKey)) { + dependentArrayKey = match[1]; + + var itemPropertyKeyPattern = match[2]; + var addItemPropertyKey = function (itemPropertyKey) { + cp.itemPropertyKey(dependentArrayKey, itemPropertyKey); + }; + + expandProperties(itemPropertyKeyPattern, addItemPropertyKey); + propertyArgs[guidFor(dependentArrayKey)] = dependentArrayKey; + } else { + propertyArgs[guidFor(dependentKey)] = dependentKey; + } + }); + + var propertyArgsToArray = []; + for (var guid in propertyArgs) { + propertyArgsToArray.push(propertyArgs[guid]); + } + + return ComputedProperty.prototype.property.apply(this, propertyArgsToArray); + }; + + /** + Creates a computed property which operates on dependent arrays and + is updated with "one at a time" semantics. When items are added or + removed from the dependent array(s) a reduce computed only operates + on the change instead of re-evaluating the entire array. + + If there are more than one arguments the first arguments are + considered to be dependent property keys. The last argument is + required to be an options object. The options object can have the + following four properties: + + `initialValue` - A value or function that will be used as the initial + value for the computed. If this property is a function the result of calling + the function will be used as the initial value. This property is required. + + `initialize` - An optional initialize function. Typically this will be used + to set up state on the instanceMeta object. + + `removedItem` - A function that is called each time an element is removed + from the array. + + `addedItem` - A function that is called each time an element is added to + the array. + + + The `initialize` function has the following signature: + + ```javascript + function(initialValue, changeMeta, instanceMeta) + ``` + + `initialValue` - The value of the `initialValue` property from the + options object. + + `changeMeta` - An object which contains meta information about the + computed. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + + The `removedItem` and `addedItem` functions both have the following signature: + + ```javascript + function(accumulatedValue, item, changeMeta, instanceMeta) + ``` + + `accumulatedValue` - The value returned from the last time + `removedItem` or `addedItem` was called or `initialValue`. + + `item` - the element added or removed from the array + + `changeMeta` - An object which contains meta information about the + change. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + - `index` the index of the added or removed item + - `item` the added or removed item: this is exactly the same as + the second arg + - `arrayChanged` the array that triggered the change. Can be + useful when depending on multiple arrays. + + For property changes triggered on an item property change (when + depKey is something like `someArray.@each.someProperty`), + `changeMeta` will also contain the following property: + + - `previousValues` an object whose keys are the properties that changed on + the item, and whose values are the item's previous values. + + `previousValues` is important Ember coalesces item property changes via + Ember.run.once. This means that by the time removedItem gets called, item has + the new values, but you may need the previous value (eg for sorting & + filtering). + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + The `removedItem` and `addedItem` functions should return the accumulated + value. It is acceptable to not return anything (ie return undefined) + to invalidate the computation. This is generally not a good idea for + arrayComputed but it's used in eg max and min. + + Note that observers will be fired if either of these functions return a value + that differs from the accumulated value. When returning an object that + mutates in response to array changes, for example an array that maps + everything from some other array (see `Ember.computed.map`), it is usually + important that the *same* array be returned to avoid accidentally triggering observers. + + Example + + ```javascript + Ember.computed.max = function(dependentKey) { + return Ember.reduceComputed(dependentKey, { + initialValue: -Infinity, + + addedItem: function(accumulatedValue, item, changeMeta, instanceMeta) { + return Math.max(accumulatedValue, item); + }, + + removedItem: function(accumulatedValue, item, changeMeta, instanceMeta) { + if (item < accumulatedValue) { + return accumulatedValue; + } + } + }); + }; + ``` + + Dependent keys may refer to `@this` to observe changes to the object itself, + which must be array-like, rather than a property of the object. This is + mostly useful for array proxies, to ensure objects are retrieved via + `objectAtContent`. This is how you could sort items by properties defined on an item controller. + + Example + + ```javascript + App.PeopleController = Ember.ArrayController.extend({ + itemController: 'person', + + sortedPeople: Ember.computed.sort('@this.@each.reversedName', function(personA, personB) { + // `reversedName` isn't defined on Person, but we have access to it via + // the item controller App.PersonController. If we'd used + // `content.@each.reversedName` above, we would be getting the objects + // directly and not have access to `reversedName`. + // + var reversedNameA = get(personA, 'reversedName'); + var reversedNameB = get(personB, 'reversedName'); + + return Ember.compare(reversedNameA, reversedNameB); + }) + }); + + App.PersonController = Ember.ObjectController.extend({ + reversedName: function() { + return reverse(get(this, 'name')); + }.property('name') + }); + ``` + + Dependent keys whose values are not arrays are treated as regular + dependencies: when they change, the computed property is completely + recalculated. It is sometimes useful to have dependent arrays with similar + semantics. Dependent keys which end in `.[]` do not use "one at a time" + semantics. When an item is added or removed from such a dependency, the + computed property is completely recomputed. + + When the computed property is completely recomputed, the `accumulatedValue` + is discarded, it starts with `initialValue` again, and each item is passed + to `addedItem` in turn. + + Example + + ```javascript + Ember.Object.extend({ + // When `string` is changed, `computed` is completely recomputed. + string: 'a string', + + // When an item is added to `array`, `addedItem` is called. + array: [], + + // When an item is added to `anotherArray`, `computed` is completely + // recomputed. + anotherArray: [], + + computed: Ember.reduceComputed('string', 'array', 'anotherArray.[]', { + addedItem: addedItemCallback, + removedItem: removedItemCallback + }) + }); + ``` + + @method reduceComputed + @for Ember + @param {String} [dependentKeys*] + @param {Object} options + @return {Ember.ComputedProperty} + */ + function reduceComputed(options) { + var args; + + if (arguments.length > 1) { + args = a_slice.call(arguments, 0, -1); + options = a_slice.call(arguments, -1)[0]; + } + + if (typeof options !== 'object') { + throw new EmberError('Reduce Computed Property declared without an options hash'); + } + + if (!('initialValue' in options)) { + throw new EmberError('Reduce Computed Property declared without an initial value'); + } + + var cp = new ReduceComputedProperty(options); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + __exports__.reduceComputed = reduceComputed; + }); +define("ember-runtime/computed/reduce_computed_macros", + ["ember-metal/core","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/enumerable_utils","ember-metal/run_loop","ember-metal/observer","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/system/object_proxy","ember-runtime/system/subarray","ember-metal/keys","ember-runtime/compare","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var merge = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var isArray = __dependency5__.isArray; + var guidFor = __dependency5__.guidFor; + var EmberError = __dependency6__["default"]; + var forEach = __dependency7__.forEach; + var run = __dependency8__["default"]; + var addObserver = __dependency9__.addObserver; + var arrayComputed = __dependency10__.arrayComputed; + var reduceComputed = __dependency11__.reduceComputed; + var ObjectProxy = __dependency12__["default"]; + var SubArray = __dependency13__["default"]; + var keys = __dependency14__["default"]; + var compare = __dependency15__["default"]; + + var a_slice = [].slice; + + /** + A computed property that returns the sum of the value + in the dependent array. + + @method computed.sum + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the sum of all values in the dependentKey's array + @since 1.4.0 + */ + + function sum(dependentKey){ + return reduceComputed(dependentKey, { + initialValue: 0, + + addedItem: function(accumulatedValue, item, changeMeta, instanceMeta){ + return accumulatedValue + item; + }, + + removedItem: function(accumulatedValue, item, changeMeta, instanceMeta){ + return accumulatedValue - item; + } + }); + } + + __exports__.sum = sum;/** + A computed property that calculates the maximum value in the + dependent array. This will return `-Infinity` when the dependent + array is empty. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age'), + maxChildAge: Ember.computed.max('childAges') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('maxChildAge'); // -Infinity + lordByron.get('children').pushObject({ + name: 'Augusta Ada Byron', age: 7 + }); + lordByron.get('maxChildAge'); // 7 + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('maxChildAge'); // 8 + ``` + + @method computed.max + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the largest value in the dependentKey's array + */ + function max(dependentKey) { + return reduceComputed(dependentKey, { + initialValue: -Infinity, + + addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + return Math.max(accumulatedValue, item); + }, + + removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + if (item < accumulatedValue) { + return accumulatedValue; + } + } + }); + } + + __exports__.max = max;/** + A computed property that calculates the minimum value in the + dependent array. This will return `Infinity` when the dependent + array is empty. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age'), + minChildAge: Ember.computed.min('childAges') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('minChildAge'); // Infinity + lordByron.get('children').pushObject({ + name: 'Augusta Ada Byron', age: 7 + }); + lordByron.get('minChildAge'); // 7 + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('minChildAge'); // 5 + ``` + + @method computed.min + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the smallest value in the dependentKey's array + */ + function min(dependentKey) { + return reduceComputed(dependentKey, { + initialValue: Infinity, + + addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + return Math.min(accumulatedValue, item); + }, + + removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + if (item > accumulatedValue) { + return accumulatedValue; + } + } + }); + } + + __exports__.min = min;/** + Returns an array mapped via the callback + + The callback method you provide should have the following signature. + `item` is the current item in the iteration. + `index` is the integer index of the current item in the iteration. + + ```javascript + function(item, index); + ``` + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + excitingChores: Ember.computed.map('chores', function(chore, index) { + return chore.toUpperCase() + '!'; + }) + }); + + var hamster = Hamster.create({ + chores: ['clean', 'write more unit tests'] + }); + + hamster.get('excitingChores'); // ['CLEAN!', 'WRITE MORE UNIT TESTS!'] + ``` + + @method computed.map + @for Ember + @param {String} dependentKey + @param {Function} callback + @return {Ember.ComputedProperty} an array mapped via the callback + */ + function map(dependentKey, callback) { + var options = { + addedItem: function(array, item, changeMeta, instanceMeta) { + var mapped = callback.call(this, item, changeMeta.index); + array.insertAt(changeMeta.index, mapped); + return array; + }, + removedItem: function(array, item, changeMeta, instanceMeta) { + array.removeAt(changeMeta.index, 1); + return array; + } + }; + + return arrayComputed(dependentKey, options); + } + + __exports__.map = map;/** + Returns an array mapped to the specified key. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('childAges'); // [] + lordByron.get('children').pushObject({ name: 'Augusta Ada Byron', age: 7 }); + lordByron.get('childAges'); // [7] + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('childAges'); // [7, 5, 8] + ``` + + @method computed.mapBy + @for Ember + @param {String} dependentKey + @param {String} propertyKey + @return {Ember.ComputedProperty} an array mapped to the specified key + */ + function mapBy (dependentKey, propertyKey) { + var callback = function(item) { return get(item, propertyKey); }; + return map(dependentKey + '.@each.' + propertyKey, callback); + } + + __exports__.mapBy = mapBy;/** + @method computed.mapProperty + @for Ember + @deprecated Use `Ember.computed.mapBy` instead + @param dependentKey + @param propertyKey + */ + var mapProperty = mapBy; + __exports__.mapProperty = mapProperty; + /** + Filters the array by the callback. + + The callback method you provide should have the following signature. + `item` is the current item in the iteration. + `index` is the integer index of the current item in the iteration. + + ```javascript + function(item, index); + ``` + + ```javascript + var Hamster = Ember.Object.extend({ + remainingChores: Ember.computed.filter('chores', function(chore, index) { + return !chore.done; + }) + }); + + var hamster = Hamster.create({ + chores: [ + { name: 'cook', done: true }, + { name: 'clean', done: true }, + { name: 'write more unit tests', done: false } + ] + }); + + hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] + ``` + + @method computed.filter + @for Ember + @param {String} dependentKey + @param {Function} callback + @return {Ember.ComputedProperty} the filtered array + */ + function filter(dependentKey, callback) { + var options = { + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.filteredArrayIndexes = new SubArray(); + }, + + addedItem: function (array, item, changeMeta, instanceMeta) { + var match = !!callback.call(this, item, changeMeta.index); + var filterIndex = instanceMeta.filteredArrayIndexes.addItem(changeMeta.index, match); + + if (match) { + array.insertAt(filterIndex, item); + } + + return array; + }, + + removedItem: function(array, item, changeMeta, instanceMeta) { + var filterIndex = instanceMeta.filteredArrayIndexes.removeItem(changeMeta.index); + + if (filterIndex > -1) { + array.removeAt(filterIndex); + } + + return array; + } + }; + + return arrayComputed(dependentKey, options); + } + + __exports__.filter = filter;/** + Filters the array by the property and value + + ```javascript + var Hamster = Ember.Object.extend({ + remainingChores: Ember.computed.filterBy('chores', 'done', false) + }); + + var hamster = Hamster.create({ + chores: [ + { name: 'cook', done: true }, + { name: 'clean', done: true }, + { name: 'write more unit tests', done: false } + ] + }); + + hamster.get('remainingChores'); // [{ name: 'write more unit tests', done: false }] + ``` + + @method computed.filterBy + @for Ember + @param {String} dependentKey + @param {String} propertyKey + @param {*} value + @return {Ember.ComputedProperty} the filtered array + */ + function filterBy (dependentKey, propertyKey, value) { + var callback; + + if (arguments.length === 2) { + callback = function(item) { + return get(item, propertyKey); + }; + } else { + callback = function(item) { + return get(item, propertyKey) === value; + }; + } + + return filter(dependentKey + '.@each.' + propertyKey, callback); + } + + __exports__.filterBy = filterBy;/** + @method computed.filterProperty + @for Ember + @param dependentKey + @param propertyKey + @param value + @deprecated Use `Ember.computed.filterBy` instead + */ + var filterProperty = filterBy; + __exports__.filterProperty = filterProperty; + /** + A computed property which returns a new array with all the unique + elements from one or more dependent arrays. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + uniqueFruits: Ember.computed.uniq('fruits') + }); + + var hamster = Hamster.create({ + fruits: [ + 'banana', + 'grape', + 'kale', + 'banana' + ] + }); + + hamster.get('uniqueFruits'); // ['banana', 'grape', 'kale'] + ``` + + @method computed.uniq + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + unique elements from the dependent array + */ + function uniq() { + var args = a_slice.call(arguments); + + args.push({ + initialize: function(array, changeMeta, instanceMeta) { + instanceMeta.itemCounts = {}; + }, + + addedItem: function(array, item, changeMeta, instanceMeta) { + var guid = guidFor(item); + + if (!instanceMeta.itemCounts[guid]) { + instanceMeta.itemCounts[guid] = 1; + array.pushObject(item); + } else { + ++instanceMeta.itemCounts[guid]; + } + return array; + }, + + removedItem: function(array, item, _, instanceMeta) { + var guid = guidFor(item); + var itemCounts = instanceMeta.itemCounts; + + if (--itemCounts[guid] === 0) { + array.removeObject(item); + } + + return array; + } + }); + + return arrayComputed.apply(null, args); + } + + __exports__.uniq = uniq;/** + Alias for [Ember.computed.uniq](/api/#method_computed_uniq). + + @method computed.union + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + unique elements from the dependent array + */ + var union = uniq; + __exports__.union = union; + /** + A computed property which returns a new array with all the duplicated + elements from two or more dependent arrays. + + Example + + ```javascript + var obj = Ember.Object.createWithMixins({ + adaFriends: ['Charles Babbage', 'John Hobhouse', 'William King', 'Mary Somerville'], + charlesFriends: ['William King', 'Mary Somerville', 'Ada Lovelace', 'George Peacock'], + friendsInCommon: Ember.computed.intersect('adaFriends', 'charlesFriends') + }); + + obj.get('friendsInCommon'); // ['William King', 'Mary Somerville'] + ``` + + @method computed.intersect + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + duplicated elements from the dependent arrays + */ + function intersect() { + var args = a_slice.call(arguments); + + args.push({ + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.itemCounts = {}; + }, + + addedItem: function(array, item, changeMeta, instanceMeta) { + var itemGuid = guidFor(item); + var dependentGuid = guidFor(changeMeta.arrayChanged); + var numberOfDependentArrays = changeMeta.property._dependentKeys.length; + var itemCounts = instanceMeta.itemCounts; + + if (!itemCounts[itemGuid]) { + itemCounts[itemGuid] = {}; + } + + if (itemCounts[itemGuid][dependentGuid] === undefined) { + itemCounts[itemGuid][dependentGuid] = 0; + } + + if (++itemCounts[itemGuid][dependentGuid] === 1 && + numberOfDependentArrays === keys(itemCounts[itemGuid]).length) { + array.addObject(item); + } + + return array; + }, + + removedItem: function(array, item, changeMeta, instanceMeta) { + var itemGuid = guidFor(item); + var dependentGuid = guidFor(changeMeta.arrayChanged); + var numberOfDependentArrays = changeMeta.property._dependentKeys.length; + var numberOfArraysItemAppearsIn; + var itemCounts = instanceMeta.itemCounts; + + if (itemCounts[itemGuid][dependentGuid] === undefined) { + itemCounts[itemGuid][dependentGuid] = 0; + } + + if (--itemCounts[itemGuid][dependentGuid] === 0) { + delete itemCounts[itemGuid][dependentGuid]; + numberOfArraysItemAppearsIn = keys(itemCounts[itemGuid]).length; + + if (numberOfArraysItemAppearsIn === 0) { + delete itemCounts[itemGuid]; + } + + array.removeObject(item); + } + + return array; + } + }); + + return arrayComputed.apply(null, args); + } + + __exports__.intersect = intersect;/** + A computed property which returns a new array with all the + properties from the first dependent array that are not in the second + dependent array. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + likes: ['banana', 'grape', 'kale'], + wants: Ember.computed.setDiff('likes', 'fruits') + }); + + var hamster = Hamster.create({ + fruits: [ + 'grape', + 'kale', + ] + }); + + hamster.get('wants'); // ['banana'] + ``` + + @method computed.setDiff + @for Ember + @param {String} setAProperty + @param {String} setBProperty + @return {Ember.ComputedProperty} computes a new array with all the + items from the first dependent array that are not in the second + dependent array + */ + function setDiff(setAProperty, setBProperty) { + if (arguments.length !== 2) { + throw new EmberError('setDiff requires exactly two dependent arrays.'); + } + + return arrayComputed(setAProperty, setBProperty, { + addedItem: function (array, item, changeMeta, instanceMeta) { + var setA = get(this, setAProperty); + var setB = get(this, setBProperty); + + if (changeMeta.arrayChanged === setA) { + if (!setB.contains(item)) { + array.addObject(item); + } + } else { + array.removeObject(item); + } + + return array; + }, + + removedItem: function (array, item, changeMeta, instanceMeta) { + var setA = get(this, setAProperty); + var setB = get(this, setBProperty); + + if (changeMeta.arrayChanged === setB) { + if (setA.contains(item)) { + array.addObject(item); + } + } else { + array.removeObject(item); + } + + return array; + } + }); + } + + __exports__.setDiff = setDiff;function binarySearch(array, item, low, high) { + var mid, midItem, res, guidMid, guidItem; + + if (arguments.length < 4) { + high = get(array, 'length'); + } + + if (arguments.length < 3) { + low = 0; + } + + if (low === high) { + return low; + } + + mid = low + Math.floor((high - low) / 2); + midItem = array.objectAt(mid); + + guidMid = _guidFor(midItem); + guidItem = _guidFor(item); + + if (guidMid === guidItem) { + return mid; + } + + res = this.order(midItem, item); + + if (res === 0) { + res = guidMid < guidItem ? -1 : 1; + } + + + if (res < 0) { + return this.binarySearch(array, item, mid+1, high); + } else if (res > 0) { + return this.binarySearch(array, item, low, mid); + } + + return mid; + + function _guidFor(item) { + if (SearchProxy.detectInstance(item)) { + return guidFor(get(item, 'content')); + } + + return guidFor(item); + } + } + + + var SearchProxy = ObjectProxy.extend(); + + /** + A computed property which returns a new array with all the + properties from the first dependent array sorted based on a property + or sort function. + + The callback method you provide should have the following signature: + + ```javascript + function(itemA, itemB); + ``` + + - `itemA` the first item to compare. + - `itemB` the second item to compare. + + This function should return negative number (e.g. `-1`) when `itemA` should come before + `itemB`. It should return positive number (e.g. `1`) when `itemA` should come after + `itemB`. If the `itemA` and `itemB` are equal this function should return `0`. + + Therefore, if this function is comparing some numeric values, simple `itemA - itemB` or + `itemA.get( 'foo' ) - itemB.get( 'foo' )` can be used instead of series of `if`. + + Example + + ```javascript + var ToDoList = Ember.Object.extend({ + // using standard ascending sort + todosSorting: ['name'], + sortedTodos: Ember.computed.sort('todos', 'todosSorting'), + + // using descending sort + todosSortingDesc: ['name:desc'], + sortedTodosDesc: Ember.computed.sort('todos', 'todosSortingDesc'), + + // using a custom sort function + priorityTodos: Ember.computed.sort('todos', function(a, b){ + if (a.priority > b.priority) { + return 1; + } else if (a.priority < b.priority) { + return -1; + } + + return 0; + }) + }); + + var todoList = ToDoList.create({todos: [ + { name: 'Unit Test', priority: 2 }, + { name: 'Documentation', priority: 3 }, + { name: 'Release', priority: 1 } + ]}); + + todoList.get('sortedTodos'); // [{ name:'Documentation', priority:3 }, { name:'Release', priority:1 }, { name:'Unit Test', priority:2 }] + todoList.get('sortedTodosDesc'); // [{ name:'Unit Test', priority:2 }, { name:'Release', priority:1 }, { name:'Documentation', priority:3 }] + todoList.get('priorityTodos'); // [{ name:'Release', priority:1 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] + ``` + + @method computed.sort + @for Ember + @param {String} dependentKey + @param {String or Function} sortDefinition a dependent key to an + array of sort properties (add `:desc` to the arrays sort properties to sort descending) or a function to use when sorting + @return {Ember.ComputedProperty} computes a new sorted array based + on the sort property array or callback function + */ + function sort(itemsKey, sortDefinition) { + Ember.assert('Ember.computed.sort requires two arguments: an array key to sort and ' + + 'either a sort properties key or sort function', arguments.length === 2); + + var initFn, sortPropertiesKey; + + if (typeof sortDefinition === 'function') { + initFn = function (array, changeMeta, instanceMeta) { + instanceMeta.order = sortDefinition; + instanceMeta.binarySearch = binarySearch; + }; + } else { + sortPropertiesKey = sortDefinition; + + initFn = function (array, changeMeta, instanceMeta) { + function setupSortProperties() { + var sortPropertyDefinitions = get(this, sortPropertiesKey); + var sortProperties = instanceMeta.sortProperties = []; + var sortPropertyAscending = instanceMeta.sortPropertyAscending = {}; + var sortProperty, idx, asc; + + Ember.assert('Cannot sort: \'' + sortPropertiesKey + '\' is not an array.', + isArray(sortPropertyDefinitions)); + + changeMeta.property.clearItemPropertyKeys(itemsKey); + + forEach(sortPropertyDefinitions, function (sortPropertyDefinition) { + if ((idx = sortPropertyDefinition.indexOf(':')) !== -1) { + sortProperty = sortPropertyDefinition.substring(0, idx); + asc = sortPropertyDefinition.substring(idx+1).toLowerCase() !== 'desc'; + } else { + sortProperty = sortPropertyDefinition; + asc = true; + } + + sortProperties.push(sortProperty); + sortPropertyAscending[sortProperty] = asc; + changeMeta.property.itemPropertyKey(itemsKey, sortProperty); + }); + + sortPropertyDefinitions.addObserver('@each', this, updateSortPropertiesOnce); + } + + function updateSortPropertiesOnce() { + run.once(this, updateSortProperties, changeMeta.propertyName); + } + + function updateSortProperties(propertyName) { + setupSortProperties.call(this); + changeMeta.property.recomputeOnce.call(this, propertyName); + } + + addObserver(this, sortPropertiesKey, updateSortPropertiesOnce); + setupSortProperties.call(this); + + instanceMeta.order = function (itemA, itemB) { + var isProxy = itemB instanceof SearchProxy; + var sortProperty, result, asc; + + for (var i = 0; i < this.sortProperties.length; ++i) { + sortProperty = this.sortProperties[i]; + result = compare(get(itemA, sortProperty), isProxy ? itemB[sortProperty] : get(itemB, sortProperty)); + + if (result !== 0) { + asc = this.sortPropertyAscending[sortProperty]; + return asc ? result : (-1 * result); + } + } + + return 0; + }; + + instanceMeta.binarySearch = binarySearch; + }; + } + + return arrayComputed(itemsKey, { + initialize: initFn, + + addedItem: function (array, item, changeMeta, instanceMeta) { + var index = instanceMeta.binarySearch(array, item); + array.insertAt(index, item); + + return array; + }, + + removedItem: function (array, item, changeMeta, instanceMeta) { + var proxyProperties, index, searchItem; + + if (changeMeta.previousValues) { + proxyProperties = merge({ content: item }, changeMeta.previousValues); + + searchItem = SearchProxy.create(proxyProperties); + } else { + searchItem = item; + } + + index = instanceMeta.binarySearch(array, searchItem); + array.removeAt(index); + + return array; + } + }); + } + + __exports__.sort = sort; + }); +define("ember-runtime/controllers/array_controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/enumerable_utils","ember-runtime/system/array_proxy","ember-runtime/mixins/sortable","ember-runtime/mixins/controller","ember-metal/computed","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var forEach = __dependency4__.forEach; + var replace = __dependency4__.replace; + var ArrayProxy = __dependency5__["default"]; + var SortableMixin = __dependency6__["default"]; + var ControllerMixin = __dependency7__["default"]; + var computed = __dependency8__.computed; + var EmberError = __dependency9__["default"]; + + + /** + `Ember.ArrayController` provides a way for you to publish a collection of + objects so that you can easily bind to the collection from a Handlebars + `#each` helper, an `Ember.CollectionView`, or other controllers. + + The advantage of using an `ArrayController` is that you only have to set up + your view bindings once; to change what's displayed, simply swap out the + `model` property on the controller. + + For example, imagine you wanted to display a list of items fetched via an XHR + request. Create an `Ember.ArrayController` and set its `model` property: + + ```javascript + MyApp.listController = Ember.ArrayController.create(); + + $.get('people.json', function(data) { + MyApp.listController.set('model', data); + }); + ``` + + Then, create a view that binds to your new controller: + + ```handlebars + {{#each MyApp.listController}} + {{firstName}} {{lastName}} + {{/each}} + ``` + + Although you are binding to the controller, the behavior of this controller + is to pass through any methods or properties to the underlying array. This + capability comes from `Ember.ArrayProxy`, which this class inherits from. + + Sometimes you want to display computed properties within the body of an + `#each` helper that depend on the underlying items in `model`, but are not + present on those items. To do this, set `itemController` to the name of a + controller (probably an `ObjectController`) that will wrap each individual item. + + For example: + + ```handlebars + {{#each post in controller}} +
  • {{post.title}} ({{post.titleLength}} characters)
  • + {{/each}} + ``` + + ```javascript + App.PostsController = Ember.ArrayController.extend({ + itemController: 'post' + }); + + App.PostController = Ember.ObjectController.extend({ + // the `title` property will be proxied to the underlying post. + titleLength: function() { + return this.get('title').length; + }.property('title') + }); + ``` + + In some cases it is helpful to return a different `itemController` depending + on the particular item. Subclasses can do this by overriding + `lookupItemController`. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + lookupItemController: function( object ) { + if (object.get('isSpecial')) { + return "special"; // use App.SpecialController + } else { + return "regular"; // use App.RegularController + } + } + }); + ``` + + The itemController instances will have a `parentController` property set to + the `ArrayController` instance. + + @class ArrayController + @namespace Ember + @extends Ember.ArrayProxy + @uses Ember.SortableMixin + @uses Ember.ControllerMixin + */ + + __exports__["default"] = ArrayProxy.extend(ControllerMixin, SortableMixin, { + + /** + The controller used to wrap items, if any. If the value is a string, it will + be used to lookup the container for the controller. As an alternative, you + can also provide a controller class as the value. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + itemController: Ember.ObjectController.extend({ + //Item Controller Implementation + }) + }); + ``` + + @property itemController + @type String | Ember.Controller + @default null + */ + itemController: null, + + /** + Return the name of the controller to wrap items, or `null` if items should + be returned directly. The default implementation simply returns the + `itemController` property, but subclasses can override this method to return + different controllers for different objects. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + lookupItemController: function( object ) { + if (object.get('isSpecial')) { + return "special"; // use App.SpecialController + } else { + return "regular"; // use App.RegularController + } + } + }); + ``` + + @method lookupItemController + @param {Object} object + @return {String} + */ + lookupItemController: function(object) { + return get(this, 'itemController'); + }, + + objectAtContent: function(idx) { + var length = get(this, 'length'); + var arrangedContent = get(this, 'arrangedContent'); + var object = arrangedContent && arrangedContent.objectAt(idx); + var controllerClass; + + if (idx >= 0 && idx < length) { + controllerClass = this.lookupItemController(object); + + if (controllerClass) { + return this.controllerAt(idx, object, controllerClass); + } + } + + // When `controllerClass` is falsy, we have not opted in to using item + // controllers, so return the object directly. + + // When the index is out of range, we want to return the "out of range" + // value, whatever that might be. Rather than make assumptions + // (e.g. guessing `null` or `undefined`) we defer this to `arrangedContent`. + return object; + }, + + arrangedContentDidChange: function() { + this._super(); + this._resetSubControllers(); + }, + + arrayContentDidChange: function(idx, removedCnt, addedCnt) { + var subControllers = this._subControllers; + + if (subControllers.length) { + var subControllersToRemove = subControllers.slice(idx, idx + removedCnt); + + forEach(subControllersToRemove, function(subController) { + if (subController) { + subController.destroy(); + } + }); + + replace(subControllers, idx, removedCnt, new Array(addedCnt)); + } + + // The shadow array of subcontrollers must be updated before we trigger + // observers, otherwise observers will get the wrong subcontainer when + // calling `objectAt` + this._super(idx, removedCnt, addedCnt); + }, + + init: function() { + this._super(); + this._subControllers = []; + }, + + model: computed(function () { + return Ember.A(); + }), + + /** + * Flag to mark as being "virtual". Used to keep this instance + * from participating in the parentController hierarchy. + * + * @private + * @property _isVirtual + * @type Boolean + */ + _isVirtual: false, + + controllerAt: function(idx, object, controllerClass) { + var container = get(this, 'container'); + var subControllers = this._subControllers; + var fullName, subController, subControllerFactory, parentController, options; + + if (subControllers.length > idx) { + subController = subControllers[idx]; + + if (subController) { + return subController; + } + } + + if (this._isVirtual) { + parentController = get(this, 'parentController'); + } else { + parentController = this; + } + + + fullName = 'controller:' + controllerClass; + + if (!container.has(fullName)) { + throw new EmberError('Could not resolve itemController: "' + controllerClass + '"'); + } + + subController = container.lookupFactory(fullName).create({ + target: parentController, + parentController: parentController, + model: object + }); + + + subControllers[idx] = subController; + + return subController; + }, + + _subControllers: null, + + _resetSubControllers: function() { + var controller; + var subControllers = this._subControllers; + + if (subControllers.length) { + for (var i = 0, length = subControllers.length; length > i; i++) { + controller = subControllers[i]; + + if (controller) { + controller.destroy(); + } + } + + subControllers.length = 0; + } + }, + + willDestroy: function() { + this._resetSubControllers(); + this._super(); + } + }); + }); +define("ember-runtime/controllers/controller", + ["ember-runtime/system/object","ember-runtime/mixins/controller","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + var Mixin = __dependency2__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + /** + @class Controller + @namespace Ember + @extends Ember.Object + @uses Ember.ControllerMixin + */ + __exports__["default"] = EmberObject.extend(Mixin); + }); +define("ember-runtime/controllers/object_controller", + ["ember-runtime/mixins/controller","ember-runtime/system/object_proxy","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var ControllerMixin = __dependency1__["default"]; + var ObjectProxy = __dependency2__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + /** + `Ember.ObjectController` is part of Ember's Controller layer. It is intended + to wrap a single object, proxying unhandled attempts to `get` and `set` to the underlying + model object, and to forward unhandled action attempts to its `target`. + + `Ember.ObjectController` derives this functionality from its superclass + `Ember.ObjectProxy` and the `Ember.ControllerMixin` mixin. + + @class ObjectController + @namespace Ember + @extends Ember.ObjectProxy + @uses Ember.ControllerMixin + **/ + __exports__["default"] = ObjectProxy.extend(ControllerMixin); + }); +define("ember-runtime/copy", + ["ember-metal/enumerable_utils","ember-metal/utils","ember-runtime/system/object","ember-runtime/mixins/copyable","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var indexOf = __dependency1__.indexOf; + var typeOf = __dependency2__.typeOf; + var EmberObject = __dependency3__["default"]; + var Copyable = __dependency4__["default"]; + + function _copy(obj, deep, seen, copies) { + var ret, loc, key; + + // primitive data types are immutable, just return them. + if (typeof obj !== 'object' || obj === null) { + return obj; + } + + // avoid cyclical loops + if (deep && (loc = indexOf(seen, obj)) >= 0) { + return copies[loc]; + } + + Ember.assert('Cannot clone an Ember.Object that does not implement Ember.Copyable', + !(obj instanceof EmberObject) || (Copyable && Copyable.detect(obj))); + + // IMPORTANT: this specific test will detect a native array only. Any other + // object will need to implement Copyable. + if (typeOf(obj) === 'array') { + ret = obj.slice(); + + if (deep) { + loc = ret.length; + + while (--loc >= 0) { + ret[loc] = _copy(ret[loc], deep, seen, copies); + } + } + } else if (Copyable && Copyable.detect(obj)) { + ret = obj.copy(deep, seen, copies); + } else if (obj instanceof Date) { + ret = new Date(obj.getTime()); + } else { + ret = {}; + + for (key in obj) { + // support Null prototype + if (!Object.prototype.hasOwnProperty.call(obj, key)) { + continue; + } + + // Prevents browsers that don't respect non-enumerability from + // copying internal Ember properties + if (key.substring(0, 2) === '__') { + continue; + } + + ret[key] = deep ? _copy(obj[key], deep, seen, copies) : obj[key]; + } + } + + if (deep) { + seen.push(obj); + copies.push(ret); + } + + return ret; + } + + /** + Creates a clone of the passed object. This function can take just about + any type of object and create a clone of it, including primitive values + (which are not actually cloned because they are immutable). + + If the passed object implements the `clone()` method, then this function + will simply call that method and return the result. + + @method copy + @for Ember + @param {Object} obj The object to clone + @param {Boolean} deep If true, a deep copy of the object is made + @return {Object} The cloned object + */ + __exports__["default"] = function copy(obj, deep) { + // fast paths + if ('object' !== typeof obj || obj === null) { + return obj; // can't copy primitives + } + + if (Copyable && Copyable.detect(obj)) { + return obj.copy(deep); + } + + return _copy(obj, deep, deep ? [] : null, deep ? [] : null); + } + }); +define("ember-runtime/core", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + /** + Compares two objects, returning true if they are logically equal. This is + a deeper comparison than a simple triple equal. For sets it will compare the + internal objects. For any other object that implements `isEqual()` it will + respect that method. + + ```javascript + Ember.isEqual('hello', 'hello'); // true + Ember.isEqual(1, 2); // false + Ember.isEqual([4, 2], [4, 2]); // false + ``` + + @method isEqual + @for Ember + @param {Object} a first object to compare + @param {Object} b second object to compare + @return {Boolean} + */ + var isEqual = function isEqual(a, b) { + if (a && typeof a.isEqual === 'function') { + return a.isEqual(b); + } + + if (a instanceof Date && b instanceof Date) { + return a.getTime() === b.getTime(); + } + + return a === b; + }; + __exports__.isEqual = isEqual; + }); +define("ember-runtime/ext/function", + ["ember-metal/core","ember-metal/expand_properties","ember-metal/computed","ember-metal/mixin"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.EXTEND_PROTOTYPES, Ember.assert + var expandProperties = __dependency2__["default"]; + var computed = __dependency3__.computed; + var observer = __dependency4__.observer; + + var a_slice = Array.prototype.slice; + var FunctionPrototype = Function.prototype; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) { + + /** + The `property` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + `true`, which is the default. + + Computed properties allow you to treat a function like a property: + + ```javascript + MyApp.President = Ember.Object.extend({ + firstName: '', + lastName: '', + + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + }.property() // Call this flag to mark the function as a property + }); + + var president = MyApp.President.create({ + firstName: 'Barack', + lastName: 'Obama' + }); + + president.get('fullName'); // 'Barack Obama' + ``` + + Treating a function like a property is useful because they can work with + bindings, just like any other property. + + Many computed properties have dependencies on other properties. For + example, in the above example, the `fullName` property depends on + `firstName` and `lastName` to determine its value. You can tell Ember + about these dependencies like this: + + ```javascript + MyApp.President = Ember.Object.extend({ + firstName: '', + lastName: '', + + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + + // Tell Ember.js that this computed property depends on firstName + // and lastName + }.property('firstName', 'lastName') + }); + ``` + + Make sure you list these dependencies so Ember knows when to update + bindings that connect to a computed property. Changing a dependency + will not immediately trigger an update of the computed property, but + will instead clear the cache so that it is updated when the next `get` + is called on the property. + + See [Ember.ComputedProperty](/api/classes/Ember.ComputedProperty.html), [Ember.computed](/api/#method_computed). + + @method property + @for Function + */ + FunctionPrototype.property = function () { + var ret = computed(this); + // ComputedProperty.prototype.property expands properties; no need for us to + // do so here. + return ret.property.apply(ret, arguments); + }; + + /** + The `observes` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + true, which is the default. + + You can observe property changes simply by adding the `observes` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property changes + }.observes('value') + }); + ``` + + In the future this method may become asynchronous. If you want to ensure + synchronous behavior, use `observesImmediately`. + + See `Ember.observer`. + + @method observes + @for Function + */ + FunctionPrototype.observes = function() { + var length = arguments.length; + var args = new Array(length); + for (var x = 0; x < length; x++) { + args[x] = arguments[x]; + } + return observer.apply(this, args.concat(this)); + }; + + /** + The `observesImmediately` extension of Javascript's Function prototype is + available when `Ember.EXTEND_PROTOTYPES` or + `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. + + You can observe property changes simply by adding the `observesImmediately` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes immediately after the "value" property changes + }.observesImmediately('value') + }); + ``` + + In the future, `observes` may become asynchronous. In this event, + `observesImmediately` will maintain the synchronous behavior. + + See `Ember.immediateObserver`. + + @method observesImmediately + @for Function + */ + FunctionPrototype.observesImmediately = function () { + for (var i = 0, l = arguments.length; i < l; i++) { + var arg = arguments[i]; + Ember.assert('Immediate observers must observe internal properties only, ' + + 'not properties on other objects.', arg.indexOf('.') === -1); + } + + // observes handles property expansion + return this.observes.apply(this, arguments); + }; + + /** + The `observesBefore` extension of Javascript's Function prototype is + available when `Ember.EXTEND_PROTOTYPES` or + `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. + + You can get notified when a property change is about to happen by + by adding the `observesBefore` call to the end of your method + declarations in classes that you write. For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property is about to change + }.observesBefore('value') + }); + ``` + + See `Ember.beforeObserver`. + + @method observesBefore + @for Function + */ + FunctionPrototype.observesBefore = function () { + var watched = []; + var addWatchedProperty = function (obs) { + watched.push(obs); + }; + + for (var i = 0, l = arguments.length; i < l; ++i) { + expandProperties(arguments[i], addWatchedProperty); + } + + this.__ember_observesBefore__ = watched; + + return this; + }; + + /** + The `on` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + true, which is the default. + + You can listen for events simply by adding the `on` call to the end of + your method declarations in classes or mixins that you write. For example: + + ```javascript + Ember.Mixin.create({ + doSomethingWithElement: function() { + // Executes whenever the "didInsertElement" event fires + }.on('didInsertElement') + }); + ``` + + See `Ember.on`. + + @method on + @for Function + */ + FunctionPrototype.on = function () { + var events = a_slice.call(arguments); + this.__ember_listens__ = events; + + return this; + }; + } + }); +define("ember-runtime/ext/rsvp", + ["ember-metal/core","ember-metal/logger","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /* globals RSVP:true */ + + var Ember = __dependency1__["default"]; + var Logger = __dependency2__["default"]; + var run = __dependency3__["default"]; + + var RSVP = requireModule('rsvp'); + var testModuleName = 'ember-testing/test'; + var Test; + + var asyncStart = function() { + if (Ember.Test && Ember.Test.adapter) { + Ember.Test.adapter.asyncStart(); + } + }; + + var asyncEnd = function() { + if (Ember.Test && Ember.Test.adapter) { + Ember.Test.adapter.asyncEnd(); + } + }; + + RSVP.configure('async', function(callback, promise) { + var async = !run.currentRunLoop; + + if (Ember.testing && async) { asyncStart(); } + + run.backburner.schedule('actions', function(){ + if (Ember.testing && async) { asyncEnd(); } + callback(promise); + }); + }); + + RSVP.Promise.prototype.fail = function(callback, label){ + Ember.deprecate('RSVP.Promise.fail has been renamed as RSVP.Promise.catch'); + return this['catch'](callback, label); + }; + + RSVP.onerrorDefault = function (error) { + if (error instanceof Error) { + if (Ember.testing) { + // ES6TODO: remove when possible + if (!Test && Ember.__loader.registry[testModuleName]) { + Test = requireModule(testModuleName)['default']; + } + + if (Test && Test.adapter) { + Test.adapter.exception(error); + } else { + throw error; + } + } else if (Ember.onerror) { + Ember.onerror(error); + } else { + Logger.error(error.stack); + Ember.assert(error, false); + } + } + }; + + RSVP.on('error', RSVP.onerrorDefault); + + __exports__["default"] = RSVP; + }); +define("ember-runtime/ext/string", + ["ember-metal/core","ember-runtime/system/string"], + function(__dependency1__, __dependency2__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.EXTEND_PROTOTYPES, Ember.assert, Ember.FEATURES + var fmt = __dependency2__.fmt; + var w = __dependency2__.w; + var loc = __dependency2__.loc; + var camelize = __dependency2__.camelize; + var decamelize = __dependency2__.decamelize; + var dasherize = __dependency2__.dasherize; + var underscore = __dependency2__.underscore; + var capitalize = __dependency2__.capitalize; + var classify = __dependency2__.classify; + + var StringPrototype = String.prototype; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { + + /** + See [Ember.String.fmt](/api/classes/Ember.String.html#method_fmt). + + @method fmt + @for String + */ + StringPrototype.fmt = function () { + return fmt(this, arguments); + }; + + /** + See [Ember.String.w](/api/classes/Ember.String.html#method_w). + + @method w + @for String + */ + StringPrototype.w = function () { + return w(this); + }; + + /** + See [Ember.String.loc](/api/classes/Ember.String.html#method_loc). + + @method loc + @for String + */ + StringPrototype.loc = function () { + return loc(this, arguments); + }; + + /** + See [Ember.String.camelize](/api/classes/Ember.String.html#method_camelize). + + @method camelize + @for String + */ + StringPrototype.camelize = function () { + return camelize(this); + }; + + /** + See [Ember.String.decamelize](/api/classes/Ember.String.html#method_decamelize). + + @method decamelize + @for String + */ + StringPrototype.decamelize = function () { + return decamelize(this); + }; + + /** + See [Ember.String.dasherize](/api/classes/Ember.String.html#method_dasherize). + + @method dasherize + @for String + */ + StringPrototype.dasherize = function () { + return dasherize(this); + }; + + /** + See [Ember.String.underscore](/api/classes/Ember.String.html#method_underscore). + + @method underscore + @for String + */ + StringPrototype.underscore = function () { + return underscore(this); + }; + + /** + See [Ember.String.classify](/api/classes/Ember.String.html#method_classify). + + @method classify + @for String + */ + StringPrototype.classify = function () { + return classify(this); + }; + + /** + See [Ember.String.capitalize](/api/classes/Ember.String.html#method_capitalize). + + @method capitalize + @for String + */ + StringPrototype.capitalize = function () { + return capitalize(this); + }; + } + }); +define("ember-runtime/mixins/-proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/property_events","ember-metal/computed","ember-metal/properties","ember-metal/mixin","ember-runtime/system/string","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var meta = __dependency4__.meta; + var addObserver = __dependency5__.addObserver; + var removeObserver = __dependency5__.removeObserver; + var addBeforeObserver = __dependency5__.addBeforeObserver; + var removeBeforeObserver = __dependency5__.removeBeforeObserver; + var propertyWillChange = __dependency6__.propertyWillChange; + var propertyDidChange = __dependency6__.propertyDidChange; + var computed = __dependency7__.computed; + var defineProperty = __dependency8__.defineProperty; + var Mixin = __dependency9__.Mixin; + var observer = __dependency9__.observer; + var fmt = __dependency10__.fmt; + var EmberObject = __dependency11__["default"]; + + function contentPropertyWillChange(content, contentKey) { + var key = contentKey.slice(8); // remove "content." + if (key in this) { return; } // if shadowed in proxy + propertyWillChange(this, key); + } + + function contentPropertyDidChange(content, contentKey) { + var key = contentKey.slice(8); // remove "content." + if (key in this) { return; } // if shadowed in proxy + propertyDidChange(this, key); + } + + /** + `Ember.ProxyMixin` forwards all properties not defined by the proxy itself + to a proxied `content` object. See Ember.ObjectProxy for more details. + + @class ProxyMixin + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + The object whose properties will be forwarded. + + @property content + @type Ember.Object + @default null + */ + content: null, + _contentDidChange: observer('content', function() { + Ember.assert("Can't set Proxy's content to itself", get(this, 'content') !== this); + }), + + isTruthy: computed.bool('content'), + + _debugContainerKey: null, + + willWatchProperty: function (key) { + var contentKey = 'content.' + key; + addBeforeObserver(this, contentKey, null, contentPropertyWillChange); + addObserver(this, contentKey, null, contentPropertyDidChange); + }, + + didUnwatchProperty: function (key) { + var contentKey = 'content.' + key; + removeBeforeObserver(this, contentKey, null, contentPropertyWillChange); + removeObserver(this, contentKey, null, contentPropertyDidChange); + }, + + unknownProperty: function (key) { + var content = get(this, 'content'); + if (content) { + return get(content, key); + } + }, + + setUnknownProperty: function (key, value) { + var m = meta(this); + if (m.proto === this) { + // if marked as prototype then just defineProperty + // rather than delegate + defineProperty(this, key, null, value); + return value; + } + + var content = get(this, 'content'); + Ember.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of object proxy %@: its 'content' is undefined.", [key, value, this]), content); + return set(content, key, value); + } + + }); + }); +define("ember-runtime/mixins/action_handler", + ["ember-metal/merge","ember-metal/mixin","ember-metal/property_get","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var merge = __dependency1__["default"]; + var Mixin = __dependency2__.Mixin; + var get = __dependency3__.get; + var typeOf = __dependency4__.typeOf; + + /** + The `Ember.ActionHandler` mixin implements support for moving an `actions` + property to an `_actions` property at extend time, and adding `_actions` + to the object's mergedProperties list. + + `Ember.ActionHandler` is available on some familiar classes including + `Ember.Route`, `Ember.View`, `Ember.Component`, and controllers such as + `Ember.Controller` and `Ember.ObjectController`. + (Internally the mixin is used by `Ember.CoreView`, `Ember.ControllerMixin`, + and `Ember.Route` and available to the above classes through + inheritance.) + + @class ActionHandler + @namespace Ember + */ + var ActionHandler = Mixin.create({ + mergedProperties: ['_actions'], + + /** + The collection of functions, keyed by name, available on this + `ActionHandler` as action targets. + + These functions will be invoked when a matching `{{action}}` is triggered + from within a template and the application's current route is this route. + + Actions can also be invoked from other parts of your application + via `ActionHandler#send`. + + The `actions` hash will inherit action handlers from + the `actions` hash defined on extended parent classes + or mixins rather than just replace the entire hash, e.g.: + + ```js + App.CanDisplayBanner = Ember.Mixin.create({ + actions: { + displayBanner: function(msg) { + // ... + } + } + }); + + App.WelcomeRoute = Ember.Route.extend(App.CanDisplayBanner, { + actions: { + playMusic: function() { + // ... + } + } + }); + + // `WelcomeRoute`, when active, will be able to respond + // to both actions, since the actions hash is merged rather + // then replaced when extending mixins / parent classes. + this.send('displayBanner'); + this.send('playMusic'); + ``` + + Within a Controller, Route, View or Component's action handler, + the value of the `this` context is the Controller, Route, View or + Component object: + + ```js + App.SongRoute = Ember.Route.extend({ + actions: { + myAction: function() { + this.controllerFor("song"); + this.transitionTo("other.route"); + ... + } + } + }); + ``` + + It is also possible to call `this._super()` from within an + action handler if it overrides a handler defined on a parent + class or mixin: + + Take for example the following routes: + + ```js + App.DebugRoute = Ember.Mixin.create({ + actions: { + debugRouteInformation: function() { + console.debug("trololo"); + } + } + }); + + App.AnnoyingDebugRoute = Ember.Route.extend(App.DebugRoute, { + actions: { + debugRouteInformation: function() { + // also call the debugRouteInformation of mixed in App.DebugRoute + this._super(); + + // show additional annoyance + window.alert(...); + } + } + }); + ``` + + ## Bubbling + + By default, an action will stop bubbling once a handler defined + on the `actions` hash handles it. To continue bubbling the action, + you must return `true` from the handler: + + ```js + App.Router.map(function() { + this.resource("album", function() { + this.route("song"); + }); + }); + + App.AlbumRoute = Ember.Route.extend({ + actions: { + startPlaying: function() { + } + } + }); + + App.AlbumSongRoute = Ember.Route.extend({ + actions: { + startPlaying: function() { + // ... + + if (actionShouldAlsoBeTriggeredOnParentRoute) { + return true; + } + } + } + }); + ``` + + @property actions + @type Hash + @default null + */ + + /** + Moves `actions` to `_actions` at extend time. Note that this currently + modifies the mixin themselves, which is technically dubious but + is practically of little consequence. This may change in the future. + + @private + @method willMergeMixin + */ + willMergeMixin: function(props) { + var hashName; + + if (!props._actions) { + Ember.assert("'actions' should not be a function", typeof(props.actions) !== 'function'); + + if (typeOf(props.actions) === 'object') { + hashName = 'actions'; + } else if (typeOf(props.events) === 'object') { + Ember.deprecate('Action handlers contained in an `events` object are deprecated in favor of putting them in an `actions` object', false); + hashName = 'events'; + } + + if (hashName) { + props._actions = merge(props._actions || {}, props[hashName]); + } + + delete props[hashName]; + } + }, + + /** + Triggers a named action on the `ActionHandler`. Any parameters + supplied after the `actionName` string will be passed as arguments + to the action target function. + + If the `ActionHandler` has its `target` property set, actions may + bubble to the `target`. Bubbling happens when an `actionName` can + not be found in the `ActionHandler`'s `actions` hash or if the + action target function returns `true`. + + Example + + ```js + App.WelcomeRoute = Ember.Route.extend({ + actions: { + playTheme: function() { + this.send('playMusic', 'theme.mp3'); + }, + playMusic: function(track) { + // ... + } + } + }); + ``` + + @method send + @param {String} actionName The action to trigger + @param {*} context a context to send with the action + */ + send: function(actionName) { + var args = [].slice.call(arguments, 1); + var target; + + if (this._actions && this._actions[actionName]) { + if (this._actions[actionName].apply(this, args) === true) { + // handler returned true, so this action will bubble + } else { + return; + } + } + + if (target = get(this, 'target')) { + Ember.assert("The `target` for " + this + " (" + target + ") does not have a `send` method", typeof target.send === 'function'); + target.send.apply(target, arguments); + } + } + }); + + __exports__["default"] = ActionHandler; + }); +define("ember-runtime/mixins/array", + ["ember-metal/core","ember-metal/property_get","ember-metal/computed","ember-metal/is_none","ember-runtime/mixins/enumerable","ember-metal/enumerable_utils","ember-metal/mixin","ember-metal/property_events","ember-metal/events","ember-metal/watching","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // .......................................................... + // HELPERS + // + var Ember = __dependency1__["default"]; + // ES6TODO: Ember.A + var get = __dependency2__.get; + var computed = __dependency3__.computed; + var cacheFor = __dependency3__.cacheFor; + var isNone = __dependency4__.isNone; + var none = __dependency4__.none; + var Enumerable = __dependency5__["default"]; + var map = __dependency6__.map; + var Mixin = __dependency7__.Mixin; + var required = __dependency7__.required; + var propertyWillChange = __dependency8__.propertyWillChange; + var propertyDidChange = __dependency8__.propertyDidChange; + var addListener = __dependency9__.addListener; + var removeListener = __dependency9__.removeListener; + var sendEvent = __dependency9__.sendEvent; + var hasListeners = __dependency9__.hasListeners; + var isWatching = __dependency10__.isWatching; + + function arrayObserversHelper(obj, target, opts, operation, notify) { + var willChange = (opts && opts.willChange) || 'arrayWillChange'; + var didChange = (opts && opts.didChange) || 'arrayDidChange'; + var hasObservers = get(obj, 'hasArrayObservers'); + + if (hasObservers === notify) { + propertyWillChange(obj, 'hasArrayObservers'); + } + + operation(obj, '@array:before', target, willChange); + operation(obj, '@array:change', target, didChange); + + if (hasObservers === notify) { + propertyDidChange(obj, 'hasArrayObservers'); + } + + return obj; + } + + // .......................................................... + // ARRAY + // + /** + This mixin implements Observer-friendly Array-like behavior. It is not a + concrete implementation, but it can be used up by other classes that want + to appear like arrays. + + For example, ArrayProxy and ArrayController are both concrete classes that can + be instantiated to implement array-like behavior. Both of these classes use + the Array Mixin by way of the MutableArray mixin, which allows observable + changes to be made to the underlying array. + + Unlike `Ember.Enumerable,` this mixin defines methods specifically for + collections that provide index-ordered access to their contents. When you + are designing code that needs to accept any kind of Array-like object, you + should use these methods instead of Array primitives because these will + properly notify observers of changes to the array. + + Although these methods are efficient, they do add a layer of indirection to + your application so it is a good idea to use them only when you need the + flexibility of using both true JavaScript arrays and "virtual" arrays such + as controllers and collections. + + You can use the methods defined in this module to access and modify array + contents in a KVO-friendly way. You can also be notified whenever the + membership of an array changes by using `.observes('myArray.[]')`. + + To support `Ember.Array` in your own class, you must override two + primitives to use it: `replace()` and `objectAt()`. + + Note that the Ember.Array mixin also incorporates the `Ember.Enumerable` + mixin. All `Ember.Array`-like objects are also enumerable. + + @class Array + @namespace Ember + @uses Ember.Enumerable + @since Ember 0.9.0 + */ + __exports__["default"] = Mixin.create(Enumerable, { + + /** + Your array must support the `length` property. Your replace methods should + set this property whenever it changes. + + @property {Number} length + */ + length: required(), + + /** + Returns the object at the given `index`. If the given `index` is negative + or is greater or equal than the array length, returns `undefined`. + + This is one of the primitives you must implement to support `Ember.Array`. + If your object supports retrieving the value of an array item using `get()` + (i.e. `myArray.get(0)`), then you do not need to implement this method + yourself. + + ```javascript + var arr = ['a', 'b', 'c', 'd']; + + arr.objectAt(0); // 'a' + arr.objectAt(3); // 'd' + arr.objectAt(-1); // undefined + arr.objectAt(4); // undefined + arr.objectAt(5); // undefined + ``` + + @method objectAt + @param {Number} idx The index of the item to return. + @return {*} item at index or undefined + */ + objectAt: function(idx) { + if (idx < 0 || idx >= get(this, 'length')) { + return undefined; + } + + return get(this, idx); + }, + + /** + This returns the objects at the specified indexes, using `objectAt`. + + ```javascript + var arr = ['a', 'b', 'c', 'd']; + + arr.objectsAt([0, 1, 2]); // ['a', 'b', 'c'] + arr.objectsAt([2, 3, 4]); // ['c', 'd', undefined] + ``` + + @method objectsAt + @param {Array} indexes An array of indexes of items to return. + @return {Array} + */ + objectsAt: function(indexes) { + var self = this; + + return map(indexes, function(idx) { + return self.objectAt(idx); + }); + }, + + // overrides Ember.Enumerable version + nextObject: function(idx) { + return this.objectAt(idx); + }, + + /** + This is the handler for the special array content property. If you get + this property, it will return this. If you set this property to a new + array, it will replace the current content. + + This property overrides the default property defined in `Ember.Enumerable`. + + @property [] + @return this + */ + '[]': computed(function(key, value) { + if (value !== undefined) { + this.replace(0, get(this, 'length'), value); + } + + return this; + }), + + firstObject: computed(function() { + return this.objectAt(0); + }), + + lastObject: computed(function() { + return this.objectAt(get(this, 'length') - 1); + }), + + // optimized version from Enumerable + contains: function(obj) { + return this.indexOf(obj) >= 0; + }, + + // Add any extra methods to Ember.Array that are native to the built-in Array. + /** + Returns a new array that is a slice of the receiver. This implementation + uses the observable array methods to retrieve the objects for the new + slice. + + ```javascript + var arr = ['red', 'green', 'blue']; + + arr.slice(0); // ['red', 'green', 'blue'] + arr.slice(0, 2); // ['red', 'green'] + arr.slice(1, 100); // ['green', 'blue'] + ``` + + @method slice + @param {Integer} beginIndex (Optional) index to begin slicing from. + @param {Integer} endIndex (Optional) index to end the slice at (but not included). + @return {Array} New array with specified slice + */ + slice: function(beginIndex, endIndex) { + var ret = Ember.A(); + var length = get(this, 'length'); + + if (isNone(beginIndex)) { + beginIndex = 0; + } + + if (isNone(endIndex) || (endIndex > length)) { + endIndex = length; + } + + if (beginIndex < 0) { + beginIndex = length + beginIndex; + } + + if (endIndex < 0) { + endIndex = length + endIndex; + } + + while (beginIndex < endIndex) { + ret[ret.length] = this.objectAt(beginIndex++); + } + + return ret; + }, + + /** + Returns the index of the given object's first occurrence. + If no `startAt` argument is given, the starting location to + search is 0. If it's negative, will count backward from + the end of the array. Returns -1 if no match is found. + + ```javascript + var arr = ['a', 'b', 'c', 'd', 'a']; + + arr.indexOf('a'); // 0 + arr.indexOf('z'); // -1 + arr.indexOf('a', 2); // 4 + arr.indexOf('a', -1); // 4 + arr.indexOf('b', 3); // -1 + arr.indexOf('a', 100); // -1 + ``` + + @method indexOf + @param {Object} object the item to search for + @param {Number} startAt optional starting location to search, default 0 + @return {Number} index or -1 if not found + */ + indexOf: function(object, startAt) { + var len = get(this, 'length'); + var idx; + + if (startAt === undefined) { + startAt = 0; + } + + if (startAt < 0) { + startAt += len; + } + + for (idx = startAt; idx < len; idx++) { + if (this.objectAt(idx) === object) { + return idx; + } + } + + return -1; + }, + + /** + Returns the index of the given object's last occurrence. + If no `startAt` argument is given, the search starts from + the last position. If it's negative, will count backward + from the end of the array. Returns -1 if no match is found. + + ```javascript + var arr = ['a', 'b', 'c', 'd', 'a']; + + arr.lastIndexOf('a'); // 4 + arr.lastIndexOf('z'); // -1 + arr.lastIndexOf('a', 2); // 0 + arr.lastIndexOf('a', -1); // 4 + arr.lastIndexOf('b', 3); // 1 + arr.lastIndexOf('a', 100); // 4 + ``` + + @method lastIndexOf + @param {Object} object the item to search for + @param {Number} startAt optional starting location to search, default 0 + @return {Number} index or -1 if not found + */ + lastIndexOf: function(object, startAt) { + var len = get(this, 'length'); + var idx; + + if (startAt === undefined || startAt >= len) { + startAt = len-1; + } + + if (startAt < 0) { + startAt += len; + } + + for (idx = startAt; idx >= 0; idx--) { + if (this.objectAt(idx) === object) { + return idx; + } + } + + return -1; + }, + + // .......................................................... + // ARRAY OBSERVERS + // + + /** + Adds an array observer to the receiving array. The array observer object + normally must implement two methods: + + * `arrayWillChange(observedObj, start, removeCount, addCount)` - This method will be + called just before the array is modified. + * `arrayDidChange(observedObj, start, removeCount, addCount)` - This method will be + called just after the array is modified. + + Both callbacks will be passed the observed object, starting index of the + change as well a a count of the items to be removed and added. You can use + these callbacks to optionally inspect the array during the change, clear + caches, or do any other bookkeeping necessary. + + In addition to passing a target, you can also include an options hash + which you can use to override the method names that will be invoked on the + target. + + @method addArrayObserver + @param {Object} target The observer object. + @param {Hash} opts Optional hash of configuration options including + `willChange` and `didChange` option. + @return {Ember.Array} receiver + */ + + addArrayObserver: function(target, opts) { + return arrayObserversHelper(this, target, opts, addListener, false); + }, + + /** + Removes an array observer from the object if the observer is current + registered. Calling this method multiple times with the same object will + have no effect. + + @method removeArrayObserver + @param {Object} target The object observing the array. + @param {Hash} opts Optional hash of configuration options including + `willChange` and `didChange` option. + @return {Ember.Array} receiver + */ + removeArrayObserver: function(target, opts) { + return arrayObserversHelper(this, target, opts, removeListener, true); + }, + + /** + Becomes true whenever the array currently has observers watching changes + on the array. + + @property {Boolean} hasArrayObservers + */ + hasArrayObservers: computed(function() { + return hasListeners(this, '@array:change') || hasListeners(this, '@array:before'); + }), + + /** + If you are implementing an object that supports `Ember.Array`, call this + method just before the array content changes to notify any observers and + invalidate any related properties. Pass the starting index of the change + as well as a delta of the amounts to change. + + @method arrayContentWillChange + @param {Number} startIdx The starting index in the array that will change. + @param {Number} removeAmt The number of items that will be removed. If you + pass `null` assumes 0 + @param {Number} addAmt The number of items that will be added. If you + pass `null` assumes 0. + @return {Ember.Array} receiver + */ + arrayContentWillChange: function(startIdx, removeAmt, addAmt) { + var removing, lim; + + // if no args are passed assume everything changes + if (startIdx === undefined) { + startIdx = 0; + removeAmt = addAmt = -1; + } else { + if (removeAmt === undefined) { + removeAmt = -1; + } + + if (addAmt === undefined) { + addAmt = -1; + } + } + + // Make sure the @each proxy is set up if anyone is observing @each + if (isWatching(this, '@each')) { + get(this, '@each'); + } + + sendEvent(this, '@array:before', [this, startIdx, removeAmt, addAmt]); + + if (startIdx >= 0 && removeAmt >= 0 && get(this, 'hasEnumerableObservers')) { + removing = []; + lim = startIdx + removeAmt; + + for (var idx = startIdx; idx < lim; idx++) { + removing.push(this.objectAt(idx)); + } + } else { + removing = removeAmt; + } + + this.enumerableContentWillChange(removing, addAmt); + + return this; + }, + + /** + If you are implementing an object that supports `Ember.Array`, call this + method just after the array content changes to notify any observers and + invalidate any related properties. Pass the starting index of the change + as well as a delta of the amounts to change. + + @method arrayContentDidChange + @param {Number} startIdx The starting index in the array that did change. + @param {Number} removeAmt The number of items that were removed. If you + pass `null` assumes 0 + @param {Number} addAmt The number of items that were added. If you + pass `null` assumes 0. + @return {Ember.Array} receiver + */ + arrayContentDidChange: function(startIdx, removeAmt, addAmt) { + var adding, lim; + + // if no args are passed assume everything changes + if (startIdx === undefined) { + startIdx = 0; + removeAmt = addAmt = -1; + } else { + if (removeAmt === undefined) { + removeAmt = -1; + } + + if (addAmt === undefined) { + addAmt = -1; + } + } + + if (startIdx >= 0 && addAmt >= 0 && get(this, 'hasEnumerableObservers')) { + adding = []; + lim = startIdx + addAmt; + + for (var idx = startIdx; idx < lim; idx++) { + adding.push(this.objectAt(idx)); + } + } else { + adding = addAmt; + } + + this.enumerableContentDidChange(removeAmt, adding); + sendEvent(this, '@array:change', [this, startIdx, removeAmt, addAmt]); + + var length = get(this, 'length'); + var cachedFirst = cacheFor(this, 'firstObject'); + var cachedLast = cacheFor(this, 'lastObject'); + + if (this.objectAt(0) !== cachedFirst) { + propertyWillChange(this, 'firstObject'); + propertyDidChange(this, 'firstObject'); + } + + if (this.objectAt(length-1) !== cachedLast) { + propertyWillChange(this, 'lastObject'); + propertyDidChange(this, 'lastObject'); + } + + return this; + }, + + // .......................................................... + // ENUMERATED PROPERTIES + // + + /** + Returns a special object that can be used to observe individual properties + on the array. Just get an equivalent property on this object and it will + return an enumerable that maps automatically to the named key on the + member objects. + + If you merely want to watch for any items being added or removed to the array, + use the `[]` property instead of `@each`. + + @property @each + */ + '@each': computed(function() { + if (!this.__each) { + // ES6TODO: GRRRRR + var EachProxy = requireModule('ember-runtime/system/each_proxy')['EachProxy']; + + this.__each = new EachProxy(this); + } + + return this.__each; + }) + }); + }); +define("ember-runtime/mixins/comparable", + ["ember-metal/mixin","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var required = __dependency1__.required; + + /** + @module ember + @submodule ember-runtime + */ + + /** + Implements some standard methods for comparing objects. Add this mixin to + any class you create that can compare its instances. + + You should implement the `compare()` method. + + @class Comparable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + + /** + Override to return the result of the comparison of the two parameters. The + compare method should return: + + - `-1` if `a < b` + - `0` if `a == b` + - `1` if `a > b` + + Default implementation raises an exception. + + @method compare + @param a {Object} the first object to compare + @param b {Object} the second object to compare + @return {Integer} the result of the comparison + */ + compare: required(Function) + }); + }); +define("ember-runtime/mixins/controller", + ["ember-metal/core","ember-metal/property_get","ember-runtime/system/object","ember-metal/mixin","ember-metal/computed","ember-runtime/mixins/action_handler","ember-runtime/mixins/controller_content_model_alias_deprecation","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.deprecate + var get = __dependency2__.get; + var EmberObject = __dependency3__["default"]; + var Mixin = __dependency4__.Mixin; + var computed = __dependency5__.computed; + var ActionHandler = __dependency6__["default"]; + var ControllerContentModelAliasDeprecation = __dependency7__["default"]; + + /** + `Ember.ControllerMixin` provides a standard interface for all classes that + compose Ember's controller layer: `Ember.Controller`, + `Ember.ArrayController`, and `Ember.ObjectController`. + + @class ControllerMixin + @namespace Ember + @uses Ember.ActionHandler + */ + __exports__["default"] = Mixin.create(ActionHandler, ControllerContentModelAliasDeprecation, { + /* ducktype as a controller */ + isController: true, + + /** + The object to which actions from the view should be sent. + + For example, when a Handlebars template uses the `{{action}}` helper, + it will attempt to send the action to the view's controller's `target`. + + By default, the value of the target property is set to the router, and + is injected when a controller is instantiated. This injection is defined + in Ember.Application#buildContainer, and is applied as part of the + applications initialization process. It can also be set after a controller + has been instantiated, for instance when using the render helper in a + template, or when a controller is used as an `itemController`. In most + cases the `target` property will automatically be set to the logical + consumer of actions for the controller. + + @property target + @default null + */ + target: null, + + container: null, + + parentController: null, + + store: null, + + /** + The controller's current model. When retrieving or modifying a controller's + model, this property should be used instead of the `content` property. + + @property model + @public + */ + model: null, + + /** + @private + */ + content: computed.alias('model') + + }); + }); +define("ember-runtime/mixins/controller_content_model_alias_deprecation", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.deprecate + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + + /** + The ControllerContentModelAliasDeprecation mixin is used to provide a useful + deprecation warning when specifying `content` directly on a `Ember.Controller` + (without also specifying `model`). + + Ember versions prior to 1.7 used `model` as an alias of `content`, but due to + much confusion this alias was reversed (so `content` is now an alias of `model). + + This change reduces many caveats with model/content, and also sets a + simple ground rule: Never set a controllers content, rather always set + it's model and ember will do the right thing. + + + `Ember.ControllerContentModelAliasDeprecation` is used internally by Ember in + `Ember.Controller`. + + @class ControllerContentModelAliasDeprecation + @namespace Ember + @private + @since 1.7.0 + */ + __exports__["default"] = Mixin.create({ + /** + @private + + Moves `content` to `model` at extend time if a `model` is not also specified. + + Note that this currently modifies the mixin themselves, which is technically + dubious but is practically of little consequence. This may change in the + future. + + @method willMergeMixin + @since 1.4.0 + */ + willMergeMixin: function(props) { + // Calling super is only OK here since we KNOW that + // there is another Mixin loaded first. + this._super.apply(this, arguments); + + var modelSpecified = !!props.model; + + if (props.content && !modelSpecified) { + props.model = props.content; + delete props['content']; + + Ember.deprecate('Do not specify `content` on a Controller, use `model` instead.', false); + } + } + }); + }); +define("ember-runtime/mixins/copyable", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/freezable","ember-runtime/system/string","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + + var get = __dependency1__.get; + var set = __dependency2__.set; + var required = __dependency3__.required; + var Freezable = __dependency4__.Freezable; + var Mixin = __dependency3__.Mixin; + var fmt = __dependency5__.fmt; + var EmberError = __dependency6__["default"]; + + + /** + Implements some standard methods for copying an object. Add this mixin to + any object you create that can create a copy of itself. This mixin is + added automatically to the built-in array. + + You should generally implement the `copy()` method to return a copy of the + receiver. + + Note that `frozenCopy()` will only work if you also implement + `Ember.Freezable`. + + @class Copyable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + /** + Override to return a copy of the receiver. Default implementation raises + an exception. + + @method copy + @param {Boolean} deep if `true`, a deep copy of the object should be made + @return {Object} copy of receiver + */ + copy: required(Function), + + /** + If the object implements `Ember.Freezable`, then this will return a new + copy if the object is not frozen and the receiver if the object is frozen. + + Raises an exception if you try to call this method on a object that does + not support freezing. + + You should use this method whenever you want a copy of a freezable object + since a freezable object can simply return itself without actually + consuming more memory. + + @method frozenCopy + @return {Object} copy of receiver or receiver + */ + frozenCopy: function() { + if (Freezable && Freezable.detect(this)) { + return get(this, 'isFrozen') ? this : this.copy().freeze(); + } else { + throw new EmberError(fmt("%@ does not support freezing", [this])); + } + } + }); + }); +define("ember-runtime/mixins/deferred", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","ember-metal/computed","ember-runtime/ext/rsvp","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.Test + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + var computed = __dependency4__.computed; + var RSVP = __dependency5__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + + /** + @class Deferred + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + Add handlers to be called when the Deferred object is resolved or rejected. + + @method then + @param {Function} resolve a callback function to be called when done + @param {Function} reject a callback function to be called when failed + */ + then: function(resolve, reject, label) { + var deferred, promise, entity; + + entity = this; + deferred = get(this, '_deferred'); + promise = deferred.promise; + + function fulfillmentHandler(fulfillment) { + if (fulfillment === promise) { + return resolve(entity); + } else { + return resolve(fulfillment); + } + } + + return promise.then(resolve && fulfillmentHandler, reject, label); + }, + + /** + Resolve a Deferred object and call any `doneCallbacks` with the given args. + + @method resolve + */ + resolve: function(value) { + var deferred, promise; + + deferred = get(this, '_deferred'); + promise = deferred.promise; + + if (value === this) { + deferred.resolve(promise); + } else { + deferred.resolve(value); + } + }, + + /** + Reject a Deferred object and call any `failCallbacks` with the given args. + + @method reject + */ + reject: function(value) { + get(this, '_deferred').reject(value); + }, + + _deferred: computed(function() { + Ember.deprecate('Usage of Ember.DeferredMixin or Ember.Deferred is deprecated.', this._suppressDeferredDeprecation); + + return RSVP.defer('Ember: DeferredMixin - ' + this); + }) + }); + }); +define("ember-runtime/mixins/enumerable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/property_events","ember-metal/events","ember-runtime/compare","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // .......................................................... + // HELPERS + // + + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var apply = __dependency4__.apply; + var Mixin = __dependency5__.Mixin; + var required = __dependency5__.required; + var aliasMethod = __dependency5__.aliasMethod; + var indexOf = __dependency6__.indexOf; + var computed = __dependency7__.computed; + var propertyWillChange = __dependency8__.propertyWillChange; + var propertyDidChange = __dependency8__.propertyDidChange; + var addListener = __dependency9__.addListener; + var removeListener = __dependency9__.removeListener; + var sendEvent = __dependency9__.sendEvent; + var hasListeners = __dependency9__.hasListeners; + var compare = __dependency10__["default"]; + + var a_slice = Array.prototype.slice; + + var contexts = []; + + function popCtx() { + return contexts.length===0 ? {} : contexts.pop(); + } + + function pushCtx(ctx) { + contexts.push(ctx); + return null; + } + + function iter(key, value) { + var valueProvided = arguments.length === 2; + + function i(item) { + var cur = get(item, key); + return valueProvided ? value===cur : !!cur; + } + + return i; + } + + /** + This mixin defines the common interface implemented by enumerable objects + in Ember. Most of these methods follow the standard Array iteration + API defined up to JavaScript 1.8 (excluding language-specific features that + cannot be emulated in older versions of JavaScript). + + This mixin is applied automatically to the Array class on page load, so you + can use any of these methods on simple arrays. If Array already implements + one of these methods, the mixin will not override them. + + ## Writing Your Own Enumerable + + To make your own custom class enumerable, you need two items: + + 1. You must have a length property. This property should change whenever + the number of items in your enumerable object changes. If you use this + with an `Ember.Object` subclass, you should be sure to change the length + property using `set().` + + 2. You must implement `nextObject().` See documentation. + + Once you have these two methods implemented, apply the `Ember.Enumerable` mixin + to your class and you will be able to enumerate the contents of your object + like any other collection. + + ## Using Ember Enumeration with Other Libraries + + Many other libraries provide some kind of iterator or enumeration like + facility. This is often where the most common API conflicts occur. + Ember's API is designed to be as friendly as possible with other + libraries by implementing only methods that mostly correspond to the + JavaScript 1.8 API. + + @class Enumerable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + + /** + Implement this method to make your class enumerable. + + This method will be call repeatedly during enumeration. The index value + will always begin with 0 and increment monotonically. You don't have to + rely on the index value to determine what object to return, but you should + always check the value and start from the beginning when you see the + requested index is 0. + + The `previousObject` is the object that was returned from the last call + to `nextObject` for the current iteration. This is a useful way to + manage iteration if you are tracing a linked list, for example. + + Finally the context parameter will always contain a hash you can use as + a "scratchpad" to maintain any other state you need in order to iterate + properly. The context object is reused and is not reset between + iterations so make sure you setup the context with a fresh state whenever + the index parameter is 0. + + Generally iterators will continue to call `nextObject` until the index + reaches the your current length-1. If you run out of data before this + time for some reason, you should simply return undefined. + + The default implementation of this method simply looks up the index. + This works great on any Array-like objects. + + @method nextObject + @param {Number} index the current index of the iteration + @param {Object} previousObject the value returned by the last call to + `nextObject`. + @param {Object} context a context object you can use to maintain state. + @return {Object} the next object in the iteration or undefined + */ + nextObject: required(Function), + + /** + Helper method returns the first object from a collection. This is usually + used by bindings and other parts of the framework to extract a single + object if the enumerable contains only one item. + + If you override this method, you should implement it so that it will + always return the same value each time it is called. If your enumerable + contains only one object, this method should always return that object. + If your enumerable is empty, this method should return `undefined`. + + ```javascript + var arr = ["a", "b", "c"]; + arr.get('firstObject'); // "a" + + var arr = []; + arr.get('firstObject'); // undefined + ``` + + @property firstObject + @return {Object} the object or undefined + */ + firstObject: computed('[]', function() { + if (get(this, 'length')===0) return undefined ; + + // handle generic enumerables + var context = popCtx(), ret; + ret = this.nextObject(0, null, context); + pushCtx(context); + return ret; + }), + + /** + Helper method returns the last object from a collection. If your enumerable + contains only one object, this method should always return that object. + If your enumerable is empty, this method should return `undefined`. + + ```javascript + var arr = ["a", "b", "c"]; + arr.get('lastObject'); // "c" + + var arr = []; + arr.get('lastObject'); // undefined + ``` + + @property lastObject + @return {Object} the last object or undefined + */ + lastObject: computed('[]', function() { + var len = get(this, 'length'); + if (len===0) return undefined ; + var context = popCtx(), idx=0, cur, last = null; + do { + last = cur; + cur = this.nextObject(idx++, last, context); + } while (cur !== undefined); + pushCtx(context); + return last; + }), + + /** + Returns `true` if the passed object can be found in the receiver. The + default version will iterate through the enumerable until the object + is found. You may want to override this with a more efficient version. + + ```javascript + var arr = ["a", "b", "c"]; + arr.contains("a"); // true + arr.contains("z"); // false + ``` + + @method contains + @param {Object} obj The object to search for. + @return {Boolean} `true` if object is found in enumerable. + */ + contains: function(obj) { + return this.find(function(item) { return item===obj; }) !== undefined; + }, + + /** + Iterates through the enumerable, calling the passed function on each + item. This method corresponds to the `forEach()` method defined in + JavaScript 1.6. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(item, index, enumerable); + ``` + + - `item` is the current item in the iteration. + - `index` is the current index in the iteration. + - `enumerable` is the enumerable object itself. + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. This is a good way + to give your iterator function access to the current object. + + @method forEach + @param {Function} callback The callback to execute + @param {Object} [target] The target object to use + @return {Object} receiver + */ + forEach: function(callback, target) { + if (typeof callback !== 'function') throw new TypeError() ; + var len = get(this, 'length'), last = null, context = popCtx(); + + if (target === undefined) target = null; + + for(var idx=0;idx1) args = a_slice.call(arguments, 1); + + this.forEach(function(x, idx) { + var method = x && x[methodName]; + if ('function' === typeof method) { + ret[idx] = args ? apply(x, method, args) : x[methodName](); + } + }, this); + + return ret; + }, + + /** + Simply converts the enumerable into a genuine array. The order is not + guaranteed. Corresponds to the method implemented by Prototype. + + @method toArray + @return {Array} the enumerable as an array. + */ + toArray: function() { + var ret = Ember.A(); + this.forEach(function(o, idx) { ret[idx] = o; }); + return ret; + }, + + /** + Returns a copy of the array with all null and undefined elements removed. + + ```javascript + var arr = ["a", null, "c", undefined]; + arr.compact(); // ["a", "c"] + ``` + + @method compact + @return {Array} the array without null and undefined elements. + */ + compact: function() { + return this.filter(function(value) { return value != null; }); + }, + + /** + Returns a new enumerable that excludes the passed value. The default + implementation returns an array regardless of the receiver type unless + the receiver does not contain the value. + + ```javascript + var arr = ["a", "b", "a", "c"]; + arr.without("a"); // ["b", "c"] + ``` + + @method without + @param {Object} value + @return {Ember.Enumerable} + */ + without: function(value) { + if (!this.contains(value)) return this; // nothing to do + var ret = Ember.A(); + this.forEach(function(k) { + if (k !== value) ret[ret.length] = k; + }) ; + return ret ; + }, + + /** + Returns a new enumerable that contains only unique values. The default + implementation returns an array regardless of the receiver type. + + ```javascript + var arr = ["a", "a", "b", "b"]; + arr.uniq(); // ["a", "b"] + ``` + + @method uniq + @return {Ember.Enumerable} + */ + uniq: function() { + var ret = Ember.A(); + this.forEach(function(k) { + if (indexOf(ret, k)<0) ret.push(k); + }); + return ret; + }, + + /** + This property will trigger anytime the enumerable's content changes. + You can observe this property to be notified of changes to the enumerables + content. + + For plain enumerables, this property is read only. `Array` overrides + this method. + + @property [] + @type Array + @return this + */ + '[]': computed(function(key, value) { + return this; + }), + + // .......................................................... + // ENUMERABLE OBSERVERS + // + + /** + Registers an enumerable observer. Must implement `Ember.EnumerableObserver` + mixin. + + @method addEnumerableObserver + @param {Object} target + @param {Hash} [opts] + @return this + */ + addEnumerableObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'enumerableWillChange'; + var didChange = (opts && opts.didChange) || 'enumerableDidChange'; + var hasObservers = get(this, 'hasEnumerableObservers'); + + if (!hasObservers) propertyWillChange(this, 'hasEnumerableObservers'); + addListener(this, '@enumerable:before', target, willChange); + addListener(this, '@enumerable:change', target, didChange); + if (!hasObservers) propertyDidChange(this, 'hasEnumerableObservers'); + return this; + }, + + /** + Removes a registered enumerable observer. + + @method removeEnumerableObserver + @param {Object} target + @param {Hash} [opts] + @return this + */ + removeEnumerableObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'enumerableWillChange'; + var didChange = (opts && opts.didChange) || 'enumerableDidChange'; + + var hasObservers = get(this, 'hasEnumerableObservers'); + if (hasObservers) propertyWillChange(this, 'hasEnumerableObservers'); + removeListener(this, '@enumerable:before', target, willChange); + removeListener(this, '@enumerable:change', target, didChange); + if (hasObservers) propertyDidChange(this, 'hasEnumerableObservers'); + return this; + }, + + /** + Becomes true whenever the array currently has observers watching changes + on the array. + + @property hasEnumerableObservers + @type Boolean + */ + hasEnumerableObservers: computed(function() { + return hasListeners(this, '@enumerable:change') || hasListeners(this, '@enumerable:before'); + }), + + + /** + Invoke this method just before the contents of your enumerable will + change. You can either omit the parameters completely or pass the objects + to be removed or added if available or just a count. + + @method enumerableContentWillChange + @param {Ember.Enumerable|Number} removing An enumerable of the objects to + be removed or the number of items to be removed. + @param {Ember.Enumerable|Number} adding An enumerable of the objects to be + added or the number of items to be added. + @chainable + */ + enumerableContentWillChange: function(removing, adding) { + + var removeCnt, addCnt, hasDelta; + + if ('number' === typeof removing) removeCnt = removing; + else if (removing) removeCnt = get(removing, 'length'); + else removeCnt = removing = -1; + + if ('number' === typeof adding) addCnt = adding; + else if (adding) addCnt = get(adding,'length'); + else addCnt = adding = -1; + + hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0; + + if (removing === -1) removing = null; + if (adding === -1) adding = null; + + propertyWillChange(this, '[]'); + if (hasDelta) propertyWillChange(this, 'length'); + sendEvent(this, '@enumerable:before', [this, removing, adding]); + + return this; + }, + + /** + Invoke this method when the contents of your enumerable has changed. + This will notify any observers watching for content changes. If you are + implementing an ordered enumerable (such as an array), also pass the + start and end values where the content changed so that it can be used to + notify range observers. + + @method enumerableContentDidChange + @param {Ember.Enumerable|Number} removing An enumerable of the objects to + be removed or the number of items to be removed. + @param {Ember.Enumerable|Number} adding An enumerable of the objects to + be added or the number of items to be added. + @chainable + */ + enumerableContentDidChange: function(removing, adding) { + var removeCnt, addCnt, hasDelta; + + if ('number' === typeof removing) removeCnt = removing; + else if (removing) removeCnt = get(removing, 'length'); + else removeCnt = removing = -1; + + if ('number' === typeof adding) addCnt = adding; + else if (adding) addCnt = get(adding, 'length'); + else addCnt = adding = -1; + + hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0; + + if (removing === -1) removing = null; + if (adding === -1) adding = null; + + sendEvent(this, '@enumerable:change', [this, removing, adding]); + if (hasDelta) propertyDidChange(this, 'length'); + propertyDidChange(this, '[]'); + + return this ; + }, + + /** + Converts the enumerable into an array and sorts by the keys + specified in the argument. + + You may provide multiple arguments to sort by multiple properties. + + @method sortBy + @param {String} property name(s) to sort on + @return {Array} The sorted array. + @since 1.2.0 + */ + sortBy: function() { + var sortKeys = arguments; + return this.toArray().sort(function(a, b){ + for(var i = 0; i < sortKeys.length; i++) { + var key = sortKeys[i]; + var propA = get(a, key); + var propB = get(b, key); + // return 1 or -1 else continue to the next sortKey + var compareValue = compare(propA, propB); + if (compareValue) { return compareValue; } + } + return 0; + }); + } + }); + }); +define("ember-runtime/mixins/evented", + ["ember-metal/mixin","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var addListener = __dependency2__.addListener; + var removeListener = __dependency2__.removeListener; + var hasListeners = __dependency2__.hasListeners; + var sendEvent = __dependency2__.sendEvent; + + /** + @module ember + @submodule ember-runtime + */ + + /** + This mixin allows for Ember objects to subscribe to and emit events. + + ```javascript + App.Person = Ember.Object.extend(Ember.Evented, { + greet: function() { + // ... + this.trigger('greet'); + } + }); + + var person = App.Person.create(); + + person.on('greet', function() { + console.log('Our person has greeted'); + }); + + person.greet(); + + // outputs: 'Our person has greeted' + ``` + + You can also chain multiple event subscriptions: + + ```javascript + person.on('greet', function() { + console.log('Our person has greeted'); + }).one('greet', function() { + console.log('Offer one-time special'); + }).off('event', this, forgetThis); + ``` + + @class Evented + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + + /** + Subscribes to a named event with given function. + + ```javascript + person.on('didLoad', function() { + // fired once the person has loaded + }); + ``` + + An optional target can be passed in as the 2nd argument that will + be set as the "this" for the callback. This is a good way to give your + function access to the object triggering the event. When the target + parameter is used the callback becomes the third argument. + + @method on + @param {String} name The name of the event + @param {Object} [target] The "this" binding for the callback + @param {Function} method The callback to execute + @return this + */ + on: function(name, target, method) { + addListener(this, name, target, method); + return this; + }, + + /** + Subscribes a function to a named event and then cancels the subscription + after the first time the event is triggered. It is good to use ``one`` when + you only care about the first time an event has taken place. + + This function takes an optional 2nd argument that will become the "this" + value for the callback. If this argument is passed then the 3rd argument + becomes the function. + + @method one + @param {String} name The name of the event + @param {Object} [target] The "this" binding for the callback + @param {Function} method The callback to execute + @return this + */ + one: function(name, target, method) { + if (!method) { + method = target; + target = null; + } + + addListener(this, name, target, method, true); + return this; + }, + + /** + Triggers a named event for the object. Any additional arguments + will be passed as parameters to the functions that are subscribed to the + event. + + ```javascript + person.on('didEat', function(food) { + console.log('person ate some ' + food); + }); + + person.trigger('didEat', 'broccoli'); + + // outputs: person ate some broccoli + ``` + @method trigger + @param {String} name The name of the event + @param {Object...} args Optional arguments to pass on + */ + trigger: function(name) { + var length = arguments.length; + var args = new Array(length - 1); + + for (var i = 1; i < length; i++) { + args[i - 1] = arguments[i]; + } + + sendEvent(this, name, args); + }, + + /** + Cancels subscription for given name, target, and method. + + @method off + @param {String} name The name of the event + @param {Object} target The target of the subscription + @param {Function} method The function of the subscription + @return this + */ + off: function(name, target, method) { + removeListener(this, name, target, method); + return this; + }, + + /** + Checks to see if object has any subscriptions for named event. + + @method has + @param {String} name The name of the event + @return {Boolean} does the object have a subscription for event + */ + has: function(name) { + return hasListeners(this, name); + } + }); + }); +define("ember-runtime/mixins/freezable", + ["ember-metal/mixin","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Mixin = __dependency1__.Mixin; + var get = __dependency2__.get; + var set = __dependency3__.set; + + /** + The `Ember.Freezable` mixin implements some basic methods for marking an + object as frozen. Once an object is frozen it should be read only. No changes + may be made the internal state of the object. + + ## Enforcement + + To fully support freezing in your subclass, you must include this mixin and + override any method that might alter any property on the object to instead + raise an exception. You can check the state of an object by checking the + `isFrozen` property. + + Although future versions of JavaScript may support language-level freezing + object objects, that is not the case today. Even if an object is freezable, + it is still technically possible to modify the object, even though it could + break other parts of your application that do not expect a frozen object to + change. It is, therefore, very important that you always respect the + `isFrozen` property on all freezable objects. + + ## Example Usage + + The example below shows a simple object that implement the `Ember.Freezable` + protocol. + + ```javascript + Contact = Ember.Object.extend(Ember.Freezable, { + firstName: null, + lastName: null, + + // swaps the names + swapNames: function() { + if (this.get('isFrozen')) throw Ember.FROZEN_ERROR; + var tmp = this.get('firstName'); + this.set('firstName', this.get('lastName')); + this.set('lastName', tmp); + return this; + } + + }); + + c = Contact.create({ firstName: "John", lastName: "Doe" }); + c.swapNames(); // returns c + c.freeze(); + c.swapNames(); // EXCEPTION + ``` + + ## Copying + + Usually the `Ember.Freezable` protocol is implemented in cooperation with the + `Ember.Copyable` protocol, which defines a `frozenCopy()` method that will + return a frozen object, if the object implements this method as well. + + @class Freezable + @namespace Ember + @since Ember 0.9 + */ + var Freezable = Mixin.create({ + + /** + Set to `true` when the object is frozen. Use this property to detect + whether your object is frozen or not. + + @property isFrozen + @type Boolean + */ + isFrozen: false, + + /** + Freezes the object. Once this method has been called the object should + no longer allow any properties to be edited. + + @method freeze + @return {Object} receiver + */ + freeze: function() { + if (get(this, 'isFrozen')) return this; + set(this, 'isFrozen', true); + return this; + } + + }); + __exports__.Freezable = Freezable; + var FROZEN_ERROR = "Frozen object cannot be modified."; + __exports__.FROZEN_ERROR = FROZEN_ERROR; + }); +define("ember-runtime/mixins/mutable_array", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/mixin","ember-runtime/mixins/array","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + + // require('ember-runtime/mixins/array'); + // require('ember-runtime/mixins/mutable_enumerable'); + + // .......................................................... + // CONSTANTS + // + + var OUT_OF_RANGE_EXCEPTION = "Index out of range"; + var EMPTY = []; + + // .......................................................... + // HELPERS + // + + var get = __dependency1__.get; + var set = __dependency2__.set; + var isArray = __dependency3__.isArray; + var EmberError = __dependency4__["default"]; + var Mixin = __dependency5__.Mixin; + var required = __dependency5__.required; + var EmberArray = __dependency6__["default"]; + var MutableEnumerable = __dependency7__["default"]; + var Enumerable = __dependency8__["default"]; + /** + This mixin defines the API for modifying array-like objects. These methods + can be applied only to a collection that keeps its items in an ordered set. + It builds upon the Array mixin and adds methods to modify the array. + Concrete implementations of this class include ArrayProxy and ArrayController. + + It is important to use the methods in this class to modify arrays so that + changes are observable. This allows the binding system in Ember to function + correctly. + + + Note that an Array can change even if it does not implement this mixin. + For example, one might implement a SparseArray that cannot be directly + modified, but if its underlying enumerable changes, it will change also. + + @class MutableArray + @namespace Ember + @uses Ember.Array + @uses Ember.MutableEnumerable + */ + __exports__["default"] = Mixin.create(EmberArray, MutableEnumerable, { + + /** + __Required.__ You must implement this method to apply this mixin. + + This is one of the primitives you must implement to support `Ember.Array`. + You should replace amt objects started at idx with the objects in the + passed array. You should also call `this.enumerableContentDidChange()` + + @method replace + @param {Number} idx Starting index in the array to replace. If + idx >= length, then append to the end of the array. + @param {Number} amt Number of elements that should be removed from + the array, starting at *idx*. + @param {Array} objects An array of zero or more objects that should be + inserted into the array at *idx* + */ + replace: required(), + + /** + Remove all elements from the array. This is useful if you + want to reuse an existing array without having to recreate it. + + ```javascript + var colors = ["red", "green", "blue"]; + color.length(); // 3 + colors.clear(); // [] + colors.length(); // 0 + ``` + + @method clear + @return {Ember.Array} An empty Array. + */ + clear: function () { + var len = get(this, 'length'); + if (len === 0) return this; + this.replace(0, len, EMPTY); + return this; + }, + + /** + This will use the primitive `replace()` method to insert an object at the + specified index. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.insertAt(2, "yellow"); // ["red", "green", "yellow", "blue"] + colors.insertAt(5, "orange"); // Error: Index out of range + ``` + + @method insertAt + @param {Number} idx index of insert the object at. + @param {Object} object object to insert + @return {Ember.Array} receiver + */ + insertAt: function(idx, object) { + if (idx > get(this, 'length')) throw new EmberError(OUT_OF_RANGE_EXCEPTION); + this.replace(idx, 0, [object]); + return this; + }, + + /** + Remove an object at the specified index using the `replace()` primitive + method. You can pass either a single index, or a start and a length. + + If you pass a start and length that is beyond the + length this method will throw an `OUT_OF_RANGE_EXCEPTION`. + + ```javascript + var colors = ["red", "green", "blue", "yellow", "orange"]; + colors.removeAt(0); // ["green", "blue", "yellow", "orange"] + colors.removeAt(2, 2); // ["green", "blue"] + colors.removeAt(4, 2); // Error: Index out of range + ``` + + @method removeAt + @param {Number} start index, start of range + @param {Number} len length of passing range + @return {Ember.Array} receiver + */ + removeAt: function(start, len) { + if ('number' === typeof start) { + + if ((start < 0) || (start >= get(this, 'length'))) { + throw new EmberError(OUT_OF_RANGE_EXCEPTION); + } + + // fast case + if (len === undefined) len = 1; + this.replace(start, len, EMPTY); + } + + return this; + }, + + /** + Push the object onto the end of the array. Works just like `push()` but it + is KVO-compliant. + + ```javascript + var colors = ["red", "green"]; + colors.pushObject("black"); // ["red", "green", "black"] + colors.pushObject(["yellow"]); // ["red", "green", ["yellow"]] + ``` + + @method pushObject + @param {*} obj object to push + @return object same object passed as a param + */ + pushObject: function(obj) { + this.insertAt(get(this, 'length'), obj); + return obj; + }, + + /** + Add the objects in the passed numerable to the end of the array. Defers + notifying observers of the change until all objects are added. + + ```javascript + var colors = ["red"]; + colors.pushObjects(["yellow", "orange"]); // ["red", "yellow", "orange"] + ``` + + @method pushObjects + @param {Ember.Enumerable} objects the objects to add + @return {Ember.Array} receiver + */ + pushObjects: function(objects) { + if (!(Enumerable.detect(objects) || isArray(objects))) { + throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects"); + } + this.replace(get(this, 'length'), 0, objects); + return this; + }, + + /** + Pop object from array or nil if none are left. Works just like `pop()` but + it is KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.popObject(); // "blue" + console.log(colors); // ["red", "green"] + ``` + + @method popObject + @return object + */ + popObject: function() { + var len = get(this, 'length'); + if (len === 0) return null; + + var ret = this.objectAt(len-1); + this.removeAt(len-1, 1); + return ret; + }, + + /** + Shift an object from start of array or nil if none are left. Works just + like `shift()` but it is KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.shiftObject(); // "red" + console.log(colors); // ["green", "blue"] + ``` + + @method shiftObject + @return object + */ + shiftObject: function() { + if (get(this, 'length') === 0) return null; + var ret = this.objectAt(0); + this.removeAt(0); + return ret; + }, + + /** + Unshift an object to start of array. Works just like `unshift()` but it is + KVO-compliant. + + ```javascript + var colors = ["red"]; + colors.unshiftObject("yellow"); // ["yellow", "red"] + colors.unshiftObject(["black"]); // [["black"], "yellow", "red"] + ``` + + @method unshiftObject + @param {*} obj object to unshift + @return object same object passed as a param + */ + unshiftObject: function(obj) { + this.insertAt(0, obj); + return obj; + }, + + /** + Adds the named objects to the beginning of the array. Defers notifying + observers until all objects have been added. + + ```javascript + var colors = ["red"]; + colors.unshiftObjects(["black", "white"]); // ["black", "white", "red"] + colors.unshiftObjects("yellow"); // Type Error: 'undefined' is not a function + ``` + + @method unshiftObjects + @param {Ember.Enumerable} objects the objects to add + @return {Ember.Array} receiver + */ + unshiftObjects: function(objects) { + this.replace(0, 0, objects); + return this; + }, + + /** + Reverse objects in the array. Works just like `reverse()` but it is + KVO-compliant. + + @method reverseObjects + @return {Ember.Array} receiver + */ + reverseObjects: function() { + var len = get(this, 'length'); + if (len === 0) return this; + var objects = this.toArray().reverse(); + this.replace(0, len, objects); + return this; + }, + + /** + Replace all the the receiver's content with content of the argument. + If argument is an empty array receiver will be cleared. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.setObjects(["black", "white"]); // ["black", "white"] + colors.setObjects([]); // [] + ``` + + @method setObjects + @param {Ember.Array} objects array whose content will be used for replacing + the content of the receiver + @return {Ember.Array} receiver with the new content + */ + setObjects: function(objects) { + if (objects.length === 0) return this.clear(); + + var len = get(this, 'length'); + this.replace(0, len, objects); + return this; + }, + + // .......................................................... + // IMPLEMENT Ember.MutableEnumerable + // + + /** + Remove all occurances of an object in the array. + + ```javascript + var cities = ["Chicago", "Berlin", "Lima", "Chicago"]; + cities.removeObject("Chicago"); // ["Berlin", "Lima"] + cities.removeObject("Lima"); // ["Berlin"] + cities.removeObject("Tokyo") // ["Berlin"] + ``` + + @method removeObject + @param {*} obj object to remove + @return {Ember.Array} receiver + */ + removeObject: function(obj) { + var loc = get(this, 'length') || 0; + while(--loc >= 0) { + var curObject = this.objectAt(loc); + if (curObject === obj) this.removeAt(loc); + } + return this; + }, + + /** + Push the object onto the end of the array if it is not already + present in the array. + + ```javascript + var cities = ["Chicago", "Berlin"]; + cities.addObject("Lima"); // ["Chicago", "Berlin", "Lima"] + cities.addObject("Berlin"); // ["Chicago", "Berlin", "Lima"] + ``` + + @method addObject + @param {*} obj object to add, if not already present + @return {Ember.Array} receiver + */ + addObject: function(obj) { + if (!this.contains(obj)) this.pushObject(obj); + return this; + } + + }); + }); +define("ember-runtime/mixins/mutable_enumerable", + ["ember-metal/enumerable_utils","ember-runtime/mixins/enumerable","ember-metal/mixin","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var forEach = __dependency1__.forEach; + var Enumerable = __dependency2__["default"]; + var Mixin = __dependency3__.Mixin; + var required = __dependency3__.required; + var beginPropertyChanges = __dependency4__.beginPropertyChanges; + var endPropertyChanges = __dependency4__.endPropertyChanges; + + /** + @module ember + @submodule ember-runtime + */ + + /** + This mixin defines the API for modifying generic enumerables. These methods + can be applied to an object regardless of whether it is ordered or + unordered. + + Note that an Enumerable can change even if it does not implement this mixin. + For example, a MappedEnumerable cannot be directly modified but if its + underlying enumerable changes, it will change also. + + ## Adding Objects + + To add an object to an enumerable, use the `addObject()` method. This + method will only add the object to the enumerable if the object is not + already present and is of a type supported by the enumerable. + + ```javascript + set.addObject(contact); + ``` + + ## Removing Objects + + To remove an object from an enumerable, use the `removeObject()` method. This + will only remove the object if it is present in the enumerable, otherwise + this method has no effect. + + ```javascript + set.removeObject(contact); + ``` + + ## Implementing In Your Own Code + + If you are implementing an object and want to support this API, just include + this mixin in your class and implement the required methods. In your unit + tests, be sure to apply the Ember.MutableEnumerableTests to your object. + + @class MutableEnumerable + @namespace Ember + @uses Ember.Enumerable + */ + __exports__["default"] = Mixin.create(Enumerable, { + + /** + __Required.__ You must implement this method to apply this mixin. + + Attempts to add the passed object to the receiver if the object is not + already present in the collection. If the object is present, this method + has no effect. + + If the passed object is of a type not supported by the receiver, + then this method should raise an exception. + + @method addObject + @param {Object} object The object to add to the enumerable. + @return {Object} the passed object + */ + addObject: required(Function), + + /** + Adds each object in the passed enumerable to the receiver. + + @method addObjects + @param {Ember.Enumerable} objects the objects to add. + @return {Object} receiver + */ + addObjects: function(objects) { + beginPropertyChanges(this); + forEach(objects, function(obj) { this.addObject(obj); }, this); + endPropertyChanges(this); + return this; + }, + + /** + __Required.__ You must implement this method to apply this mixin. + + Attempts to remove the passed object from the receiver collection if the + object is present in the collection. If the object is not present, + this method has no effect. + + If the passed object is of a type not supported by the receiver, + then this method should raise an exception. + + @method removeObject + @param {Object} object The object to remove from the enumerable. + @return {Object} the passed object + */ + removeObject: required(Function), + + + /** + Removes each object in the passed enumerable from the receiver. + + @method removeObjects + @param {Ember.Enumerable} objects the objects to remove + @return {Object} receiver + */ + removeObjects: function(objects) { + beginPropertyChanges(this); + for (var i = objects.length - 1; i >= 0; i--) { + this.removeObject(objects[i]); + } + endPropertyChanges(this); + return this; + } + }); + }); +define("ember-runtime/mixins/observable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/get_properties","ember-metal/set_properties","ember-metal/mixin","ember-metal/events","ember-metal/property_events","ember-metal/observer","ember-metal/computed","ember-metal/is_none","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var getWithDefault = __dependency2__.getWithDefault; + var set = __dependency3__.set; + var apply = __dependency4__.apply; + var getProperties = __dependency5__["default"]; + var setProperties = __dependency6__["default"]; + var Mixin = __dependency7__.Mixin; + var hasListeners = __dependency8__.hasListeners; + var beginPropertyChanges = __dependency9__.beginPropertyChanges; + var propertyWillChange = __dependency9__.propertyWillChange; + var propertyDidChange = __dependency9__.propertyDidChange; + var endPropertyChanges = __dependency9__.endPropertyChanges; + var addObserver = __dependency10__.addObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeObserver = __dependency10__.removeObserver; + var observersFor = __dependency10__.observersFor; + var cacheFor = __dependency11__.cacheFor; + var isNone = __dependency12__.isNone; + + + var slice = Array.prototype.slice; + /** + ## Overview + + This mixin provides properties and property observing functionality, core + features of the Ember object model. + + Properties and observers allow one object to observe changes to a + property on another object. This is one of the fundamental ways that + models, controllers and views communicate with each other in an Ember + application. + + Any object that has this mixin applied can be used in observer + operations. That includes `Ember.Object` and most objects you will + interact with as you write your Ember application. + + Note that you will not generally apply this mixin to classes yourself, + but you will use the features provided by this module frequently, so it + is important to understand how to use it. + + ## Using `get()` and `set()` + + Because of Ember's support for bindings and observers, you will always + access properties using the get method, and set properties using the + set method. This allows the observing objects to be notified and + computed properties to be handled properly. + + More documentation about `get` and `set` are below. + + ## Observing Property Changes + + You typically observe property changes simply by adding the `observes` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property changes + }.observes('value') + }); + ``` + + Although this is the most common way to add an observer, this capability + is actually built into the `Ember.Object` class on top of two methods + defined in this mixin: `addObserver` and `removeObserver`. You can use + these two methods to add and remove observers yourself if you need to + do so at runtime. + + To add an observer for a property, call: + + ```javascript + object.addObserver('propertyKey', targetObject, targetAction) + ``` + + This will call the `targetAction` method on the `targetObject` whenever + the value of the `propertyKey` changes. + + Note that if `propertyKey` is a computed property, the observer will be + called when any of the property dependencies are changed, even if the + resulting value of the computed property is unchanged. This is necessary + because computed properties are not computed until `get` is called. + + @class Observable + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + + /** + Retrieves the value of a property from the object. + + This method is usually similar to using `object[keyName]` or `object.keyName`, + however it supports both computed properties and the unknownProperty + handler. + + Because `get` unifies the syntax for accessing all these kinds + of properties, it can make many refactorings easier, such as replacing a + simple property with a computed property, or vice versa. + + ### Computed Properties + + Computed properties are methods defined with the `property` modifier + declared at the end, such as: + + ```javascript + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + }.property('firstName', 'lastName') + ``` + + When you call `get` on a computed property, the function will be + called and the return value will be returned instead of the function + itself. + + ### Unknown Properties + + Likewise, if you try to call `get` on a property whose value is + `undefined`, the `unknownProperty()` method will be called on the object. + If this method returns any value other than `undefined`, it will be returned + instead. This allows you to implement "virtual" properties that are + not defined upfront. + + @method get + @param {String} keyName The property to retrieve + @return {Object} The property value or undefined. + */ + get: function(keyName) { + return get(this, keyName); + }, + + /** + To get the values of multiple properties at once, call `getProperties` + with a list of strings or an array: + + ```javascript + record.getProperties('firstName', 'lastName', 'zipCode'); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + is equivalent to: + + ```javascript + record.getProperties(['firstName', 'lastName', 'zipCode']); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + @method getProperties + @param {String...|Array} list of keys to get + @return {Hash} + */ + getProperties: function() { + return apply(null, getProperties, [this].concat(slice.call(arguments))); + }, + + /** + Sets the provided key or path to the value. + + This method is generally very similar to calling `object[key] = value` or + `object.key = value`, except that it provides support for computed + properties, the `setUnknownProperty()` method and property observers. + + ### Computed Properties + + If you try to set a value on a key that has a computed property handler + defined (see the `get()` method for an example), then `set()` will call + that method, passing both the value and key instead of simply changing + the value itself. This is useful for those times when you need to + implement a property that is composed of one or more member + properties. + + ### Unknown Properties + + If you try to set a value on a key that is undefined in the target + object, then the `setUnknownProperty()` handler will be called instead. This + gives you an opportunity to implement complex "virtual" properties that + are not predefined on the object. If `setUnknownProperty()` returns + undefined, then `set()` will simply set the value on the object. + + ### Property Observers + + In addition to changing the property, `set()` will also register a property + change with the object. Unless you have placed this call inside of a + `beginPropertyChanges()` and `endPropertyChanges(),` any "local" observers + (i.e. observer methods declared on the same object), will be called + immediately. Any "remote" observers (i.e. observer methods declared on + another object) will be placed in a queue and called at a later time in a + coalesced manner. + + ### Chaining + + In addition to property changes, `set()` returns the value of the object + itself so you can do chaining like this: + + ```javascript + record.set('firstName', 'Charles').set('lastName', 'Jolley'); + ``` + + @method set + @param {String} keyName The property to set + @param {Object} value The value to set or `null`. + @return {Ember.Observable} + */ + set: function(keyName, value) { + set(this, keyName, value); + return this; + }, + + + /** + Sets a list of properties at once. These properties are set inside + a single `beginPropertyChanges` and `endPropertyChanges` batch, so + observers will be buffered. + + ```javascript + record.setProperties({ firstName: 'Charles', lastName: 'Jolley' }); + ``` + + @method setProperties + @param {Hash} hash the hash of keys and values to set + @return {Ember.Observable} + */ + setProperties: function(hash) { + return setProperties(this, hash); + }, + + /** + Begins a grouping of property changes. + + You can use this method to group property changes so that notifications + will not be sent until the changes are finished. If you plan to make a + large number of changes to an object at one time, you should call this + method at the beginning of the changes to begin deferring change + notifications. When you are done making changes, call + `endPropertyChanges()` to deliver the deferred change notifications and end + deferring. + + @method beginPropertyChanges + @return {Ember.Observable} + */ + beginPropertyChanges: function() { + beginPropertyChanges(); + return this; + }, + + /** + Ends a grouping of property changes. + + You can use this method to group property changes so that notifications + will not be sent until the changes are finished. If you plan to make a + large number of changes to an object at one time, you should call + `beginPropertyChanges()` at the beginning of the changes to defer change + notifications. When you are done making changes, call this method to + deliver the deferred change notifications and end deferring. + + @method endPropertyChanges + @return {Ember.Observable} + */ + endPropertyChanges: function() { + endPropertyChanges(); + return this; + }, + + /** + Notify the observer system that a property is about to change. + + Sometimes you need to change a value directly or indirectly without + actually calling `get()` or `set()` on it. In this case, you can use this + method and `propertyDidChange()` instead. Calling these two methods + together will notify all observers that the property has potentially + changed value. + + Note that you must always call `propertyWillChange` and `propertyDidChange` + as a pair. If you do not, it may get the property change groups out of + order and cause notifications to be delivered more often than you would + like. + + @method propertyWillChange + @param {String} keyName The property key that is about to change. + @return {Ember.Observable} + */ + propertyWillChange: function(keyName) { + propertyWillChange(this, keyName); + return this; + }, + + /** + Notify the observer system that a property has just changed. + + Sometimes you need to change a value directly or indirectly without + actually calling `get()` or `set()` on it. In this case, you can use this + method and `propertyWillChange()` instead. Calling these two methods + together will notify all observers that the property has potentially + changed value. + + Note that you must always call `propertyWillChange` and `propertyDidChange` + as a pair. If you do not, it may get the property change groups out of + order and cause notifications to be delivered more often than you would + like. + + @method propertyDidChange + @param {String} keyName The property key that has just changed. + @return {Ember.Observable} + */ + propertyDidChange: function(keyName) { + propertyDidChange(this, keyName); + return this; + }, + + /** + Convenience method to call `propertyWillChange` and `propertyDidChange` in + succession. + + @method notifyPropertyChange + @param {String} keyName The property key to be notified about. + @return {Ember.Observable} + */ + notifyPropertyChange: function(keyName) { + this.propertyWillChange(keyName); + this.propertyDidChange(keyName); + return this; + }, + + addBeforeObserver: function(key, target, method) { + addBeforeObserver(this, key, target, method); + }, + + /** + Adds an observer on a property. + + This is the core method used to register an observer for a property. + + Once you call this method, any time the key's value is set, your observer + will be notified. Note that the observers are triggered any time the + value is set, regardless of whether it has actually changed. Your + observer should be prepared to handle that. + + You can also pass an optional context parameter to this method. The + context will be passed to your observer method whenever it is triggered. + Note that if you add the same target/method pair on a key multiple times + with different context parameters, your observer will only be called once + with the last context you passed. + + ### Observer Methods + + Observer methods you pass should generally have the following signature if + you do not pass a `context` parameter: + + ```javascript + fooDidChange: function(sender, key, value, rev) { }; + ``` + + The sender is the object that changed. The key is the property that + changes. The value property is currently reserved and unused. The rev + is the last property revision of the object when it changed, which you can + use to detect if the key value has really changed or not. + + If you pass a `context` parameter, the context will be passed before the + revision like so: + + ```javascript + fooDidChange: function(sender, key, value, context, rev) { }; + ``` + + Usually you will not need the value, context or revision parameters at + the end. In this case, it is common to write observer methods that take + only a sender and key value as parameters or, if you aren't interested in + any of these values, to write an observer that has no parameters at all. + + @method addObserver + @param {String} key The key to observer + @param {Object} target The target object to invoke + @param {String|Function} method The method to invoke. + */ + addObserver: function(key, target, method) { + addObserver(this, key, target, method); + }, + + /** + Remove an observer you have previously registered on this object. Pass + the same key, target, and method you passed to `addObserver()` and your + target will no longer receive notifications. + + @method removeObserver + @param {String} key The key to observer + @param {Object} target The target object to invoke + @param {String|Function} method The method to invoke. + */ + removeObserver: function(key, target, method) { + removeObserver(this, key, target, method); + }, + + /** + Returns `true` if the object currently has observers registered for a + particular key. You can use this method to potentially defer performing + an expensive action until someone begins observing a particular property + on the object. + + @method hasObserverFor + @param {String} key Key to check + @return {Boolean} + */ + hasObserverFor: function(key) { + return hasListeners(this, key+':change'); + }, + + /** + Retrieves the value of a property, or a default value in the case that the + property returns `undefined`. + + ```javascript + person.getWithDefault('lastName', 'Doe'); + ``` + + @method getWithDefault + @param {String} keyName The name of the property to retrieve + @param {Object} defaultValue The value to return if the property value is undefined + @return {Object} The property value or the defaultValue. + */ + getWithDefault: function(keyName, defaultValue) { + return getWithDefault(this, keyName, defaultValue); + }, + + /** + Set the value of a property to the current value plus some amount. + + ```javascript + person.incrementProperty('age'); + team.incrementProperty('score', 2); + ``` + + @method incrementProperty + @param {String} keyName The name of the property to increment + @param {Number} increment The amount to increment by. Defaults to 1 + @return {Number} The new property value + */ + incrementProperty: function(keyName, increment) { + if (isNone(increment)) { increment = 1; } + Ember.assert("Must pass a numeric value to incrementProperty", (!isNaN(parseFloat(increment)) && isFinite(increment))); + set(this, keyName, (parseFloat(get(this, keyName)) || 0) + increment); + return get(this, keyName); + }, + + /** + Set the value of a property to the current value minus some amount. + + ```javascript + player.decrementProperty('lives'); + orc.decrementProperty('health', 5); + ``` + + @method decrementProperty + @param {String} keyName The name of the property to decrement + @param {Number} decrement The amount to decrement by. Defaults to 1 + @return {Number} The new property value + */ + decrementProperty: function(keyName, decrement) { + if (isNone(decrement)) { decrement = 1; } + Ember.assert("Must pass a numeric value to decrementProperty", (!isNaN(parseFloat(decrement)) && isFinite(decrement))); + set(this, keyName, (get(this, keyName) || 0) - decrement); + return get(this, keyName); + }, + + /** + Set the value of a boolean property to the opposite of it's + current value. + + ```javascript + starship.toggleProperty('warpDriveEngaged'); + ``` + + @method toggleProperty + @param {String} keyName The name of the property to toggle + @return {Object} The new property value + */ + toggleProperty: function(keyName) { + set(this, keyName, !get(this, keyName)); + return get(this, keyName); + }, + + /** + Returns the cached value of a computed property, if it exists. + This allows you to inspect the value of a computed property + without accidentally invoking it if it is intended to be + generated lazily. + + @method cacheFor + @param {String} keyName + @return {Object} The cached value of the computed property, if any + */ + cacheFor: function(keyName) { + return cacheFor(this, keyName); + }, + + // intended for debugging purposes + observersForKey: function(keyName) { + return observersFor(this, keyName); + } + }); + }); +define("ember-runtime/mixins/promise_proxy", + ["ember-metal/property_get","ember-metal/set_properties","ember-metal/computed","ember-metal/mixin","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var setProperties = __dependency2__["default"]; + var computed = __dependency3__.computed; + var Mixin = __dependency4__.Mixin; + var EmberError = __dependency5__["default"]; + + var not = computed.not; + var or = computed.or; + + /** + @module ember + @submodule ember-runtime + */ + + function tap(proxy, promise) { + setProperties(proxy, { + isFulfilled: false, + isRejected: false + }); + + return promise.then(function(value) { + setProperties(proxy, { + content: value, + isFulfilled: true + }); + return value; + }, function(reason) { + setProperties(proxy, { + reason: reason, + isRejected: true + }); + throw reason; + }, "Ember: PromiseProxy"); + } + + /** + A low level mixin making ObjectProxy, ObjectController or ArrayController's promise aware. + + ```javascript + var ObjectPromiseController = Ember.ObjectController.extend(Ember.PromiseProxyMixin); + + var controller = ObjectPromiseController.create({ + promise: $.getJSON('/some/remote/data.json') + }); + + controller.then(function(json){ + // the json + }, function(reason) { + // the reason why you have no json + }); + ``` + + the controller has bindable attributes which + track the promises life cycle + + ```javascript + controller.get('isPending') //=> true + controller.get('isSettled') //=> false + controller.get('isRejected') //=> false + controller.get('isFulfilled') //=> false + ``` + + When the the $.getJSON completes, and the promise is fulfilled + with json, the life cycle attributes will update accordingly. + + ```javascript + controller.get('isPending') //=> false + controller.get('isSettled') //=> true + controller.get('isRejected') //=> false + controller.get('isFulfilled') //=> true + ``` + + As the controller is an ObjectController, and the json now its content, + all the json properties will be available directly from the controller. + + ```javascript + // Assuming the following json: + { + firstName: 'Stefan', + lastName: 'Penner' + } + + // both properties will accessible on the controller + controller.get('firstName') //=> 'Stefan' + controller.get('lastName') //=> 'Penner' + ``` + + If the controller is backing a template, the attributes are + bindable from within that template + + ```handlebars + {{#if isPending}} + loading... + {{else}} + firstName: {{firstName}} + lastName: {{lastName}} + {{/if}} + ``` + @class Ember.PromiseProxyMixin + */ + __exports__["default"] = Mixin.create({ + /** + If the proxied promise is rejected this will contain the reason + provided. + + @property reason + @default null + */ + reason: null, + + /** + Once the proxied promise has settled this will become `false`. + + @property isPending + @default true + */ + isPending: not('isSettled').readOnly(), + + /** + Once the proxied promise has settled this will become `true`. + + @property isSettled + @default false + */ + isSettled: or('isRejected', 'isFulfilled').readOnly(), + + /** + Will become `true` if the proxied promise is rejected. + + @property isRejected + @default false + */ + isRejected: false, + + /** + Will become `true` if the proxied promise is fulfilled. + + @property isFulfilled + @default false + */ + isFulfilled: false, + + /** + The promise whose fulfillment value is being proxied by this object. + + This property must be specified upon creation, and should not be + changed once created. + + Example: + + ```javascript + Ember.ObjectController.extend(Ember.PromiseProxyMixin).create({ + promise: + }); + ``` + + @property promise + */ + promise: computed(function(key, promise) { + if (arguments.length === 2) { + return tap(this, promise); + } else { + throw new EmberError("PromiseProxy's promise must be set"); + } + }), + + /** + An alias to the proxied promise's `then`. + + See RSVP.Promise.then. + + @method then + @param {Function} callback + @return {RSVP.Promise} + */ + then: promiseAlias('then'), + + /** + An alias to the proxied promise's `catch`. + + See RSVP.Promise.catch. + + @method catch + @param {Function} callback + @return {RSVP.Promise} + @since 1.3.0 + */ + 'catch': promiseAlias('catch'), + + /** + An alias to the proxied promise's `finally`. + + See RSVP.Promise.finally. + + @method finally + @param {Function} callback + @return {RSVP.Promise} + @since 1.3.0 + */ + 'finally': promiseAlias('finally') + + }); + + function promiseAlias(name) { + return function () { + var promise = get(this, 'promise'); + return promise[name].apply(promise, arguments); + }; + } + }); +define("ember-runtime/mixins/sortable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/enumerable_utils","ember-metal/mixin","ember-runtime/mixins/mutable_enumerable","ember-runtime/compare","ember-metal/observer","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.A + + var get = __dependency2__.get; + var set = __dependency3__.set; + var forEach = __dependency4__.forEach; + var Mixin = __dependency5__.Mixin; + var MutableEnumerable = __dependency6__["default"]; + var compare = __dependency7__["default"]; + var addObserver = __dependency8__.addObserver; + var removeObserver = __dependency8__.removeObserver; + var computed = __dependency9__.computed; + var beforeObserver = __dependency5__.beforeObserver; + var observer = __dependency5__.observer; + //ES6TODO: should we access these directly from their package or from how thier exposed in ember-metal? + + /** + `Ember.SortableMixin` provides a standard interface for array proxies + to specify a sort order and maintain this sorting when objects are added, + removed, or updated without changing the implicit order of their underlying + modelarray: + + ```javascript + songs = [ + {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'}, + {trackNumber: 2, title: 'Back in the U.S.S.R.'}, + {trackNumber: 3, title: 'Glass Onion'}, + ]; + + songsController = Ember.ArrayController.create({ + model: songs, + sortProperties: ['trackNumber'], + sortAscending: true + }); + + songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} + + songsController.addObject({trackNumber: 1, title: 'Dear Prudence'}); + songsController.get('firstObject'); // {trackNumber: 1, title: 'Dear Prudence'} + ``` + + If you add or remove the properties to sort by or change the sort direction the model + sort order will be automatically updated. + + ```javascript + songsController.set('sortProperties', ['title']); + songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} + + songsController.toggleProperty('sortAscending'); + songsController.get('firstObject'); // {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'} + ``` + + SortableMixin works by sorting the arrangedContent array, which is the array that + arrayProxy displays. Due to the fact that the underlying 'content' array is not changed, that + array will not display the sorted list: + + ```javascript + songsController.get('content').get('firstObject'); // Returns the unsorted original content + songsController.get('firstObject'); // Returns the sorted content. + ``` + + Although the sorted content can also be accessed through the arrangedContent property, + it is preferable to use the proxied class and not the arrangedContent array directly. + + @class SortableMixin + @namespace Ember + @uses Ember.MutableEnumerable + */ + __exports__["default"] = Mixin.create(MutableEnumerable, { + + /** + Specifies which properties dictate the arrangedContent's sort order. + + When specifying multiple properties the sorting will use properties + from the `sortProperties` array prioritized from first to last. + + @property {Array} sortProperties + */ + sortProperties: null, + + /** + Specifies the arrangedContent's sort direction. + Sorts the content in ascending order by default. Set to `false` to + use descending order. + + @property {Boolean} sortAscending + @default true + */ + sortAscending: true, + + /** + The function used to compare two values. You can override this if you + want to do custom comparisons. Functions must be of the type expected by + Array#sort, i.e. + return 0 if the two parameters are equal, + return a negative value if the first parameter is smaller than the second or + return a positive value otherwise: + + ```javascript + function(x,y) { // These are assumed to be integers + if (x === y) + return 0; + return x < y ? -1 : 1; + } + ``` + + @property sortFunction + @type {Function} + @default Ember.compare + */ + sortFunction: compare, + + orderBy: function(item1, item2) { + var result = 0; + var sortProperties = get(this, 'sortProperties'); + var sortAscending = get(this, 'sortAscending'); + var sortFunction = get(this, 'sortFunction'); + + Ember.assert("you need to define `sortProperties`", !!sortProperties); + + forEach(sortProperties, function(propertyName) { + if (result === 0) { + result = sortFunction.call(this, get(item1, propertyName), get(item2, propertyName)); + if ((result !== 0) && !sortAscending) { + result = (-1) * result; + } + } + }, this); + + return result; + }, + + destroy: function() { + var content = get(this, 'content'); + var sortProperties = get(this, 'sortProperties'); + + if (content && sortProperties) { + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(); + }, + + isSorted: computed.notEmpty('sortProperties'), + + /** + Overrides the default arrangedContent from arrayProxy in order to sort by sortFunction. + Also sets up observers for each sortProperty on each item in the content Array. + + @property arrangedContent + */ + + arrangedContent: computed('content', 'sortProperties.@each', function(key, value) { + var content = get(this, 'content'); + var isSorted = get(this, 'isSorted'); + var sortProperties = get(this, 'sortProperties'); + var self = this; + + if (content && isSorted) { + content = content.slice(); + content.sort(function(item1, item2) { + return self.orderBy(item1, item2); + }); + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + return Ember.A(content); + } + + return content; + }), + + _contentWillChange: beforeObserver('content', function() { + var content = get(this, 'content'); + var sortProperties = get(this, 'sortProperties'); + + if (content && sortProperties) { + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + this._super(); + }), + + sortPropertiesWillChange: beforeObserver('sortProperties', function() { + this._lastSortAscending = undefined; + }), + + sortPropertiesDidChange: observer('sortProperties', function() { + this._lastSortAscending = undefined; + }), + + sortAscendingWillChange: beforeObserver('sortAscending', function() { + this._lastSortAscending = get(this, 'sortAscending'); + }), + + sortAscendingDidChange: observer('sortAscending', function() { + if (this._lastSortAscending !== undefined && get(this, 'sortAscending') !== this._lastSortAscending) { + var arrangedContent = get(this, 'arrangedContent'); + arrangedContent.reverseObjects(); + } + }), + + contentArrayWillChange: function(array, idx, removedCount, addedCount) { + var isSorted = get(this, 'isSorted'); + + if (isSorted) { + var arrangedContent = get(this, 'arrangedContent'); + var removedObjects = array.slice(idx, idx+removedCount); + var sortProperties = get(this, 'sortProperties'); + + forEach(removedObjects, function(item) { + arrangedContent.removeObject(item); + + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(array, idx, removedCount, addedCount); + }, + + contentArrayDidChange: function(array, idx, removedCount, addedCount) { + var isSorted = get(this, 'isSorted'); + var sortProperties = get(this, 'sortProperties'); + + if (isSorted) { + var addedObjects = array.slice(idx, idx+addedCount); + + forEach(addedObjects, function(item) { + this.insertItemSorted(item); + + forEach(sortProperties, function(sortProperty) { + addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(array, idx, removedCount, addedCount); + }, + + insertItemSorted: function(item) { + var arrangedContent = get(this, 'arrangedContent'); + var length = get(arrangedContent, 'length'); + + var idx = this._binarySearch(item, 0, length); + arrangedContent.insertAt(idx, item); + }, + + contentItemSortPropertyDidChange: function(item) { + var arrangedContent = get(this, 'arrangedContent'); + var oldIndex = arrangedContent.indexOf(item); + var leftItem = arrangedContent.objectAt(oldIndex - 1); + var rightItem = arrangedContent.objectAt(oldIndex + 1); + var leftResult = leftItem && this.orderBy(item, leftItem); + var rightResult = rightItem && this.orderBy(item, rightItem); + + if (leftResult < 0 || rightResult > 0) { + arrangedContent.removeObject(item); + this.insertItemSorted(item); + } + }, + + _binarySearch: function(item, low, high) { + var mid, midItem, res, arrangedContent; + + if (low === high) { + return low; + } + + arrangedContent = get(this, 'arrangedContent'); + + mid = low + Math.floor((high - low) / 2); + midItem = arrangedContent.objectAt(mid); + + res = this.orderBy(midItem, item); + + if (res < 0) { + return this._binarySearch(item, mid+1, high); + } else if (res > 0) { + return this._binarySearch(item, low, mid); + } + + return mid; + } + }); + }); +define("ember-runtime/mixins/target_action_support", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.lookup, Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var typeOf = __dependency4__.typeOf; + var Mixin = __dependency5__.Mixin; + var computed = __dependency6__.computed; + + /** + `Ember.TargetActionSupport` is a mixin that can be included in a class + to add a `triggerAction` method with semantics similar to the Handlebars + `{{action}}` helper. In normal Ember usage, the `{{action}}` helper is + usually the best choice. This mixin is most often useful when you are + doing more complex event handling in View objects. + + See also `Ember.ViewTargetActionSupport`, which has + view-aware defaults for target and actionContext. + + @class TargetActionSupport + @namespace Ember + @extends Ember.Mixin + */ + var TargetActionSupport = Mixin.create({ + target: null, + action: null, + actionContext: null, + + targetObject: computed(function() { + var target = get(this, 'target'); + + if (typeOf(target) === "string") { + var value = get(this, target); + if (value === undefined) { value = get(Ember.lookup, target); } + return value; + } else { + return target; + } + }).property('target'), + + actionContextObject: computed(function() { + var actionContext = get(this, 'actionContext'); + + if (typeOf(actionContext) === "string") { + var value = get(this, actionContext); + if (value === undefined) { value = get(Ember.lookup, actionContext); } + return value; + } else { + return actionContext; + } + }).property('actionContext'), + + /** + Send an `action` with an `actionContext` to a `target`. The action, actionContext + and target will be retrieved from properties of the object. For example: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + target: Ember.computed.alias('controller'), + action: 'save', + actionContext: Ember.computed.alias('context'), + click: function() { + this.triggerAction(); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `target`, `action`, and `actionContext` can be provided as properties of + an optional object argument to `triggerAction` as well. + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + click: function() { + this.triggerAction({ + action: 'save', + target: this.get('controller'), + actionContext: this.get('context') + }); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `actionContext` defaults to the object you are mixing `TargetActionSupport` into. + But `target` and `action` must be specified either as properties or with the argument + to `triggerAction`, or a combination: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + target: Ember.computed.alias('controller'), + click: function() { + this.triggerAction({ + action: 'save' + }); // Sends the `save` action, along with a reference to `this`, + // to the current controller + } + }); + ``` + + @method triggerAction + @param opts {Hash} (optional, with the optional keys action, target and/or actionContext) + @return {Boolean} true if the action was sent successfully and did not return false + */ + triggerAction: function(opts) { + opts = opts || {}; + var action = opts.action || get(this, 'action'); + var target = opts.target || get(this, 'targetObject'); + var actionContext = opts.actionContext; + + function args(options, actionName) { + var ret = []; + if (actionName) { ret.push(actionName); } + + return ret.concat(options); + } + + if (typeof actionContext === 'undefined') { + actionContext = get(this, 'actionContextObject') || this; + } + + if (target && action) { + var ret; + + if (target.send) { + ret = target.send.apply(target, args(actionContext, action)); + } else { + Ember.assert("The action '" + action + "' did not exist on " + target, typeof target[action] === 'function'); + ret = target[action].apply(target, args(actionContext)); + } + + if (ret !== false) ret = true; + + return ret; + } else { + return false; + } + } + }); + + __exports__["default"] = TargetActionSupport; + }); +define("ember-runtime/system/application", + ["ember-runtime/system/namespace","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Namespace = __dependency1__["default"]; + + __exports__["default"] = Namespace.extend(); + }); +define("ember-runtime/system/array_proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/property_events","ember-metal/error","ember-runtime/system/object","ember-runtime/mixins/mutable_array","ember-runtime/mixins/enumerable","ember-runtime/system/string","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.K, Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var isArray = __dependency4__.isArray; + var apply = __dependency4__.apply; + var computed = __dependency5__.computed; + var beforeObserver = __dependency6__.beforeObserver; + var observer = __dependency6__.observer; + var beginPropertyChanges = __dependency7__.beginPropertyChanges; + var endPropertyChanges = __dependency7__.endPropertyChanges; + var EmberError = __dependency8__["default"]; + var EmberObject = __dependency9__["default"]; + var MutableArray = __dependency10__["default"]; + var Enumerable = __dependency11__["default"]; + var fmt = __dependency12__.fmt; + + /** + @module ember + @submodule ember-runtime + */ + + var OUT_OF_RANGE_EXCEPTION = "Index out of range"; + var EMPTY = []; + var alias = computed.alias; + var K = Ember.K; + + /** + An ArrayProxy wraps any other object that implements `Ember.Array` and/or + `Ember.MutableArray,` forwarding all requests. This makes it very useful for + a number of binding use cases or other cases where being able to swap + out the underlying array is useful. + + A simple example of usage: + + ```javascript + var pets = ['dog', 'cat', 'fish']; + var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) }); + + ap.get('firstObject'); // 'dog' + ap.set('content', ['amoeba', 'paramecium']); + ap.get('firstObject'); // 'amoeba' + ``` + + This class can also be useful as a layer to transform the contents of + an array, as they are accessed. This can be done by overriding + `objectAtContent`: + + ```javascript + var pets = ['dog', 'cat', 'fish']; + var ap = Ember.ArrayProxy.create({ + content: Ember.A(pets), + objectAtContent: function(idx) { + return this.get('content').objectAt(idx).toUpperCase(); + } + }); + + ap.get('firstObject'); // . 'DOG' + ``` + + @class ArrayProxy + @namespace Ember + @extends Ember.Object + @uses Ember.MutableArray + */ + var ArrayProxy = EmberObject.extend(MutableArray, { + + /** + The content array. Must be an object that implements `Ember.Array` and/or + `Ember.MutableArray.` + + @property content + @type Ember.Array + */ + content: null, + + /** + The array that the proxy pretends to be. In the default `ArrayProxy` + implementation, this and `content` are the same. Subclasses of `ArrayProxy` + can override this property to provide things like sorting and filtering. + + @property arrangedContent + */ + arrangedContent: alias('content'), + + /** + Should actually retrieve the object at the specified index from the + content. You can override this method in subclasses to transform the + content item to something new. + + This method will only be called if content is non-`null`. + + @method objectAtContent + @param {Number} idx The index to retrieve. + @return {Object} the value or undefined if none found + */ + objectAtContent: function(idx) { + return get(this, 'arrangedContent').objectAt(idx); + }, + + /** + Should actually replace the specified objects on the content array. + You can override this method in subclasses to transform the content item + into something new. + + This method will only be called if content is non-`null`. + + @method replaceContent + @param {Number} idx The starting index + @param {Number} amt The number of items to remove from the content. + @param {Array} objects Optional array of objects to insert or null if no + objects. + @return {void} + */ + replaceContent: function(idx, amt, objects) { + get(this, 'content').replace(idx, amt, objects); + }, + + /** + Invoked when the content property is about to change. Notifies observers that the + entire array content will change. + + @private + @method _contentWillChange + */ + _contentWillChange: beforeObserver('content', function() { + this._teardownContent(); + }), + + _teardownContent: function() { + var content = get(this, 'content'); + + if (content) { + content.removeArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + } + }, + + /** + Override to implement content array `willChange` observer. + + @method contentArrayWillChange + + @param {Ember.Array} contentArray the content array + @param {Number} start starting index of the change + @param {Number} removeCount count of items removed + @param {Number} addCount count of items added + + */ + contentArrayWillChange: K, + /** + Override to implement content array `didChange` observer. + + @method contentArrayDidChange + + @param {Ember.Array} contentArray the content array + @param {Number} start starting index of the change + @param {Number} removeCount count of items removed + @param {Number} addCount count of items added + */ + contentArrayDidChange: K, + + /** + Invoked when the content property changes. Notifies observers that the + entire array content has changed. + + @private + @method _contentDidChange + */ + _contentDidChange: observer('content', function() { + var content = get(this, 'content'); + + Ember.assert("Can't set ArrayProxy's content to itself", content !== this); + + this._setupContent(); + }), + + _setupContent: function() { + var content = get(this, 'content'); + + if (content) { + Ember.assert(fmt('ArrayProxy expects an Array or ' + + 'Ember.ArrayProxy, but you passed %@', [typeof content]), + isArray(content) || content.isDestroyed); + + content.addArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + } + }, + + _arrangedContentWillChange: beforeObserver('arrangedContent', function() { + var arrangedContent = get(this, 'arrangedContent'); + var len = arrangedContent ? get(arrangedContent, 'length') : 0; + + this.arrangedContentArrayWillChange(this, 0, len, undefined); + this.arrangedContentWillChange(this); + + this._teardownArrangedContent(arrangedContent); + }), + + _arrangedContentDidChange: observer('arrangedContent', function() { + var arrangedContent = get(this, 'arrangedContent'); + var len = arrangedContent ? get(arrangedContent, 'length') : 0; + + Ember.assert("Can't set ArrayProxy's content to itself", arrangedContent !== this); + + this._setupArrangedContent(); + + this.arrangedContentDidChange(this); + this.arrangedContentArrayDidChange(this, 0, undefined, len); + }), + + _setupArrangedContent: function() { + var arrangedContent = get(this, 'arrangedContent'); + + if (arrangedContent) { + Ember.assert(fmt('ArrayProxy expects an Array or ' + + 'Ember.ArrayProxy, but you passed %@', [typeof arrangedContent]), + isArray(arrangedContent) || arrangedContent.isDestroyed); + + arrangedContent.addArrayObserver(this, { + willChange: 'arrangedContentArrayWillChange', + didChange: 'arrangedContentArrayDidChange' + }); + } + }, + + _teardownArrangedContent: function() { + var arrangedContent = get(this, 'arrangedContent'); + + if (arrangedContent) { + arrangedContent.removeArrayObserver(this, { + willChange: 'arrangedContentArrayWillChange', + didChange: 'arrangedContentArrayDidChange' + }); + } + }, + + arrangedContentWillChange: K, + arrangedContentDidChange: K, + + objectAt: function(idx) { + return get(this, 'content') && this.objectAtContent(idx); + }, + + length: computed(function() { + var arrangedContent = get(this, 'arrangedContent'); + return arrangedContent ? get(arrangedContent, 'length') : 0; + // No dependencies since Enumerable notifies length of change + }), + + _replace: function(idx, amt, objects) { + var content = get(this, 'content'); + Ember.assert('The content property of '+ this.constructor + ' should be set before modifying it', content); + if (content) this.replaceContent(idx, amt, objects); + return this; + }, + + replace: function() { + if (get(this, 'arrangedContent') === get(this, 'content')) { + apply(this, this._replace, arguments); + } else { + throw new EmberError("Using replace on an arranged ArrayProxy is not allowed."); + } + }, + + _insertAt: function(idx, object) { + if (idx > get(this, 'content.length')) throw new EmberError(OUT_OF_RANGE_EXCEPTION); + this._replace(idx, 0, [object]); + return this; + }, + + insertAt: function(idx, object) { + if (get(this, 'arrangedContent') === get(this, 'content')) { + return this._insertAt(idx, object); + } else { + throw new EmberError("Using insertAt on an arranged ArrayProxy is not allowed."); + } + }, + + removeAt: function(start, len) { + if ('number' === typeof start) { + var content = get(this, 'content'); + var arrangedContent = get(this, 'arrangedContent'); + var indices = []; + var i; + + if ((start < 0) || (start >= get(this, 'length'))) { + throw new EmberError(OUT_OF_RANGE_EXCEPTION); + } + + if (len === undefined) len = 1; + + // Get a list of indices in original content to remove + for (i=start; i= 0) { + var baseValue = this[keyName]; + + if (baseValue) { + if ('function' === typeof baseValue.concat) { + value = baseValue.concat(value); + } else { + value = makeArray(baseValue).concat(value); + } + } else { + value = makeArray(value); + } + } + + if (desc) { + desc.set(this, keyName, value); + } else { + if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { + this.setUnknownProperty(keyName, value); + } else { + + if (hasPropertyAccessors) { + defineProperty(this, keyName, null, value); // setup mandatory setter + } else { + this[keyName] = value; + } + } + } + } + } + } + finishPartial(this, m); + var length = arguments.length; + var args = new Array(length); + for (var x = 0; x < length; x++) { + args[x] = arguments[x]; + } + apply(this, this.init, args); + m.proto = proto; + finishChains(this); + sendEvent(this, "init"); + }; + + Class.toString = Mixin.prototype.toString; + Class.willReopen = function() { + if (wasApplied) { + Class.PrototypeMixin = Mixin.create(Class.PrototypeMixin); + } + + wasApplied = false; + }; + Class._initMixins = function(args) { initMixins = args; }; + Class._initProperties = function(args) { initProperties = args; }; + + Class.proto = function() { + var superclass = Class.superclass; + if (superclass) { superclass.proto(); } + + if (!wasApplied) { + wasApplied = true; + Class.PrototypeMixin.applyPartial(Class.prototype); + rewatch(Class.prototype); + } + + return this.prototype; + }; + + return Class; + + } + + /** + @class CoreObject + @namespace Ember + */ + var CoreObject = makeCtor(); + CoreObject.toString = function() { return "Ember.CoreObject"; }; + CoreObject.PrototypeMixin = Mixin.create({ + reopen: function() { + var length = arguments.length; + var args = new Array(length); + for (var i = 0; i < length; i++) { + args[i] = arguments[i]; + } + applyMixin(this, args, true); + return this; + }, + + /** + An overridable method called when objects are instantiated. By default, + does nothing unless it is overridden during class definition. + + Example: + + ```javascript + App.Person = Ember.Object.extend({ + init: function() { + alert('Name is ' + this.get('name')); + } + }); + + var steve = App.Person.create({ + name: "Steve" + }); + + // alerts 'Name is Steve'. + ``` + + NOTE: If you do override `init` for a framework class like `Ember.View` or + `Ember.ArrayController`, be sure to call `this._super()` in your + `init` declaration! If you don't, Ember may not have an opportunity to + do important setup work, and you'll see strange behavior in your + application. + + @method init + */ + init: function() {}, + + /** + Defines the properties that will be concatenated from the superclass + (instead of overridden). + + By default, when you extend an Ember class a property defined in + the subclass overrides a property with the same name that is defined + in the superclass. However, there are some cases where it is preferable + to build up a property's value by combining the superclass' property + value with the subclass' value. An example of this in use within Ember + is the `classNames` property of `Ember.View`. + + Here is some sample code showing the difference between a concatenated + property and a normal one: + + ```javascript + App.BarView = Ember.View.extend({ + someNonConcatenatedProperty: ['bar'], + classNames: ['bar'] + }); + + App.FooBarView = App.BarView.extend({ + someNonConcatenatedProperty: ['foo'], + classNames: ['foo'] + }); + + var fooBarView = App.FooBarView.create(); + fooBarView.get('someNonConcatenatedProperty'); // ['foo'] + fooBarView.get('classNames'); // ['ember-view', 'bar', 'foo'] + ``` + + This behavior extends to object creation as well. Continuing the + above example: + + ```javascript + var view = App.FooBarView.create({ + someNonConcatenatedProperty: ['baz'], + classNames: ['baz'] + }) + view.get('someNonConcatenatedProperty'); // ['baz'] + view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] + ``` + Adding a single property that is not an array will just add it in the array: + + ```javascript + var view = App.FooBarView.create({ + classNames: 'baz' + }) + view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] + ``` + + Using the `concatenatedProperties` property, we can tell to Ember that mix + the content of the properties. + + In `Ember.View` the `classNameBindings` and `attributeBindings` properties + are also concatenated, in addition to `classNames`. + + This feature is available for you to use throughout the Ember object model, + although typical app developers are likely to use it infrequently. Since + it changes expectations about behavior of properties, you should properly + document its usage in each individual concatenated property (to not + mislead your users to think they can override the property in a subclass). + + @property concatenatedProperties + @type Array + @default null + */ + concatenatedProperties: null, + + /** + Destroyed object property flag. + + if this property is `true` the observers and bindings were already + removed by the effect of calling the `destroy()` method. + + @property isDestroyed + @default false + */ + isDestroyed: false, + + /** + Destruction scheduled flag. The `destroy()` method has been called. + + The object stays intact until the end of the run loop at which point + the `isDestroyed` flag is set. + + @property isDestroying + @default false + */ + isDestroying: false, + + /** + Destroys an object by setting the `isDestroyed` flag and removing its + metadata, which effectively destroys observers and bindings. + + If you try to set a property on a destroyed object, an exception will be + raised. + + Note that destruction is scheduled for the end of the run loop and does not + happen immediately. It will set an isDestroying flag immediately. + + @method destroy + @return {Ember.Object} receiver + */ + destroy: function() { + if (this.isDestroying) { return; } + this.isDestroying = true; + + schedule('actions', this, this.willDestroy); + schedule('destroy', this, this._scheduledDestroy); + return this; + }, + + /** + Override to implement teardown. + + @method willDestroy + */ + willDestroy: K, + + /** + Invoked by the run loop to actually destroy the object. This is + scheduled for execution by the `destroy` method. + + @private + @method _scheduledDestroy + */ + _scheduledDestroy: function() { + if (this.isDestroyed) { return; } + destroy(this); + this.isDestroyed = true; + }, + + bind: function(to, from) { + if (!(from instanceof Binding)) { from = Binding.from(from); } + from.to(to).connect(this); + return from; + }, + + /** + Returns a string representation which attempts to provide more information + than Javascript's `toString` typically does, in a generic way for all Ember + objects. + + ```javascript + App.Person = Em.Object.extend() + person = App.Person.create() + person.toString() //=> "" + ``` + + If the object's class is not defined on an Ember namespace, it will + indicate it is a subclass of the registered superclass: + + ```javascript + Student = App.Person.extend() + student = Student.create() + student.toString() //=> "<(subclass of App.Person):ember1025>" + ``` + + If the method `toStringExtension` is defined, its return value will be + included in the output. + + ```javascript + App.Teacher = App.Person.extend({ + toStringExtension: function() { + return this.get('fullName'); + } + }); + teacher = App.Teacher.create() + teacher.toString(); //=> "" + ``` + + @method toString + @return {String} string representation + */ + toString: function toString() { + var hasToStringExtension = typeof this.toStringExtension === 'function'; + var extension = hasToStringExtension ? ":" + this.toStringExtension() : ''; + var ret = '<'+this.constructor.toString()+':'+guidFor(this)+extension+'>'; + + this.toString = makeToString(ret); + return ret; + } + }); + + CoreObject.PrototypeMixin.ownerConstructor = CoreObject; + + function makeToString(ret) { + return function() { return ret; }; + } + + if (Ember.config.overridePrototypeMixin) { + Ember.config.overridePrototypeMixin(CoreObject.PrototypeMixin); + } + + CoreObject.__super__ = null; + + var ClassMixin = Mixin.create({ + + ClassMixin: required(), + + PrototypeMixin: required(), + + isClass: true, + + isMethod: false, + + /** + Creates a new subclass. + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + alert(thing); + } + }); + ``` + + This defines a new subclass of Ember.Object: `App.Person`. It contains one method: `say()`. + + You can also create a subclass from any existing class by calling its `extend()` method. For example, you might want to create a subclass of Ember's built-in `Ember.View` class: + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li', + classNameBindings: ['isAdministrator'] + }); + ``` + + When defining a subclass, you can override methods but still access the implementation of your parent class by calling the special `_super()` method: + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + var name = this.get('name'); + alert(name + ' says: ' + thing); + } + }); + + App.Soldier = App.Person.extend({ + say: function(thing) { + this._super(thing + ", sir!"); + }, + march: function(numberOfHours) { + alert(this.get('name') + ' marches for ' + numberOfHours + ' hours.') + } + }); + + var yehuda = App.Soldier.create({ + name: "Yehuda Katz" + }); + + yehuda.say("Yes"); // alerts "Yehuda Katz says: Yes, sir!" + ``` + + The `create()` on line #17 creates an *instance* of the `App.Soldier` class. The `extend()` on line #8 creates a *subclass* of `App.Person`. Any instance of the `App.Person` class will *not* have the `march()` method. + + You can also pass `Mixin` classes to add additional properties to the subclass. + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + alert(this.get('name') + ' says: ' + thing); + } + }); + + App.SingingMixin = Mixin.create({ + sing: function(thing){ + alert(this.get('name') + ' sings: la la la ' + thing); + } + }); + + App.BroadwayStar = App.Person.extend(App.SingingMixin, { + dance: function() { + alert(this.get('name') + ' dances: tap tap tap tap '); + } + }); + ``` + + The `App.BroadwayStar` class contains three methods: `say()`, `sing()`, and `dance()`. + + @method extend + @static + + @param {Mixin} [mixins]* One or more Mixin classes + @param {Object} [arguments]* Object containing values to use within the new class + */ + extend: function extend() { + var Class = makeCtor(); + var proto; + Class.ClassMixin = Mixin.create(this.ClassMixin); + Class.PrototypeMixin = Mixin.create(this.PrototypeMixin); + + Class.ClassMixin.ownerConstructor = Class; + Class.PrototypeMixin.ownerConstructor = Class; + + reopen.apply(Class.PrototypeMixin, arguments); + + Class.superclass = this; + Class.__super__ = this.prototype; + + proto = Class.prototype = o_create(this.prototype); + proto.constructor = Class; + generateGuid(proto); + meta(proto).proto = proto; // this will disable observers on prototype + + Class.ClassMixin.apply(Class); + return Class; + }, + + /** + Equivalent to doing `extend(arguments).create()`. + If possible use the normal `create` method instead. + + @method createWithMixins + @static + @param [arguments]* + */ + createWithMixins: function() { + var C = this; + var l= arguments.length; + if (l > 0) { + var args = new Array(l); + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + this._initMixins(args); + } + return new C(); + }, + + /** + Creates an instance of a class. Accepts either no arguments, or an object + containing values to initialize the newly instantiated object with. + + ```javascript + App.Person = Ember.Object.extend({ + helloWorld: function() { + alert("Hi, my name is " + this.get('name')); + } + }); + + var tom = App.Person.create({ + name: 'Tom Dale' + }); + + tom.helloWorld(); // alerts "Hi, my name is Tom Dale". + ``` + + `create` will call the `init` function if defined during + `Ember.AnyObject.extend` + + If no arguments are passed to `create`, it will not set values to the new + instance during initialization: + + ```javascript + var noName = App.Person.create(); + noName.helloWorld(); // alerts undefined + ``` + + NOTE: For performance reasons, you cannot declare methods or computed + properties during `create`. You should instead declare methods and computed + properties when using `extend` or use the `createWithMixins` shorthand. + + @method create + @static + @param [arguments]* + */ + create: function() { + var C = this; + var l = arguments.length; + if (l > 0) { + var args = new Array(l); + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + this._initProperties(args); + } + return new C(); + }, + + /** + Augments a constructor's prototype with additional + properties and functions: + + ```javascript + MyObject = Ember.Object.extend({ + name: 'an object' + }); + + o = MyObject.create(); + o.get('name'); // 'an object' + + MyObject.reopen({ + say: function(msg){ + console.log(msg); + } + }) + + o2 = MyObject.create(); + o2.say("hello"); // logs "hello" + + o.say("goodbye"); // logs "goodbye" + ``` + + To add functions and properties to the constructor itself, + see `reopenClass` + + @method reopen + */ + reopen: function() { + this.willReopen(); + + var l = arguments.length; + var args = new Array(l); + if (l > 0) { + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + } + + apply(this.PrototypeMixin, reopen, args); + return this; + }, + + /** + Augments a constructor's own properties and functions: + + ```javascript + MyObject = Ember.Object.extend({ + name: 'an object' + }); + + MyObject.reopenClass({ + canBuild: false + }); + + MyObject.canBuild; // false + o = MyObject.create(); + ``` + + In other words, this creates static properties and functions for the class. These are only available on the class + and not on any instance of that class. + + ```javascript + App.Person = Ember.Object.extend({ + name : "", + sayHello : function(){ + alert("Hello. My name is " + this.get('name')); + } + }); + + App.Person.reopenClass({ + species : "Homo sapiens", + createPerson: function(newPersonsName){ + return App.Person.create({ + name:newPersonsName + }); + } + }); + + var tom = App.Person.create({ + name : "Tom Dale" + }); + var yehuda = App.Person.createPerson("Yehuda Katz"); + + tom.sayHello(); // "Hello. My name is Tom Dale" + yehuda.sayHello(); // "Hello. My name is Yehuda Katz" + alert(App.Person.species); // "Homo sapiens" + ``` + + Note that `species` and `createPerson` are *not* valid on the `tom` and `yehuda` + variables. They are only valid on `App.Person`. + + To add functions and properties to instances of + a constructor by extending the constructor's prototype + see `reopen` + + @method reopenClass + */ + reopenClass: function() { + var l = arguments.length; + var args = new Array(l); + if (l > 0) { + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + } + + apply(this.ClassMixin, reopen, args); + applyMixin(this, arguments, false); + return this; + }, + + detect: function(obj) { + if ('function' !== typeof obj) { return false; } + while(obj) { + if (obj===this) { return true; } + obj = obj.superclass; + } + return false; + }, + + detectInstance: function(obj) { + return obj instanceof this; + }, + + /** + In some cases, you may want to annotate computed properties with additional + metadata about how they function or what values they operate on. For + example, computed property functions may close over variables that are then + no longer available for introspection. + + You can pass a hash of these values to a computed property like this: + + ```javascript + person: function() { + var personId = this.get('personId'); + return App.Person.create({ id: personId }); + }.property().meta({ type: App.Person }) + ``` + + Once you've done this, you can retrieve the values saved to the computed + property from your class like this: + + ```javascript + MyClass.metaForProperty('person'); + ``` + + This will return the original hash that was passed to `meta()`. + + @method metaForProperty + @param key {String} property name + */ + metaForProperty: function(key) { + var meta = this.proto()['__ember_meta__']; + var desc = meta && meta.descs[key]; + + Ember.assert("metaForProperty() could not find a computed property with key '"+key+"'.", !!desc && desc instanceof ComputedProperty); + return desc._meta || {}; + }, + + _computedProperties: Ember.computed(function() { + hasCachedComputedProperties = true; + var proto = this.proto(); + var descs = meta(proto).descs; + var property; + var properties = []; + + for (var name in descs) { + property = descs[name]; + + if (property instanceof ComputedProperty) { + properties.push({ + name: name, + meta: property._meta + }); + } + } + return properties; + }).readOnly(), + + /** + Iterate over each computed property for the class, passing its name + and any associated metadata (see `metaForProperty`) to the callback. + + @method eachComputedProperty + @param {Function} callback + @param {Object} binding + */ + eachComputedProperty: function(callback, binding) { + var property, name; + var empty = {}; + + var properties = get(this, '_computedProperties'); + + for (var i = 0, length = properties.length; i < length; i++) { + property = properties[i]; + name = property.name; + callback.call(binding || this, property.name, property.meta || empty); + } + } + }); + + ClassMixin.ownerConstructor = CoreObject; + + if (Ember.config.overrideClassMixin) { + Ember.config.overrideClassMixin(ClassMixin); + } + + CoreObject.ClassMixin = ClassMixin; + + ClassMixin.apply(CoreObject); + + CoreObject.reopen({ + didDefineProperty: function(proto, key, value) { + if (hasCachedComputedProperties === false) { return; } + if (value instanceof Ember.ComputedProperty) { + var cache = Ember.meta(this.constructor).cache; + + if (cache._computedProperties !== undefined) { + cache._computedProperties = undefined; + } + } + } + }); + + __exports__["default"] = CoreObject; + }); +define("ember-runtime/system/deferred", + ["ember-metal/core","ember-runtime/mixins/deferred","ember-metal/property_get","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var DeferredMixin = __dependency2__["default"]; + var get = __dependency3__.get; + var EmberObject = __dependency4__["default"]; + + var Deferred = EmberObject.extend(DeferredMixin, { + init: function() { + Ember.deprecate('Usage of Ember.Deferred is deprecated.'); + this._super(); + } + }); + + Deferred.reopenClass({ + promise: function(callback, binding) { + var deferred = Deferred.create(); + callback.call(binding, deferred); + return deferred; + } + }); + + __exports__["default"] = Deferred; + }); +define("ember-runtime/system/each_proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/enumerable_utils","ember-metal/array","ember-runtime/mixins/array","ember-runtime/system/object","ember-metal/computed","ember-metal/observer","ember-metal/events","ember-metal/properties","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var forEach = __dependency5__.forEach; + var indexOf = __dependency6__.indexOf; + var EmberArray = __dependency7__["default"]; + // ES6TODO: WAT? Circular dep? + var EmberObject = __dependency8__["default"]; + var computed = __dependency9__.computed; + var addObserver = __dependency10__.addObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeBeforeObserver = __dependency10__.removeBeforeObserver; + var removeObserver = __dependency10__.removeObserver; + var typeOf = __dependency4__.typeOf; + var watchedEvents = __dependency11__.watchedEvents; + var defineProperty = __dependency12__.defineProperty; + var beginPropertyChanges = __dependency13__.beginPropertyChanges; + var propertyDidChange = __dependency13__.propertyDidChange; + var propertyWillChange = __dependency13__.propertyWillChange; + var endPropertyChanges = __dependency13__.endPropertyChanges; + var changeProperties = __dependency13__.changeProperties; + + var EachArray = EmberObject.extend(EmberArray, { + + init: function(content, keyName, owner) { + this._super(); + this._keyName = keyName; + this._owner = owner; + this._content = content; + }, + + objectAt: function(idx) { + var item = this._content.objectAt(idx); + return item && get(item, this._keyName); + }, + + length: computed(function() { + var content = this._content; + return content ? get(content, 'length') : 0; + }) + + }); + + var IS_OBSERVER = /^.+:(before|change)$/; + + function addObserverForContentKey(content, keyName, proxy, idx, loc) { + var objects = proxy._objects; + var guid; + if (!objects) objects = proxy._objects = {}; + + while(--loc>=idx) { + var item = content.objectAt(loc); + if (item) { + Ember.assert('When using @each to observe the array ' + content + ', the array must return an object', typeOf(item) === 'instance' || typeOf(item) === 'object'); + addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + addObserver(item, keyName, proxy, 'contentKeyDidChange'); + + // keep track of the index each item was found at so we can map + // it back when the obj changes. + guid = guidFor(item); + if (!objects[guid]) objects[guid] = []; + objects[guid].push(loc); + } + } + } + + function removeObserverForContentKey(content, keyName, proxy, idx, loc) { + var objects = proxy._objects; + if (!objects) objects = proxy._objects = {}; + var indicies, guid; + + while(--loc>=idx) { + var item = content.objectAt(loc); + if (item) { + removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + removeObserver(item, keyName, proxy, 'contentKeyDidChange'); + + guid = guidFor(item); + indicies = objects[guid]; + indicies[indexOf.call(indicies, loc)] = null; + } + } + } + + /** + This is the object instance returned when you get the `@each` property on an + array. It uses the unknownProperty handler to automatically create + EachArray instances for property names. + + @private + @class EachProxy + @namespace Ember + @extends Ember.Object + */ + var EachProxy = EmberObject.extend({ + + init: function(content) { + this._super(); + this._content = content; + content.addArrayObserver(this); + + // in case someone is already observing some keys make sure they are + // added + forEach(watchedEvents(this), function(eventName) { + this.didAddListener(eventName); + }, this); + }, + + /** + You can directly access mapped properties by simply requesting them. + The `unknownProperty` handler will generate an EachArray of each item. + + @method unknownProperty + @param keyName {String} + @param value {*} + */ + unknownProperty: function(keyName, value) { + var ret; + ret = new EachArray(this._content, keyName, this); + defineProperty(this, keyName, null, ret); + this.beginObservingContentKey(keyName); + return ret; + }, + + // .......................................................... + // ARRAY CHANGES + // Invokes whenever the content array itself changes. + + arrayWillChange: function(content, idx, removedCnt, addedCnt) { + var keys = this._keys; + var key, lim; + + lim = removedCnt>0 ? idx+removedCnt : -1; + beginPropertyChanges(this); + + for(key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } + + if (lim>0) { removeObserverForContentKey(content, key, this, idx, lim); } + + propertyWillChange(this, key); + } + + propertyWillChange(this._content, '@each'); + endPropertyChanges(this); + }, + + arrayDidChange: function(content, idx, removedCnt, addedCnt) { + var keys = this._keys; + var lim; + + lim = addedCnt>0 ? idx+addedCnt : -1; + changeProperties(function() { + for(var key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } + + if (lim>0) { addObserverForContentKey(content, key, this, idx, lim); } + + propertyDidChange(this, key); + } + + propertyDidChange(this._content, '@each'); + }, this); + }, + + // .......................................................... + // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS + // Start monitoring keys based on who is listening... + + didAddListener: function(eventName) { + if (IS_OBSERVER.test(eventName)) { + this.beginObservingContentKey(eventName.slice(0, -7)); + } + }, + + didRemoveListener: function(eventName) { + if (IS_OBSERVER.test(eventName)) { + this.stopObservingContentKey(eventName.slice(0, -7)); + } + }, + + // .......................................................... + // CONTENT KEY OBSERVING + // Actual watch keys on the source content. + + beginObservingContentKey: function(keyName) { + var keys = this._keys; + if (!keys) keys = this._keys = {}; + if (!keys[keyName]) { + keys[keyName] = 1; + var content = this._content; + var len = get(content, 'length'); + + addObserverForContentKey(content, keyName, this, 0, len); + } else { + keys[keyName]++; + } + }, + + stopObservingContentKey: function(keyName) { + var keys = this._keys; + if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) { + var content = this._content; + var len = get(content, 'length'); + + removeObserverForContentKey(content, keyName, this, 0, len); + } + }, + + contentKeyWillChange: function(obj, keyName) { + propertyWillChange(this, keyName); + }, + + contentKeyDidChange: function(obj, keyName) { + propertyDidChange(this, keyName); + } + }); + + __exports__.EachArray = EachArray; + __exports__.EachProxy = EachProxy; + }); +define("ember-runtime/system/lazy_load", + ["ember-metal/core","ember-metal/array","ember-runtime/system/native_array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /*globals CustomEvent */ + + var Ember = __dependency1__["default"]; + // Ember.ENV.EMBER_LOAD_HOOKS + var forEach = __dependency2__.forEach; + // make sure Ember.A is setup. + + /** + @module ember + @submodule ember-runtime + */ + + var loadHooks = Ember.ENV.EMBER_LOAD_HOOKS || {}; + var loaded = {}; + + /** + Detects when a specific package of Ember (e.g. 'Ember.Handlebars') + has fully loaded and is available for extension. + + The provided `callback` will be called with the `name` passed + resolved from a string into the object: + + ``` javascript + Ember.onLoad('Ember.Handlebars' function(hbars) { + hbars.registerHelper(...); + }); + ``` + + @method onLoad + @for Ember + @param name {String} name of hook + @param callback {Function} callback to be called + */ + function onLoad(name, callback) { + var object; + + loadHooks[name] = loadHooks[name] || Ember.A(); + loadHooks[name].pushObject(callback); + + if (object = loaded[name]) { + callback(object); + } + } + + __exports__.onLoad = onLoad;/** + Called when an Ember.js package (e.g Ember.Handlebars) has finished + loading. Triggers any callbacks registered for this event. + + @method runLoadHooks + @for Ember + @param name {String} name of hook + @param object {Object} object to pass to callbacks + */ + function runLoadHooks(name, object) { + loaded[name] = object; + + if (typeof window === 'object' && typeof window.dispatchEvent === 'function' && typeof CustomEvent === "function") { + var event = new CustomEvent(name, {detail: object, name: name}); + window.dispatchEvent(event); + } + + if (loadHooks[name]) { + forEach.call(loadHooks[name], function(callback) { + callback(object); + }); + } + } + + __exports__.runLoadHooks = runLoadHooks; + }); +define("ember-runtime/system/namespace", + ["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/mixin","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // Ember.lookup, Ember.BOOTED, Ember.deprecate, Ember.NAME_KEY, Ember.anyUnprocessedMixins + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var indexOf = __dependency3__.indexOf; + var GUID_KEY = __dependency4__.GUID_KEY; + var guidFor = __dependency4__.guidFor; + var Mixin = __dependency5__.Mixin; + + var EmberObject = __dependency6__["default"]; + + /** + A Namespace is an object usually used to contain other objects or methods + such as an application or framework. Create a namespace anytime you want + to define one of these new containers. + + # Example Usage + + ```javascript + MyFramework = Ember.Namespace.create({ + VERSION: '1.0.0' + }); + ``` + + @class Namespace + @namespace Ember + @extends Ember.Object + */ + var Namespace = EmberObject.extend({ + isNamespace: true, + + init: function() { + Namespace.NAMESPACES.push(this); + Namespace.PROCESSED = false; + }, + + toString: function() { + var name = get(this, 'name'); + if (name) { return name; } + + findNamespaces(); + return this[NAME_KEY]; + }, + + nameClasses: function() { + processNamespace([this.toString()], this, {}); + }, + + destroy: function() { + var namespaces = Namespace.NAMESPACES; + var toString = this.toString(); + + if (toString) { + Ember.lookup[toString] = undefined; + delete Namespace.NAMESPACES_BY_ID[toString]; + } + namespaces.splice(indexOf.call(namespaces, this), 1); + this._super(); + } + }); + + Namespace.reopenClass({ + NAMESPACES: [Ember], + NAMESPACES_BY_ID: {}, + PROCESSED: false, + processAll: processAllNamespaces, + byName: function(name) { + if (!Ember.BOOTED) { + processAllNamespaces(); + } + + return NAMESPACES_BY_ID[name]; + } + }); + + var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID; + + var hasOwnProp = ({}).hasOwnProperty; + + function processNamespace(paths, root, seen) { + var idx = paths.length; + + NAMESPACES_BY_ID[paths.join('.')] = root; + + // Loop over all of the keys in the namespace, looking for classes + for(var key in root) { + if (!hasOwnProp.call(root, key)) { continue; } + var obj = root[key]; + + // If we are processing the `Ember` namespace, for example, the + // `paths` will start with `["Ember"]`. Every iteration through + // the loop will update the **second** element of this list with + // the key, so processing `Ember.View` will make the Array + // `['Ember', 'View']`. + paths[idx] = key; + + // If we have found an unprocessed class + if (obj && obj.toString === classToString) { + // Replace the class' `toString` with the dot-separated path + // and set its `NAME_KEY` + obj.toString = makeToString(paths.join('.')); + obj[NAME_KEY] = paths.join('.'); + + // Support nested namespaces + } else if (obj && obj.isNamespace) { + // Skip aliased namespaces + if (seen[guidFor(obj)]) { continue; } + seen[guidFor(obj)] = true; + + // Process the child namespace + processNamespace(paths, obj, seen); + } + } + + paths.length = idx; // cut out last item + } + + var STARTS_WITH_UPPERCASE = /^[A-Z]/; + + function tryIsNamespace(lookup, prop) { + try { + var obj = lookup[prop]; + return obj && obj.isNamespace && obj; + } catch (e) { + // continue + } + } + + function findNamespaces() { + var lookup = Ember.lookup; + var obj, isNamespace; + + if (Namespace.PROCESSED) { return; } + + for (var prop in lookup) { + // Only process entities that start with uppercase A-Z + if (!STARTS_WITH_UPPERCASE.test(prop)) { continue; } + + // Unfortunately, some versions of IE don't support window.hasOwnProperty + if (lookup.hasOwnProperty && !lookup.hasOwnProperty(prop)) { continue; } + + // At times we are not allowed to access certain properties for security reasons. + // There are also times where even if we can access them, we are not allowed to access their properties. + obj = tryIsNamespace(lookup, prop); + if (obj) { + obj[NAME_KEY] = prop; + } + } + } + + var NAME_KEY = Ember.NAME_KEY = GUID_KEY + '_name'; + + function superClassString(mixin) { + var superclass = mixin.superclass; + if (superclass) { + if (superclass[NAME_KEY]) { return superclass[NAME_KEY]; } + else { return superClassString(superclass); } + } else { + return; + } + } + + function classToString() { + if (!Ember.BOOTED && !this[NAME_KEY]) { + processAllNamespaces(); + } + + var ret; + + if (this[NAME_KEY]) { + ret = this[NAME_KEY]; + } else if (this._toString) { + ret = this._toString; + } else { + var str = superClassString(this); + if (str) { + ret = "(subclass of " + str + ")"; + } else { + ret = "(unknown mixin)"; + } + this.toString = makeToString(ret); + } + + return ret; + } + + function processAllNamespaces() { + var unprocessedNamespaces = !Namespace.PROCESSED; + var unprocessedMixins = Ember.anyUnprocessedMixins; + + if (unprocessedNamespaces) { + findNamespaces(); + Namespace.PROCESSED = true; + } + + if (unprocessedNamespaces || unprocessedMixins) { + var namespaces = Namespace.NAMESPACES; + var namespace; + + for (var i=0, l=namespaces.length; i 0) { + NativeArray = NativeArray.without.apply(NativeArray, ignore); + } + + /** + Creates an `Ember.NativeArray` from an Array like object. + Does not modify the original object. Ember.A is not needed if + `Ember.EXTEND_PROTOTYPES` is `true` (the default value). However, + it is recommended that you use Ember.A when creating addons for + ember or when you can not guarantee that `Ember.EXTEND_PROTOTYPES` + will be `true`. + + Example + + ```js + var Pagination = Ember.CollectionView.extend({ + tagName: 'ul', + classNames: ['pagination'], + + init: function() { + this._super(); + if (!this.get('content')) { + this.set('content', Ember.A()); + } + } + }); + ``` + + @method A + @for Ember + @return {Ember.NativeArray} + */ + var A = function(arr) { + if (arr === undefined) { arr = []; } + return EmberArray.detect(arr) ? arr : NativeArray.apply(arr); + }; + + /** + Activates the mixin on the Array.prototype if not already applied. Calling + this method more than once is safe. This will be called when ember is loaded + unless you have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` + set to `false`. + + Example + + ```js + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { + Ember.NativeArray.activate(); + } + ``` + + @method activate + @for Ember.NativeArray + @static + @return {void} + */ + NativeArray.activate = function() { + NativeArray.apply(Array.prototype); + + A = function(arr) { return arr || []; }; + }; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { + NativeArray.activate(); + } + + Ember.A = A; // ES6TODO: Setting A onto the object returned by ember-metal/core to avoid circles + __exports__.A = A; + __exports__.NativeArray = NativeArray; + __exports__["default"] = NativeArray; + }); +define("ember-runtime/system/object", + ["ember-runtime/system/core_object","ember-runtime/mixins/observable","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var CoreObject = __dependency1__["default"]; + var Observable = __dependency2__["default"]; + + /** + `Ember.Object` is the main base class for all Ember objects. It is a subclass + of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details, + see the documentation for each of these. + + @class Object + @namespace Ember + @extends Ember.CoreObject + @uses Ember.Observable + */ + var EmberObject = CoreObject.extend(Observable); + EmberObject.toString = function() { + return "Ember.Object"; + }; + + __exports__["default"] = EmberObject; + }); +define("ember-runtime/system/object_proxy", + ["ember-runtime/system/object","ember-runtime/mixins/-proxy","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + var _ProxyMixin = __dependency2__["default"]; + + /** + `Ember.ObjectProxy` forwards all properties not defined by the proxy itself + to a proxied `content` object. + + ```javascript + object = Ember.Object.create({ + name: 'Foo' + }); + + proxy = Ember.ObjectProxy.create({ + content: object + }); + + // Access and change existing properties + proxy.get('name') // 'Foo' + proxy.set('name', 'Bar'); + object.get('name') // 'Bar' + + // Create new 'description' property on `object` + proxy.set('description', 'Foo is a whizboo baz'); + object.get('description') // 'Foo is a whizboo baz' + ``` + + While `content` is unset, setting a property to be delegated will throw an + Error. + + ```javascript + proxy = Ember.ObjectProxy.create({ + content: null, + flag: null + }); + proxy.set('flag', true); + proxy.get('flag'); // true + proxy.get('foo'); // undefined + proxy.set('foo', 'data'); // throws Error + ``` + + Delegated properties can be bound to and will change when content is updated. + + Computed properties on the proxy itself can depend on delegated properties. + + ```javascript + ProxyWithComputedProperty = Ember.ObjectProxy.extend({ + fullName: function () { + var firstName = this.get('firstName'), + lastName = this.get('lastName'); + if (firstName && lastName) { + return firstName + ' ' + lastName; + } + return firstName || lastName; + }.property('firstName', 'lastName') + }); + + proxy = ProxyWithComputedProperty.create(); + + proxy.get('fullName'); // undefined + proxy.set('content', { + firstName: 'Tom', lastName: 'Dale' + }); // triggers property change for fullName on proxy + + proxy.get('fullName'); // 'Tom Dale' + ``` + + @class ObjectProxy + @namespace Ember + @extends Ember.Object + @extends Ember._ProxyMixin + */ + + __exports__["default"] = EmberObject.extend(_ProxyMixin); + }); +define("ember-runtime/system/set", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/is_none","ember-runtime/system/string","ember-runtime/system/core_object","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","ember-runtime/mixins/copyable","ember-runtime/mixins/freezable","ember-metal/error","ember-metal/property_events","ember-metal/mixin","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.isNone, Ember.A + + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var isNone = __dependency5__.isNone; + var fmt = __dependency6__.fmt; + var CoreObject = __dependency7__["default"]; + var MutableEnumerable = __dependency8__["default"]; + var Enumerable = __dependency9__["default"]; + var Copyable = __dependency10__["default"]; + var Freezable = __dependency11__.Freezable; + var FROZEN_ERROR = __dependency11__.FROZEN_ERROR; + var EmberError = __dependency12__["default"]; + var propertyWillChange = __dependency13__.propertyWillChange; + var propertyDidChange = __dependency13__.propertyDidChange; + var aliasMethod = __dependency14__.aliasMethod; + var computed = __dependency15__.computed; + + /** + An unordered collection of objects. + + A Set works a bit like an array except that its items are not ordered. You + can create a set to efficiently test for membership for an object. You can + also iterate through a set just like an array, even accessing objects by + index, however there is no guarantee as to their order. + + All Sets are observable via the Enumerable Observer API - which works + on any enumerable object including both Sets and Arrays. + + ## Creating a Set + + You can create a set like you would most objects using + `new Ember.Set()`. Most new sets you create will be empty, but you can + also initialize the set with some content by passing an array or other + enumerable of objects to the constructor. + + Finally, you can pass in an existing set and the set will be copied. You + can also create a copy of a set by calling `Ember.Set#copy()`. + + ```javascript + // creates a new empty set + var foundNames = new Ember.Set(); + + // creates a set with four names in it. + var names = new Ember.Set(["Charles", "Tom", "Juan", "Alex"]); // :P + + // creates a copy of the names set. + var namesCopy = new Ember.Set(names); + + // same as above. + var anotherNamesCopy = names.copy(); + ``` + + ## Adding/Removing Objects + + You generally add or remove objects from a set using `add()` or + `remove()`. You can add any type of object including primitives such as + numbers, strings, and booleans. + + Unlike arrays, objects can only exist one time in a set. If you call `add()` + on a set with the same object multiple times, the object will only be added + once. Likewise, calling `remove()` with the same object multiple times will + remove the object the first time and have no effect on future calls until + you add the object to the set again. + + NOTE: You cannot add/remove `null` or `undefined` to a set. Any attempt to do + so will be ignored. + + In addition to add/remove you can also call `push()`/`pop()`. Push behaves + just like `add()` but `pop()`, unlike `remove()` will pick an arbitrary + object, remove it and return it. This is a good way to use a set as a job + queue when you don't care which order the jobs are executed in. + + ## Testing for an Object + + To test for an object's presence in a set you simply call + `Ember.Set#contains()`. + + ## Observing changes + + When using `Ember.Set`, you can observe the `"[]"` property to be + alerted whenever the content changes. You can also add an enumerable + observer to the set to be notified of specific objects that are added and + removed from the set. See [Ember.Enumerable](/api/classes/Ember.Enumerable.html) + for more information on enumerables. + + This is often unhelpful. If you are filtering sets of objects, for instance, + it is very inefficient to re-filter all of the items each time the set + changes. It would be better if you could just adjust the filtered set based + on what was changed on the original set. The same issue applies to merging + sets, as well. + + ## Other Methods + + `Ember.Set` primary implements other mixin APIs. For a complete reference + on the methods you will use with `Ember.Set`, please consult these mixins. + The most useful ones will be `Ember.Enumerable` and + `Ember.MutableEnumerable` which implement most of the common iterator + methods you are used to on Array. + + Note that you can also use the `Ember.Copyable` and `Ember.Freezable` + APIs on `Ember.Set` as well. Once a set is frozen it can no longer be + modified. The benefit of this is that when you call `frozenCopy()` on it, + Ember will avoid making copies of the set. This allows you to write + code that can know with certainty when the underlying set data will or + will not be modified. + + @class Set + @namespace Ember + @extends Ember.CoreObject + @uses Ember.MutableEnumerable + @uses Ember.Copyable + @uses Ember.Freezable + @since Ember 0.9 + */ + __exports__["default"] = CoreObject.extend(MutableEnumerable, Copyable, Freezable, { + + // .......................................................... + // IMPLEMENT ENUMERABLE APIS + // + + /** + This property will change as the number of objects in the set changes. + + @property length + @type number + @default 0 + */ + length: 0, + + /** + Clears the set. This is useful if you want to reuse an existing set + without having to recreate it. + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.length; // 3 + colors.clear(); + colors.length; // 0 + ``` + + @method clear + @return {Ember.Set} An empty Set + */ + clear: function() { + if (this.isFrozen) { throw new EmberError(FROZEN_ERROR); } + + var len = get(this, 'length'); + if (len === 0) { return this; } + + var guid; + + this.enumerableContentWillChange(len, 0); + propertyWillChange(this, 'firstObject'); + propertyWillChange(this, 'lastObject'); + + for (var i=0; i < len; i++) { + guid = guidFor(this[i]); + delete this[guid]; + delete this[i]; + } + + set(this, 'length', 0); + + propertyDidChange(this, 'firstObject'); + propertyDidChange(this, 'lastObject'); + this.enumerableContentDidChange(len, 0); + + return this; + }, + + /** + Returns true if the passed object is also an enumerable that contains the + same objects as the receiver. + + ```javascript + var colors = ["red", "green", "blue"], + same_colors = new Ember.Set(colors); + + same_colors.isEqual(colors); // true + same_colors.isEqual(["purple", "brown"]); // false + ``` + + @method isEqual + @param {Ember.Set} obj the other object. + @return {Boolean} + */ + isEqual: function(obj) { + // fail fast + if (!Enumerable.detect(obj)) return false; + + var loc = get(this, 'length'); + if (get(obj, 'length') !== loc) return false; + + while(--loc >= 0) { + if (!obj.contains(this[loc])) return false; + } + + return true; + }, + + /** + Adds an object to the set. Only non-`null` objects can be added to a set + and those can only be added once. If the object is already in the set or + the passed value is null this method will have no effect. + + This is an alias for `Ember.MutableEnumerable.addObject()`. + + ```javascript + var colors = new Ember.Set(); + colors.add("blue"); // ["blue"] + colors.add("blue"); // ["blue"] + colors.add("red"); // ["blue", "red"] + colors.add(null); // ["blue", "red"] + colors.add(undefined); // ["blue", "red"] + ``` + + @method add + @param {Object} obj The object to add. + @return {Ember.Set} The set itself. + */ + add: aliasMethod('addObject'), + + /** + Removes the object from the set if it is found. If you pass a `null` value + or an object that is already not in the set, this method will have no + effect. This is an alias for `Ember.MutableEnumerable.removeObject()`. + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.remove("red"); // ["blue", "green"] + colors.remove("purple"); // ["blue", "green"] + colors.remove(null); // ["blue", "green"] + ``` + + @method remove + @param {Object} obj The object to remove + @return {Ember.Set} The set itself. + */ + remove: aliasMethod('removeObject'), + + /** + Removes the last element from the set and returns it, or `null` if it's empty. + + ```javascript + var colors = new Ember.Set(["green", "blue"]); + colors.pop(); // "blue" + colors.pop(); // "green" + colors.pop(); // null + ``` + + @method pop + @return {Object} The removed object from the set or null. + */ + pop: function() { + if (get(this, 'isFrozen')) throw new EmberError(FROZEN_ERROR); + var obj = this.length > 0 ? this[this.length-1] : null; + this.remove(obj); + return obj; + }, + + /** + Inserts the given object on to the end of the set. It returns + the set itself. + + This is an alias for `Ember.MutableEnumerable.addObject()`. + + ```javascript + var colors = new Ember.Set(); + colors.push("red"); // ["red"] + colors.push("green"); // ["red", "green"] + colors.push("blue"); // ["red", "green", "blue"] + ``` + + @method push + @return {Ember.Set} The set itself. + */ + push: aliasMethod('addObject'), + + /** + Removes the last element from the set and returns it, or `null` if it's empty. + + This is an alias for `Ember.Set.pop()`. + + ```javascript + var colors = new Ember.Set(["green", "blue"]); + colors.shift(); // "blue" + colors.shift(); // "green" + colors.shift(); // null + ``` + + @method shift + @return {Object} The removed object from the set or null. + */ + shift: aliasMethod('pop'), + + /** + Inserts the given object on to the end of the set. It returns + the set itself. + + This is an alias of `Ember.Set.push()` + + ```javascript + var colors = new Ember.Set(); + colors.unshift("red"); // ["red"] + colors.unshift("green"); // ["red", "green"] + colors.unshift("blue"); // ["red", "green", "blue"] + ``` + + @method unshift + @return {Ember.Set} The set itself. + */ + unshift: aliasMethod('push'), + + /** + Adds each object in the passed enumerable to the set. + + This is an alias of `Ember.MutableEnumerable.addObjects()` + + ```javascript + var colors = new Ember.Set(); + colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"] + ``` + + @method addEach + @param {Ember.Enumerable} objects the objects to add. + @return {Ember.Set} The set itself. + */ + addEach: aliasMethod('addObjects'), + + /** + Removes each object in the passed enumerable to the set. + + This is an alias of `Ember.MutableEnumerable.removeObjects()` + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.removeEach(["red", "blue"]); // ["green"] + ``` + + @method removeEach + @param {Ember.Enumerable} objects the objects to remove. + @return {Ember.Set} The set itself. + */ + removeEach: aliasMethod('removeObjects'), + + // .......................................................... + // PRIVATE ENUMERABLE SUPPORT + // + + init: function(items) { + Ember.deprecate('Ember.Set is deprecated and will be removed in a future release.'); + this._super(); + if (items) this.addObjects(items); + }, + + // implement Ember.Enumerable + nextObject: function(idx) { + return this[idx]; + }, + + // more optimized version + firstObject: computed(function() { + return this.length > 0 ? this[0] : undefined; + }), + + // more optimized version + lastObject: computed(function() { + return this.length > 0 ? this[this.length-1] : undefined; + }), + + // implements Ember.MutableEnumerable + addObject: function(obj) { + if (get(this, 'isFrozen')) throw new EmberError(FROZEN_ERROR); + if (isNone(obj)) return this; // nothing to do + + var guid = guidFor(obj); + var idx = this[guid]; + var len = get(this, 'length'); + var added; + + if (idx>=0 && idx=0 && idx=0; + }, + + copy: function() { + var C = this.constructor, ret = new C(), loc = get(this, 'length'); + set(ret, 'length', loc); + while(--loc>=0) { + ret[loc] = this[loc]; + ret[guidFor(this[loc])] = loc; + } + return ret; + }, + + toString: function() { + var len = this.length, idx, array = []; + for(idx = 0; idx < len; idx++) { + array[idx] = this[idx]; + } + return fmt("Ember.Set<%@>", [array.join(',')]); + } + }); + }); +define("ember-runtime/system/string", + ["ember-metal/core","ember-metal/utils","ember-metal/cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.STRINGS, Ember.FEATURES + var isArray = __dependency2__.isArray; + var emberInspect = __dependency2__.inspect; + + var Cache = __dependency3__["default"]; + + var STRING_DASHERIZE_REGEXP = (/[ _]/g); + + var STRING_DASHERIZE_CACHE = new Cache(1000, function(key) { + return decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-'); + }); + + var CAMELIZE_CACHE = new Cache(1000, function(key) { + return key.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) { + return chr ? chr.toUpperCase() : ''; + }).replace(/^([A-Z])/, function(match, separator, chr) { + return match.toLowerCase(); + }); + }); + + var CLASSIFY_CACHE = new Cache(1000, function(str) { + var parts = str.split("."); + var out = []; + + for (var i=0, l=parts.length; i 2) { + cachedFormats = new Array(arguments.length - 1); + + for (var i = 1, l = arguments.length; i < l; i++) { + cachedFormats[i - 1] = arguments[i]; + } + } + + // first, replace any ORDERED replacements. + var idx = 0; // the current index for non-numerical replacements + return str.replace(/%@([0-9]+)?/g, function(s, argIndex) { + argIndex = (argIndex) ? parseInt(argIndex, 10) - 1 : idx++; + s = cachedFormats[argIndex]; + return (s === null) ? '(null)' : (s === undefined) ? '' : emberInspect(s); + }); + } + + function loc(str, formats) { + if (!isArray(formats) || arguments.length > 2) { + formats = Array.prototype.slice.call(arguments, 1); + } + + str = Ember.STRINGS[str] || str; + return fmt(str, formats); + } + + function w(str) { + return str.split(/\s+/); + } + + function decamelize(str) { + return DECAMELIZE_CACHE.get(str); + } + + function dasherize(str) { + return STRING_DASHERIZE_CACHE.get(str); + } + + function camelize(str) { + return CAMELIZE_CACHE.get(str); + } + + function classify(str) { + return CLASSIFY_CACHE.get(str); + } + + function underscore(str) { + return UNDERSCORE_CACHE.get(str); + } + + function capitalize(str) { + return CAPITALIZE_CACHE.get(str); + } + + /** + Defines the hash of localized strings for the current language. Used by + the `Ember.String.loc()` helper. To localize, add string values to this + hash. + + @property STRINGS + @for Ember + @type Hash + */ + Ember.STRINGS = {}; + + /** + Defines string helper methods including string formatting and localization. + Unless `Ember.EXTEND_PROTOTYPES.String` is `false` these methods will also be + added to the `String.prototype` as well. + + @class String + @namespace Ember + @static + */ + __exports__["default"] = { + /** + Apply formatting options to the string. This will look for occurrences + of "%@" in your string and substitute them with the arguments you pass into + this method. If you want to control the specific order of replacement, + you can add a number after the key as well to indicate which argument + you want to insert. + + Ordered insertions are most useful when building loc strings where values + you need to insert may appear in different orders. + + ```javascript + "Hello %@ %@".fmt('John', 'Doe'); // "Hello John Doe" + "Hello %@2, %@1".fmt('John', 'Doe'); // "Hello Doe, John" + ``` + + @method fmt + @param {String} str The string to format + @param {Array} formats An array of parameters to interpolate into string. + @return {String} formatted string + */ + fmt: fmt, + + /** + Formats the passed string, but first looks up the string in the localized + strings hash. This is a convenient way to localize text. See + `Ember.String.fmt()` for more information on formatting. + + Note that it is traditional but not required to prefix localized string + keys with an underscore or other character so you can easily identify + localized strings. + + ```javascript + Ember.STRINGS = { + '_Hello World': 'Bonjour le monde', + '_Hello %@ %@': 'Bonjour %@ %@' + }; + + Ember.String.loc("_Hello World"); // 'Bonjour le monde'; + Ember.String.loc("_Hello %@ %@", ["John", "Smith"]); // "Bonjour John Smith"; + ``` + + @method loc + @param {String} str The string to format + @param {Array} formats Optional array of parameters to interpolate into string. + @return {String} formatted string + */ + loc: loc, + + /** + Splits a string into separate units separated by spaces, eliminating any + empty strings in the process. This is a convenience method for split that + is mostly useful when applied to the `String.prototype`. + + ```javascript + Ember.String.w("alpha beta gamma").forEach(function(key) { + console.log(key); + }); + + // > alpha + // > beta + // > gamma + ``` + + @method w + @param {String} str The string to split + @return {Array} array containing the split strings + */ + w: w, + + /** + Converts a camelized string into all lower case separated by underscores. + + ```javascript + 'innerHTML'.decamelize(); // 'inner_html' + 'action_name'.decamelize(); // 'action_name' + 'css-class-name'.decamelize(); // 'css-class-name' + 'my favorite items'.decamelize(); // 'my favorite items' + ``` + + @method decamelize + @param {String} str The string to decamelize. + @return {String} the decamelized string. + */ + decamelize: decamelize, + + /** + Replaces underscores, spaces, or camelCase with dashes. + + ```javascript + 'innerHTML'.dasherize(); // 'inner-html' + 'action_name'.dasherize(); // 'action-name' + 'css-class-name'.dasherize(); // 'css-class-name' + 'my favorite items'.dasherize(); // 'my-favorite-items' + ``` + + @method dasherize + @param {String} str The string to dasherize. + @return {String} the dasherized string. + */ + dasherize: dasherize, + + /** + Returns the lowerCamelCase form of a string. + + ```javascript + 'innerHTML'.camelize(); // 'innerHTML' + 'action_name'.camelize(); // 'actionName' + 'css-class-name'.camelize(); // 'cssClassName' + 'my favorite items'.camelize(); // 'myFavoriteItems' + 'My Favorite Items'.camelize(); // 'myFavoriteItems' + ``` + + @method camelize + @param {String} str The string to camelize. + @return {String} the camelized string. + */ + camelize: camelize, + + /** + Returns the UpperCamelCase form of a string. + + ```javascript + 'innerHTML'.classify(); // 'InnerHTML' + 'action_name'.classify(); // 'ActionName' + 'css-class-name'.classify(); // 'CssClassName' + 'my favorite items'.classify(); // 'MyFavoriteItems' + ``` + + @method classify + @param {String} str the string to classify + @return {String} the classified string + */ + classify: classify, + + /** + More general than decamelize. Returns the lower\_case\_and\_underscored + form of a string. + + ```javascript + 'innerHTML'.underscore(); // 'inner_html' + 'action_name'.underscore(); // 'action_name' + 'css-class-name'.underscore(); // 'css_class_name' + 'my favorite items'.underscore(); // 'my_favorite_items' + ``` + + @method underscore + @param {String} str The string to underscore. + @return {String} the underscored string. + */ + underscore: underscore, + + /** + Returns the Capitalized form of a string + + ```javascript + 'innerHTML'.capitalize() // 'InnerHTML' + 'action_name'.capitalize() // 'Action_name' + 'css-class-name'.capitalize() // 'Css-class-name' + 'my favorite items'.capitalize() // 'My favorite items' + ``` + + @method capitalize + @param {String} str The string to capitalize. + @return {String} The capitalized string. + */ + capitalize: capitalize + }; + + __exports__.fmt = fmt; + __exports__.loc = loc; + __exports__.w = w; + __exports__.decamelize = decamelize; + __exports__.dasherize = dasherize; + __exports__.camelize = camelize; + __exports__.classify = classify; + __exports__.underscore = underscore; + __exports__.capitalize = capitalize; + }); +define("ember-runtime/system/subarray", + ["ember-metal/property_get","ember-metal/error","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var EmberError = __dependency2__["default"]; + var EnumerableUtils = __dependency3__["default"]; + + var RETAIN = 'r'; + var FILTER = 'f'; + + function Operation(type, count) { + this.type = type; + this.count = count; + } + + __exports__["default"] = SubArray; + + /** + An `Ember.SubArray` tracks an array in a way similar to, but more specialized + than, `Ember.TrackedArray`. It is useful for keeping track of the indexes of + items within a filtered array. + + @class SubArray + @namespace Ember + */ + function SubArray (length) { + if (arguments.length < 1) { length = 0; } + + if (length > 0) { + this._operations = [new Operation(RETAIN, length)]; + } else { + this._operations = []; + } + } + + + SubArray.prototype = { + /** + Track that an item was added to the tracked array. + + @method addItem + + @param {Number} index The index of the item in the tracked array. + @param {Boolean} match `true` iff the item is included in the subarray. + + @return {number} The index of the item in the subarray. + */ + addItem: function(index, match) { + var returnValue = -1; + var itemType = match ? RETAIN : FILTER; + var self = this; + + this._findOperation(index, function(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { + var newOperation, splitOperation; + + if (itemType === operation.type) { + ++operation.count; + } else if (index === rangeStart) { + // insert to the left of `operation` + self._operations.splice(operationIndex, 0, new Operation(itemType, 1)); + } else { + newOperation = new Operation(itemType, 1); + splitOperation = new Operation(operation.type, rangeEnd - index + 1); + operation.count = index - rangeStart; + + self._operations.splice(operationIndex + 1, 0, newOperation, splitOperation); + } + + if (match) { + if (operation.type === RETAIN) { + returnValue = seenInSubArray + (index - rangeStart); + } else { + returnValue = seenInSubArray; + } + } + + self._composeAt(operationIndex); + }, function(seenInSubArray) { + self._operations.push(new Operation(itemType, 1)); + + if (match) { + returnValue = seenInSubArray; + } + + self._composeAt(self._operations.length-1); + }); + + return returnValue; + }, + + /** + Track that an item was removed from the tracked array. + + @method removeItem + + @param {Number} index The index of the item in the tracked array. + + @return {number} The index of the item in the subarray, or `-1` if the item + was not in the subarray. + */ + removeItem: function(index) { + var returnValue = -1; + var self = this; + + this._findOperation(index, function (operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { + if (operation.type === RETAIN) { + returnValue = seenInSubArray + (index - rangeStart); + } + + if (operation.count > 1) { + --operation.count; + } else { + self._operations.splice(operationIndex, 1); + self._composeAt(operationIndex); + } + }, function() { + throw new EmberError("Can't remove an item that has never been added."); + }); + + return returnValue; + }, + + + _findOperation: function (index, foundCallback, notFoundCallback) { + var seenInSubArray = 0; + var operationIndex, len, operation, rangeStart, rangeEnd; + + // OPTIMIZE: change to balanced tree + // find leftmost operation to the right of `index` + for (operationIndex = rangeStart = 0, len = this._operations.length; operationIndex < len; rangeStart = rangeEnd + 1, ++operationIndex) { + operation = this._operations[operationIndex]; + rangeEnd = rangeStart + operation.count - 1; + + if (index >= rangeStart && index <= rangeEnd) { + foundCallback(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray); + return; + } else if (operation.type === RETAIN) { + seenInSubArray += operation.count; + } + } + + notFoundCallback(seenInSubArray); + }, + + _composeAt: function(index) { + var op = this._operations[index]; + var otherOp; + + if (!op) { + // Composing out of bounds is a no-op, as when removing the last operation + // in the list. + return; + } + + if (index > 0) { + otherOp = this._operations[index-1]; + if (otherOp.type === op.type) { + op.count += otherOp.count; + this._operations.splice(index-1, 1); + --index; + } + } + + if (index < this._operations.length-1) { + otherOp = this._operations[index+1]; + if (otherOp.type === op.type) { + op.count += otherOp.count; + this._operations.splice(index+1, 1); + } + } + }, + + toString: function () { + var str = ""; + EnumerableUtils.forEach(this._operations, function (operation) { + str += " " + operation.type + ":" + operation.count; + }); + return str.substring(1); + } + }; + }); +define("ember-runtime/system/tracked_array", + ["ember-metal/property_get","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var forEach = __dependency2__.forEach; + + var RETAIN = 'r'; + var INSERT = 'i'; + var DELETE = 'd'; + + __exports__["default"] = TrackedArray; + + /** + An `Ember.TrackedArray` tracks array operations. It's useful when you want to + lazily compute the indexes of items in an array after they've been shifted by + subsequent operations. + + @class TrackedArray + @namespace Ember + @param {Array} [items=[]] The array to be tracked. This is used just to get + the initial items for the starting state of retain:n. + */ + function TrackedArray(items) { + if (arguments.length < 1) { items = []; } + + var length = get(items, 'length'); + + if (length) { + this._operations = [new ArrayOperation(RETAIN, length, items)]; + } else { + this._operations = []; + } + } + + TrackedArray.RETAIN = RETAIN; + TrackedArray.INSERT = INSERT; + TrackedArray.DELETE = DELETE; + + TrackedArray.prototype = { + + /** + Track that `newItems` were added to the tracked array at `index`. + + @method addItems + @param index + @param newItems + */ + addItems: function (index, newItems) { + var count = get(newItems, 'length'); + if (count < 1) { return; } + + var match = this._findArrayOperation(index); + var arrayOperation = match.operation; + var arrayOperationIndex = match.index; + var arrayOperationRangeStart = match.rangeStart; + var composeIndex, splitIndex, splitItems, splitArrayOperation, newArrayOperation; + + newArrayOperation = new ArrayOperation(INSERT, count, newItems); + + if (arrayOperation) { + if (!match.split) { + // insert left of arrayOperation + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); + composeIndex = arrayOperationIndex; + } else { + this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); + composeIndex = arrayOperationIndex + 1; + } + } else { + // insert at end + this._operations.push(newArrayOperation); + composeIndex = arrayOperationIndex; + } + + this._composeInsert(composeIndex); + }, + + /** + Track that `count` items were removed at `index`. + + @method removeItems + @param index + @param count + */ + removeItems: function (index, count) { + if (count < 1) { return; } + + var match = this._findArrayOperation(index); + var arrayOperation = match.operation; + var arrayOperationIndex = match.index; + var arrayOperationRangeStart = match.rangeStart; + var newArrayOperation, composeIndex; + + newArrayOperation = new ArrayOperation(DELETE, count); + if (!match.split) { + // insert left of arrayOperation + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); + composeIndex = arrayOperationIndex; + } else { + this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); + composeIndex = arrayOperationIndex + 1; + } + + return this._composeDelete(composeIndex); + }, + + /** + Apply all operations, reducing them to retain:n, for `n`, the number of + items in the array. + + `callback` will be called for each operation and will be passed the following arguments: + + * {array} items The items for the given operation + * {number} offset The computed offset of the items, ie the index in the + array of the first item for this operation. + * {string} operation The type of the operation. One of + `Ember.TrackedArray.{RETAIN, DELETE, INSERT}` + + @method apply + @param {Function} callback + */ + apply: function (callback) { + var items = []; + var offset = 0; + + forEach(this._operations, function (arrayOperation, operationIndex) { + callback(arrayOperation.items, offset, arrayOperation.type, operationIndex); + + if (arrayOperation.type !== DELETE) { + offset += arrayOperation.count; + items = items.concat(arrayOperation.items); + } + }); + + this._operations = [new ArrayOperation(RETAIN, items.length, items)]; + }, + + /** + Return an `ArrayOperationMatch` for the operation that contains the item at `index`. + + @method _findArrayOperation + + @param {Number} index the index of the item whose operation information + should be returned. + @private + */ + _findArrayOperation: function (index) { + var split = false; + var arrayOperationIndex, arrayOperation, + arrayOperationRangeStart, arrayOperationRangeEnd, + len; + + // OPTIMIZE: we could search these faster if we kept a balanced tree. + // find leftmost arrayOperation to the right of `index` + for (arrayOperationIndex = arrayOperationRangeStart = 0, len = this._operations.length; arrayOperationIndex < len; ++arrayOperationIndex) { + arrayOperation = this._operations[arrayOperationIndex]; + + if (arrayOperation.type === DELETE) { continue; } + + arrayOperationRangeEnd = arrayOperationRangeStart + arrayOperation.count - 1; + + if (index === arrayOperationRangeStart) { + break; + } else if (index > arrayOperationRangeStart && index <= arrayOperationRangeEnd) { + split = true; + break; + } else { + arrayOperationRangeStart = arrayOperationRangeEnd + 1; + } + } + + return new ArrayOperationMatch(arrayOperation, arrayOperationIndex, split, arrayOperationRangeStart); + }, + + _split: function (arrayOperationIndex, splitIndex, newArrayOperation) { + var arrayOperation = this._operations[arrayOperationIndex]; + var splitItems = arrayOperation.items.slice(splitIndex); + var splitArrayOperation = new ArrayOperation(arrayOperation.type, splitItems.length, splitItems); + + // truncate LHS + arrayOperation.count = splitIndex; + arrayOperation.items = arrayOperation.items.slice(0, splitIndex); + + this._operations.splice(arrayOperationIndex + 1, 0, newArrayOperation, splitArrayOperation); + }, + + // see SubArray for a better implementation. + _composeInsert: function (index) { + var newArrayOperation = this._operations[index]; + var leftArrayOperation = this._operations[index-1]; // may be undefined + var rightArrayOperation = this._operations[index+1]; // may be undefined + var leftOp = leftArrayOperation && leftArrayOperation.type; + var rightOp = rightArrayOperation && rightArrayOperation.type; + + if (leftOp === INSERT) { + // merge left + leftArrayOperation.count += newArrayOperation.count; + leftArrayOperation.items = leftArrayOperation.items.concat(newArrayOperation.items); + + if (rightOp === INSERT) { + // also merge right (we have split an insert with an insert) + leftArrayOperation.count += rightArrayOperation.count; + leftArrayOperation.items = leftArrayOperation.items.concat(rightArrayOperation.items); + this._operations.splice(index, 2); + } else { + // only merge left + this._operations.splice(index, 1); + } + } else if (rightOp === INSERT) { + // merge right + newArrayOperation.count += rightArrayOperation.count; + newArrayOperation.items = newArrayOperation.items.concat(rightArrayOperation.items); + this._operations.splice(index + 1, 1); + } + }, + + _composeDelete: function (index) { + var arrayOperation = this._operations[index]; + var deletesToGo = arrayOperation.count; + var leftArrayOperation = this._operations[index-1]; // may be undefined + var leftOp = leftArrayOperation && leftArrayOperation.type; + var nextArrayOperation; + var nextOp; + var nextCount; + var removeNewAndNextOp = false; + var removedItems = []; + + if (leftOp === DELETE) { + arrayOperation = leftArrayOperation; + index -= 1; + } + + for (var i = index + 1; deletesToGo > 0; ++i) { + nextArrayOperation = this._operations[i]; + nextOp = nextArrayOperation.type; + nextCount = nextArrayOperation.count; + + if (nextOp === DELETE) { + arrayOperation.count += nextCount; + continue; + } + + if (nextCount > deletesToGo) { + // d:2 {r,i}:5 we reduce the retain or insert, but it stays + removedItems = removedItems.concat(nextArrayOperation.items.splice(0, deletesToGo)); + nextArrayOperation.count -= deletesToGo; + + // In the case where we truncate the last arrayOperation, we don't need to + // remove it; also the deletesToGo reduction is not the entirety of + // nextCount + i -= 1; + nextCount = deletesToGo; + + deletesToGo = 0; + } else { + if (nextCount === deletesToGo) { + // Handle edge case of d:2 i:2 in which case both operations go away + // during composition. + removeNewAndNextOp = true; + } + removedItems = removedItems.concat(nextArrayOperation.items); + deletesToGo -= nextCount; + } + + if (nextOp === INSERT) { + // d:2 i:3 will result in delete going away + arrayOperation.count -= nextCount; + } + } + + if (arrayOperation.count > 0) { + // compose our new delete with possibly several operations to the right of + // disparate types + this._operations.splice(index+1, i-1-index); + } else { + // The delete operation can go away; it has merely reduced some other + // operation, as in d:3 i:4; it may also have eliminated that operation, + // as in d:3 i:3. + this._operations.splice(index, removeNewAndNextOp ? 2 : 1); + } + + return removedItems; + }, + + toString: function () { + var str = ""; + forEach(this._operations, function (operation) { + str += " " + operation.type + ":" + operation.count; + }); + return str.substring(1); + } + }; + + /** + Internal data structure to represent an array operation. + + @method ArrayOperation + @private + @param {String} type The type of the operation. One of + `Ember.TrackedArray.{RETAIN, INSERT, DELETE}` + @param {Number} count The number of items in this operation. + @param {Array} items The items of the operation, if included. RETAIN and + INSERT include their items, DELETE does not. + */ + function ArrayOperation (operation, count, items) { + this.type = operation; // RETAIN | INSERT | DELETE + this.count = count; + this.items = items; + } + + /** + Internal data structure used to include information when looking up operations + by item index. + + @method ArrayOperationMatch + @private + @param {ArrayOperation} operation + @param {Number} index The index of `operation` in the array of operations. + @param {Boolean} split Whether or not the item index searched for would + require a split for a new operation type. + @param {Number} rangeStart The index of the first item in the operation, + with respect to the tracked array. The index of the last item can be computed + from `rangeStart` and `operation.count`. + */ + function ArrayOperationMatch(operation, index, split, rangeStart) { + this.operation = operation; + this.index = index; + this.split = split; + this.rangeStart = rangeStart; + } + }); +define("ember-testing", + ["ember-metal/core","ember-testing/initializers","ember-testing/support","ember-testing/setup_for_testing","ember-testing/test","ember-testing/adapters/adapter","ember-testing/adapters/qunit","ember-testing/helpers"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { + "use strict"; + var Ember = __dependency1__["default"]; + + // to setup initializer + // to handle various edge cases + + var setupForTesting = __dependency4__["default"]; + var Test = __dependency5__["default"]; + var Adapter = __dependency6__["default"]; + var QUnitAdapter = __dependency7__["default"]; + // adds helpers to helpers object in Test + + /** + Ember Testing + + @module ember + @submodule ember-testing + @requires ember-application + */ + + Ember.Test = Test; + Ember.Test.Adapter = Adapter; + Ember.Test.QUnitAdapter = QUnitAdapter; + Ember.setupForTesting = setupForTesting; + }); +define("ember-testing/adapters/adapter", + ["ember-metal/core","ember-metal/utils","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.K + var inspect = __dependency2__.inspect; + var EmberObject = __dependency3__["default"]; + + /** + @module ember + @submodule ember-testing + */ + + /** + The primary purpose of this class is to create hooks that can be implemented + by an adapter for various test frameworks. + + @class Adapter + @namespace Ember.Test + */ + var Adapter = EmberObject.extend({ + /** + This callback will be called whenever an async operation is about to start. + + Override this to call your framework's methods that handle async + operations. + + @public + @method asyncStart + */ + asyncStart: Ember.K, + + /** + This callback will be called whenever an async operation has completed. + + @public + @method asyncEnd + */ + asyncEnd: Ember.K, + + /** + Override this method with your testing framework's false assertion. + This function is called whenever an exception occurs causing the testing + promise to fail. + + QUnit example: + + ```javascript + exception: function(error) { + ok(false, error); + }; + ``` + + @public + @method exception + @param {String} error The exception to be raised. + */ + exception: function(error) { + throw error; + } + }); + + __exports__["default"] = Adapter; + }); +define("ember-testing/adapters/qunit", + ["ember-testing/adapters/adapter","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Adapter = __dependency1__["default"]; + var inspect = __dependency2__.inspect; + + /** + This class implements the methods defined by Ember.Test.Adapter for the + QUnit testing framework. + + @class QUnitAdapter + @namespace Ember.Test + @extends Ember.Test.Adapter + */ + __exports__["default"] = Adapter.extend({ + asyncStart: function() { + QUnit.stop(); + }, + asyncEnd: function() { + QUnit.start(); + }, + exception: function(error) { + ok(false, inspect(error)); + } + }); + }); +define("ember-testing/helpers", + ["ember-metal/property_get","ember-metal/error","ember-metal/run_loop","ember-views/system/jquery","ember-testing/test"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) { + "use strict"; + var get = __dependency1__.get; + var EmberError = __dependency2__["default"]; + var run = __dependency3__["default"]; + var jQuery = __dependency4__["default"]; + var Test = __dependency5__["default"]; + + /** + * @module ember + * @submodule ember-testing + */ + + var helper = Test.registerHelper; + var asyncHelper = Test.registerAsyncHelper; + var countAsync = 0; + + function currentRouteName(app){ + var appController = app.__container__.lookup('controller:application'); + + return get(appController, 'currentRouteName'); + } + + function currentPath(app){ + var appController = app.__container__.lookup('controller:application'); + + return get(appController, 'currentPath'); + } + + function currentURL(app){ + var router = app.__container__.lookup('router:main'); + + return get(router, 'location').getURL(); + } + + function visit(app, url) { + var router = app.__container__.lookup('router:main'); + router.location.setURL(url); + + if (app._readinessDeferrals > 0) { + router['initialURL'] = url; + run(app, 'advanceReadiness'); + delete router['initialURL']; + } else { + run(app, app.handleURL, url); + } + + return app.testHelpers.wait(); + } + + function click(app, selector, context) { + var $el = app.testHelpers.findWithAssert(selector, context); + run($el, 'mousedown'); + + if ($el.is(':input')) { + var type = $el.prop('type'); + if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') { + run($el, function(){ + // Firefox does not trigger the `focusin` event if the window + // does not have focus. If the document doesn't have focus just + // use trigger('focusin') instead. + if (!document.hasFocus || document.hasFocus()) { + this.focus(); + } else { + this.trigger('focusin'); + } + }); + } + } + + run($el, 'mouseup'); + run($el, 'click'); + + return app.testHelpers.wait(); + } + + function triggerEvent(app, selector, contextOrType, typeOrOptions, possibleOptions){ + var arity = arguments.length; + var context, type, options; + + if (arity === 3) { + // context and options are optional, so this is + // app, selector, type + context = null; + type = contextOrType; + options = {}; + } else if (arity === 4) { + // context and options are optional, so this is + if (typeof typeOrOptions === "object") { // either + // app, selector, type, options + context = null; + type = contextOrType; + options = typeOrOptions; + } else { // or + // app, selector, context, type + context = contextOrType; + type = typeOrOptions; + options = {}; + } + } else { + context = contextOrType; + type = typeOrOptions; + options = possibleOptions; + } + + var $el = app.testHelpers.findWithAssert(selector, context); + + var event = jQuery.Event(type, options); + + run($el, 'trigger', event); + + return app.testHelpers.wait(); + } + + function keyEvent(app, selector, contextOrType, typeOrKeyCode, keyCode) { + var context, type; + + if (typeof keyCode === 'undefined') { + context = null; + keyCode = typeOrKeyCode; + type = contextOrType; + } else { + context = contextOrType; + type = typeOrKeyCode; + } + + return app.testHelpers.triggerEvent(selector, context, type, { keyCode: keyCode, which: keyCode }); + } + + function fillIn(app, selector, contextOrText, text) { + var $el, context; + if (typeof text === 'undefined') { + text = contextOrText; + } else { + context = contextOrText; + } + $el = app.testHelpers.findWithAssert(selector, context); + run(function() { + $el.val(text).change(); + }); + return app.testHelpers.wait(); + } + + function findWithAssert(app, selector, context) { + var $el = app.testHelpers.find(selector, context); + if ($el.length === 0) { + throw new EmberError("Element " + selector + " not found."); + } + return $el; + } + + function find(app, selector, context) { + var $el; + context = context || get(app, 'rootElement'); + $el = app.$(selector, context); + + return $el; + } + + function andThen(app, callback) { + return app.testHelpers.wait(callback(app)); + } + + function wait(app, value) { + return Test.promise(function(resolve) { + // If this is the first async promise, kick off the async test + if (++countAsync === 1) { + Test.adapter.asyncStart(); + } + + // Every 10ms, poll for the async thing to have finished + var watcher = setInterval(function() { + // 1. If the router is loading, keep polling + var routerIsLoading = !!app.__container__.lookup('router:main').router.activeTransition; + if (routerIsLoading) { return; } + + // 2. If there are pending Ajax requests, keep polling + if (Test.pendingAjaxRequests) { return; } + + // 3. If there are scheduled timers or we are inside of a run loop, keep polling + if (run.hasScheduledTimers() || run.currentRunLoop) { return; } + if (Test.waiters && Test.waiters.any(function(waiter) { + var context = waiter[0]; + var callback = waiter[1]; + return !callback.call(context); + })) { return; } + // Stop polling + clearInterval(watcher); + + // If this is the last async promise, end the async test + if (--countAsync === 0) { + Test.adapter.asyncEnd(); + } + + // Synchronously resolve the promise + run(null, resolve, value); + }, 10); + }); + + } + + + /** + * Loads a route, sets up any controllers, and renders any templates associated + * with the route as though a real user had triggered the route change while + * using your app. + * + * Example: + * + * ```javascript + * visit('posts/index').then(function() { + * // assert something + * }); + * ``` + * + * @method visit + * @param {String} url the name of the route + * @return {RSVP.Promise} + */ + asyncHelper('visit', visit); + + /** + * Clicks an element and triggers any actions triggered by the element's `click` + * event. + * + * Example: + * + * ```javascript + * click('.some-jQuery-selector').then(function() { + * // assert something + * }); + * ``` + * + * @method click + * @param {String} selector jQuery selector for finding element on the DOM + * @return {RSVP.Promise} + */ + asyncHelper('click', click); + + /** + * Simulates a key event, e.g. `keypress`, `keydown`, `keyup` with the desired keyCode + * + * Example: + * + * ```javascript + * keyEvent('.some-jQuery-selector', 'keypress', 13).then(function() { + * // assert something + * }); + * ``` + * + * @method keyEvent + * @param {String} selector jQuery selector for finding element on the DOM + * @param {String} type the type of key event, e.g. `keypress`, `keydown`, `keyup` + * @param {Number} keyCode the keyCode of the simulated key event + * @return {RSVP.Promise} + * @since 1.5.0 + */ + asyncHelper('keyEvent', keyEvent); + + /** + * Fills in an input element with some text. + * + * Example: + * + * ```javascript + * fillIn('#email', 'you@example.com').then(function() { + * // assert something + * }); + * ``` + * + * @method fillIn + * @param {String} selector jQuery selector finding an input element on the DOM + * to fill text with + * @param {String} text text to place inside the input element + * @return {RSVP.Promise} + */ + asyncHelper('fillIn', fillIn); + + /** + * Finds an element in the context of the app's container element. A simple alias + * for `app.$(selector)`. + * + * Example: + * + * ```javascript + * var $el = find('.my-selector'); + * ``` + * + * @method find + * @param {String} selector jQuery string selector for element lookup + * @return {Object} jQuery object representing the results of the query + */ + helper('find', find); + + /** + * Like `find`, but throws an error if the element selector returns no results. + * + * Example: + * + * ```javascript + * var $el = findWithAssert('.doesnt-exist'); // throws error + * ``` + * + * @method findWithAssert + * @param {String} selector jQuery selector string for finding an element within + * the DOM + * @return {Object} jQuery object representing the results of the query + * @throws {Error} throws error if jQuery object returned has a length of 0 + */ + helper('findWithAssert', findWithAssert); + + /** + Causes the run loop to process any pending events. This is used to ensure that + any async operations from other helpers (or your assertions) have been processed. + + This is most often used as the return value for the helper functions (see 'click', + 'fillIn','visit',etc). + + Example: + + ```javascript + Ember.Test.registerAsyncHelper('loginUser', function(app, username, password) { + visit('secured/path/here') + .fillIn('#username', username) + .fillIn('#password', username) + .click('.submit') + + return app.testHelpers.wait(); + }); + + @method wait + @param {Object} value The value to be returned. + @return {RSVP.Promise} + */ + asyncHelper('wait', wait); + asyncHelper('andThen', andThen); + + + /** + Returns the currently active route name. + + Example: + + ```javascript + function validateRouteName(){ + equal(currentRouteName(), 'some.path', "correct route was transitioned into."); + } + + visit('/some/path').then(validateRouteName) + ``` + + @method currentRouteName + @return {Object} The name of the currently active route. + @since 1.5.0 + */ + helper('currentRouteName', currentRouteName); + + /** + Returns the current path. + + Example: + + ```javascript + function validateURL(){ + equal(currentPath(), 'some.path.index', "correct path was transitioned into."); + } + + click('#some-link-id').then(validateURL); + ``` + + @method currentPath + @return {Object} The currently active path. + @since 1.5.0 + */ + helper('currentPath', currentPath); + + /** + Returns the current URL. + + Example: + + ```javascript + function validateURL(){ + equal(currentURL(), '/some/path', "correct URL was transitioned into."); + } + + click('#some-link-id').then(validateURL); + ``` + + @method currentURL + @return {Object} The currently active URL. + @since 1.5.0 + */ + helper('currentURL', currentURL); + + /** + Triggers the given DOM event on the element identified by the provided selector. + + Example: + + ```javascript + triggerEvent('#some-elem-id', 'blur'); + ``` + + This is actually used internally by the `keyEvent` helper like so: + + ```javascript + triggerEvent('#some-elem-id', 'keypress', { keyCode: 13 }); + ``` + + @method triggerEvent + @param {String} selector jQuery selector for finding element on the DOM + @param {String} [context] jQuery selector that will limit the selector + argument to find only within the context's children + @param {String} type The event type to be triggered. + @param {Object} [options] The options to be passed to jQuery.Event. + @return {RSVP.Promise} + @since 1.5.0 + */ + asyncHelper('triggerEvent', triggerEvent); + }); +define("ember-testing/initializers", + ["ember-runtime/system/lazy_load"], + function(__dependency1__) { + "use strict"; + var onLoad = __dependency1__.onLoad; + + var name = 'deferReadiness in `testing` mode'; + + onLoad('Ember.Application', function(Application) { + if (!Application.initializers[name]) { + Application.initializer({ + name: name, + + initialize: function(container, application){ + if (application.testing) { + application.deferReadiness(); + } + } + }); + } + }); + }); +define("ember-testing/setup_for_testing", + ["ember-metal/core","ember-testing/adapters/qunit","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // import Test from "ember-testing/test"; // ES6TODO: fix when cycles are supported + var QUnitAdapter = __dependency2__["default"]; + var jQuery = __dependency3__["default"]; + + var Test, requests; + + function incrementAjaxPendingRequests(_, xhr){ + requests.push(xhr); + Test.pendingAjaxRequests = requests.length; + } + + function decrementAjaxPendingRequests(_, xhr){ + for (var i=0;i') + .css({ position: 'absolute', left: '-1000px', top: '-1000px' }) + .appendTo('body') + .on('click', handler) + .trigger('click') + .remove(); + } + + $(function() { + /* + Determine whether a checkbox checked using jQuery's "click" method will have + the correct value for its checked property. + + If we determine that the current jQuery version exhibits this behavior, + patch it to work correctly as in the commit for the actual fix: + https://github.com/jquery/jquery/commit/1fb2f92. + */ + testCheckboxClick(function() { + if (!this.checked && !$.event.special.click) { + $.event.special.click = { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ($.nodeName( this, "input" ) && this.type === "checkbox" && this.click) { + this.click(); + return false; + } + } + }; + } + }); + + // Try again to verify that the patch took effect or blow up. + testCheckboxClick(function() { + Ember.warn("clicked checkboxes should be checked! the jQuery patch didn't work", this.checked); + }); + }); + }); +define("ember-testing/test", + ["ember-metal/core","ember-metal/run_loop","ember-metal/platform","ember-runtime/compare","ember-runtime/ext/rsvp","ember-testing/setup_for_testing","ember-application/system/application","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var emberRun = __dependency2__["default"]; + var create = __dependency3__.create; + var compare = __dependency4__["default"]; + var RSVP = __dependency5__["default"]; + var setupForTesting = __dependency6__["default"]; + var EmberApplication = __dependency7__["default"]; + + /** + @module ember + @submodule ember-testing + */ + var slice = [].slice; + var helpers = {}; + var injectHelpersCallbacks = []; + + /** + This is a container for an assortment of testing related functionality: + + * Choose your default test adapter (for your framework of choice). + * Register/Unregister additional test helpers. + * Setup callbacks to be fired when the test helpers are injected into + your application. + + @class Test + @namespace Ember + */ + var Test = { + /** + Hash containing all known test helpers. + + @property _helpers + @private + @since 1.7.0 + */ + _helpers: helpers, + + /** + `registerHelper` is used to register a test helper that will be injected + when `App.injectTestHelpers` is called. + + The helper method will always be called with the current Application as + the first parameter. + + For example: + + ```javascript + Ember.Test.registerHelper('boot', function(app) { + Ember.run(app, app.advanceReadiness); + }); + ``` + + This helper can later be called without arguments because it will be + called with `app` as the first parameter. + + ```javascript + App = Ember.Application.create(); + App.injectTestHelpers(); + boot(); + ``` + + @public + @method registerHelper + @param {String} name The name of the helper method to add. + @param {Function} helperMethod + @param options {Object} + */ + registerHelper: function(name, helperMethod) { + helpers[name] = { + method: helperMethod, + meta: { wait: false } + }; + }, + + /** + `registerAsyncHelper` is used to register an async test helper that will be injected + when `App.injectTestHelpers` is called. + + The helper method will always be called with the current Application as + the first parameter. + + For example: + + ```javascript + Ember.Test.registerAsyncHelper('boot', function(app) { + Ember.run(app, app.advanceReadiness); + }); + ``` + + The advantage of an async helper is that it will not run + until the last async helper has completed. All async helpers + after it will wait for it complete before running. + + + For example: + + ```javascript + Ember.Test.registerAsyncHelper('deletePost', function(app, postId) { + click('.delete-' + postId); + }); + + // ... in your test + visit('/post/2'); + deletePost(2); + visit('/post/3'); + deletePost(3); + ``` + + @public + @method registerAsyncHelper + @param {String} name The name of the helper method to add. + @param {Function} helperMethod + @since 1.2.0 + */ + registerAsyncHelper: function(name, helperMethod) { + helpers[name] = { + method: helperMethod, + meta: { wait: true } + }; + }, + + /** + Remove a previously added helper method. + + Example: + + ```javascript + Ember.Test.unregisterHelper('wait'); + ``` + + @public + @method unregisterHelper + @param {String} name The helper to remove. + */ + unregisterHelper: function(name) { + delete helpers[name]; + delete Test.Promise.prototype[name]; + }, + + /** + Used to register callbacks to be fired whenever `App.injectTestHelpers` + is called. + + The callback will receive the current application as an argument. + + Example: + + ```javascript + Ember.Test.onInjectHelpers(function() { + Ember.$(document).ajaxSend(function() { + Test.pendingAjaxRequests++; + }); + + Ember.$(document).ajaxComplete(function() { + Test.pendingAjaxRequests--; + }); + }); + ``` + + @public + @method onInjectHelpers + @param {Function} callback The function to be called. + */ + onInjectHelpers: function(callback) { + injectHelpersCallbacks.push(callback); + }, + + /** + This returns a thenable tailored for testing. It catches failed + `onSuccess` callbacks and invokes the `Ember.Test.adapter.exception` + callback in the last chained then. + + This method should be returned by async helpers such as `wait`. + + @public + @method promise + @param {Function} resolver The function used to resolve the promise. + */ + promise: function(resolver) { + return new Test.Promise(resolver); + }, + + /** + Used to allow ember-testing to communicate with a specific testing + framework. + + You can manually set it before calling `App.setupForTesting()`. + + Example: + + ```javascript + Ember.Test.adapter = MyCustomAdapter.create() + ``` + + If you do not set it, ember-testing will default to `Ember.Test.QUnitAdapter`. + + @public + @property adapter + @type {Class} The adapter to be used. + @default Ember.Test.QUnitAdapter + */ + adapter: null, + + /** + Replacement for `Ember.RSVP.resolve` + The only difference is this uses + an instance of `Ember.Test.Promise` + + @public + @method resolve + @param {Mixed} The value to resolve + @since 1.2.0 + */ + resolve: function(val) { + return Test.promise(function(resolve) { + return resolve(val); + }); + }, + + /** + This allows ember-testing to play nicely with other asynchronous + events, such as an application that is waiting for a CSS3 + transition or an IndexDB transaction. + + For example: + + ```javascript + Ember.Test.registerWaiter(function() { + return myPendingTransactions() == 0; + }); + ``` + The `context` argument allows you to optionally specify the `this` + with which your callback will be invoked. + + For example: + + ```javascript + Ember.Test.registerWaiter(MyDB, MyDB.hasPendingTransactions); + ``` + + @public + @method registerWaiter + @param {Object} context (optional) + @param {Function} callback + @since 1.2.0 + */ + registerWaiter: function(context, callback) { + if (arguments.length === 1) { + callback = context; + context = null; + } + if (!this.waiters) { + this.waiters = Ember.A(); + } + this.waiters.push([context, callback]); + }, + /** + `unregisterWaiter` is used to unregister a callback that was + registered with `registerWaiter`. + + @public + @method unregisterWaiter + @param {Object} context (optional) + @param {Function} callback + @since 1.2.0 + */ + unregisterWaiter: function(context, callback) { + var pair; + if (!this.waiters) { return; } + if (arguments.length === 1) { + callback = context; + context = null; + } + pair = [context, callback]; + this.waiters = Ember.A(this.waiters.filter(function(elt) { + return compare(elt, pair)!==0; + })); + } + }; + + function helper(app, name) { + var fn = helpers[name].method; + var meta = helpers[name].meta; + + return function() { + var args = slice.call(arguments); + var lastPromise = Test.lastPromise; + + args.unshift(app); + + // some helpers are not async and + // need to return a value immediately. + // example: `find` + if (!meta.wait) { + return fn.apply(app, args); + } + + if (!lastPromise) { + // It's the first async helper in current context + lastPromise = fn.apply(app, args); + } else { + // wait for last helper's promise to resolve + // and then execute + run(function() { + lastPromise = Test.resolve(lastPromise).then(function() { + return fn.apply(app, args); + }); + }); + } + + return lastPromise; + }; + } + + function run(fn) { + if (!emberRun.currentRunLoop) { + emberRun(fn); + } else { + fn(); + } + } + + EmberApplication.reopen({ + /** + This property contains the testing helpers for the current application. These + are created once you call `injectTestHelpers` on your `Ember.Application` + instance. The included helpers are also available on the `window` object by + default, but can be used from this object on the individual application also. + + @property testHelpers + @type {Object} + @default {} + */ + testHelpers: {}, + + /** + This property will contain the original methods that were registered + on the `helperContainer` before `injectTestHelpers` is called. + + When `removeTestHelpers` is called, these methods are restored to the + `helperContainer`. + + @property originalMethods + @type {Object} + @default {} + @private + @since 1.3.0 + */ + originalMethods: {}, + + + /** + This property indicates whether or not this application is currently in + testing mode. This is set when `setupForTesting` is called on the current + application. + + @property testing + @type {Boolean} + @default false + @since 1.3.0 + */ + testing: false, + + /** + This hook defers the readiness of the application, so that you can start + the app when your tests are ready to run. It also sets the router's + location to 'none', so that the window's location will not be modified + (preventing both accidental leaking of state between tests and interference + with your testing framework). + + Example: + + ``` + App.setupForTesting(); + ``` + + @method setupForTesting + */ + setupForTesting: function() { + setupForTesting(); + + this.testing = true; + + this.Router.reopen({ + location: 'none' + }); + }, + + /** + This will be used as the container to inject the test helpers into. By + default the helpers are injected into `window`. + + @property helperContainer + @type {Object} The object to be used for test helpers. + @default window + @since 1.2.0 + */ + helperContainer: window, + + /** + This injects the test helpers into the `helperContainer` object. If an object is provided + it will be used as the helperContainer. If `helperContainer` is not set it will default + to `window`. If a function of the same name has already been defined it will be cached + (so that it can be reset if the helper is removed with `unregisterHelper` or + `removeTestHelpers`). + + Any callbacks registered with `onInjectHelpers` will be called once the + helpers have been injected. + + Example: + ``` + App.injectTestHelpers(); + ``` + + @method injectTestHelpers + */ + injectTestHelpers: function(helperContainer) { + if (helperContainer) { this.helperContainer = helperContainer; } + + this.testHelpers = {}; + for (var name in helpers) { + this.originalMethods[name] = this.helperContainer[name]; + this.testHelpers[name] = this.helperContainer[name] = helper(this, name); + protoWrap(Test.Promise.prototype, name, helper(this, name), helpers[name].meta.wait); + } + + for(var i = 0, l = injectHelpersCallbacks.length; i < l; i++) { + injectHelpersCallbacks[i](this); + } + }, + + /** + This removes all helpers that have been registered, and resets and functions + that were overridden by the helpers. + + Example: + + ```javascript + App.removeTestHelpers(); + ``` + + @public + @method removeTestHelpers + */ + removeTestHelpers: function() { + for (var name in helpers) { + this.helperContainer[name] = this.originalMethods[name]; + delete this.testHelpers[name]; + delete this.originalMethods[name]; + } + } + }); + + // This method is no longer needed + // But still here for backwards compatibility + // of helper chaining + function protoWrap(proto, name, callback, isAsync) { + proto[name] = function() { + var args = arguments; + if (isAsync) { + return callback.apply(this, args); + } else { + return this.then(function() { + return callback.apply(this, args); + }); + } + }; + } + + Test.Promise = function() { + RSVP.Promise.apply(this, arguments); + Test.lastPromise = this; + }; + + Test.Promise.prototype = create(RSVP.Promise.prototype); + Test.Promise.prototype.constructor = Test.Promise; + + // Patch `then` to isolate async methods + // specifically `Ember.Test.lastPromise` + var originalThen = RSVP.Promise.prototype.then; + Test.Promise.prototype.then = function(onSuccess, onFailure) { + return originalThen.call(this, function(val) { + return isolate(onSuccess, val); + }, onFailure); + }; + + // This method isolates nested async methods + // so that they don't conflict with other last promises. + // + // 1. Set `Ember.Test.lastPromise` to null + // 2. Invoke method + // 3. Return the last promise created during method + // 4. Restore `Ember.Test.lastPromise` to original value + function isolate(fn, val) { + var value, lastPromise; + + // Reset lastPromise for nested helpers + Test.lastPromise = null; + + value = fn(val); + + lastPromise = Test.lastPromise; + + // If the method returned a promise + // return that promise. If not, + // return the last async helper's promise + if ((value && (value instanceof Test.Promise)) || !lastPromise) { + return value; + } else { + run(function() { + lastPromise = Test.resolve(lastPromise).then(function() { + return value; + }); + }); + return lastPromise; + } + } + + __exports__["default"] = Test; + }); +define("ember-views", + ["ember-runtime","ember-views/system/jquery","ember-views/system/utils","ember-views/system/render_buffer","ember-views/system/ext","ember-views/views/states","ember-views/views/core_view","ember-views/views/view","ember-views/views/container_view","ember-views/views/collection_view","ember-views/views/component","ember-views/system/event_dispatcher","ember-views/mixins/view_target_action_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /** + Ember Views + + @module ember + @submodule ember-views + @requires ember-runtime + @main ember-views + */ + + // BEGIN IMPORTS + var Ember = __dependency1__["default"]; + var jQuery = __dependency2__["default"]; + var isSimpleClick = __dependency3__.isSimpleClick; + var RenderBuffer = __dependency4__["default"]; + // for the side effect of extending Ember.run.queues + var cloneStates = __dependency6__.cloneStates; + var states = __dependency6__.states; + + var CoreView = __dependency7__["default"]; + var View = __dependency8__["default"]; + var ContainerView = __dependency9__["default"]; + var CollectionView = __dependency10__["default"]; + var Component = __dependency11__["default"]; + + var EventDispatcher = __dependency12__["default"]; + var ViewTargetActionSupport = __dependency13__["default"]; + // END IMPORTS + + /** + Alias for jQuery + + @method $ + @for Ember + */ + + // BEGIN EXPORTS + Ember.$ = jQuery; + + Ember.ViewTargetActionSupport = ViewTargetActionSupport; + Ember.RenderBuffer = RenderBuffer; + + var ViewUtils = Ember.ViewUtils = {}; + ViewUtils.isSimpleClick = isSimpleClick; + + Ember.CoreView = CoreView; + Ember.View = View; + Ember.View.states = states; + Ember.View.cloneStates = cloneStates; + + Ember.ContainerView = ContainerView; + Ember.CollectionView = CollectionView; + Ember.Component = Component; + Ember.EventDispatcher = EventDispatcher; + // END EXPORTS + + __exports__["default"] = Ember; + }); +define("ember-views/mixins/component_template_deprecation", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.deprecate + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + + /** + The ComponentTemplateDeprecation mixin is used to provide a useful + deprecation warning when using either `template` or `templateName` with + a component. The `template` and `templateName` properties specified at + extend time are moved to `layout` and `layoutName` respectively. + + `Ember.ComponentTemplateDeprecation` is used internally by Ember in + `Ember.Component`. + + @class ComponentTemplateDeprecation + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + @private + + Moves `templateName` to `layoutName` and `template` to `layout` at extend + time if a layout is not also specified. + + Note that this currently modifies the mixin themselves, which is technically + dubious but is practically of little consequence. This may change in the + future. + + @method willMergeMixin + @since 1.4.0 + */ + willMergeMixin: function(props) { + // must call _super here to ensure that the ActionHandler + // mixin is setup properly (moves actions -> _actions) + // + // Calling super is only OK here since we KNOW that + // there is another Mixin loaded first. + this._super.apply(this, arguments); + + var deprecatedProperty, replacementProperty; + var layoutSpecified = (props.layoutName || props.layout || get(this, 'layoutName')); + + if (props.templateName && !layoutSpecified) { + deprecatedProperty = 'templateName'; + replacementProperty = 'layoutName'; + + props.layoutName = props.templateName; + delete props['templateName']; + } + + if (props.template && !layoutSpecified) { + deprecatedProperty = 'template'; + replacementProperty = 'layout'; + + props.layout = props.template; + delete props['template']; + } + + if (deprecatedProperty) { + Ember.deprecate('Do not specify ' + deprecatedProperty + ' on a Component, use ' + replacementProperty + ' instead.', false); + } + } + }); + }); +define("ember-views/mixins/view_target_action_support", + ["ember-metal/mixin","ember-runtime/mixins/target_action_support","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var TargetActionSupport = __dependency2__["default"]; + + // ES6TODO: computed should have its own export path so you can do import {defaultTo} from computed + var computed = __dependency3__.computed; + var alias = computed.alias; + + /** + `Ember.ViewTargetActionSupport` is a mixin that can be included in a + view class to add a `triggerAction` method with semantics similar to + the Handlebars `{{action}}` helper. It provides intelligent defaults + for the action's target: the view's controller; and the context that is + sent with the action: the view's context. + + Note: In normal Ember usage, the `{{action}}` helper is usually the best + choice. This mixin is most often useful when you are doing more complex + event handling in custom View subclasses. + + For example: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { + action: 'save', + click: function() { + this.triggerAction(); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `action` can be provided as properties of an optional object argument + to `triggerAction` as well. + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { + click: function() { + this.triggerAction({ + action: 'save' + }); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + @class ViewTargetActionSupport + @namespace Ember + @extends Ember.TargetActionSupport + */ + __exports__["default"] = Mixin.create(TargetActionSupport, { + /** + @property target + */ + target: alias('controller'), + /** + @property actionContext + */ + actionContext: alias('context') + }); + }); +define("ember-views/system/action_manager", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + function ActionManager() {} + + /** + Global action id hash. + + @private + @property registeredActions + @type Object + */ + ActionManager.registeredActions = {}; + + __exports__["default"] = ActionManager; + }); +define("ember-views/system/event_dispatcher", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/object","ember-views/system/jquery","ember-views/system/action_manager","ember-views/views/view","ember-metal/merge","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var isNone = __dependency4__.isNone; + var run = __dependency5__["default"]; + var typeOf = __dependency6__.typeOf; + var fmt = __dependency7__.fmt; + var EmberObject = __dependency8__["default"]; + var jQuery = __dependency9__["default"]; + var ActionManager = __dependency10__["default"]; + var View = __dependency11__["default"]; + var merge = __dependency12__["default"]; + + //ES6TODO: + // find a better way to do Ember.View.views without global state + + /** + `Ember.EventDispatcher` handles delegating browser events to their + corresponding `Ember.Views.` For example, when you click on a view, + `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets + called. + + @class EventDispatcher + @namespace Ember + @private + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + + /** + The set of events names (and associated handler function names) to be setup + and dispatched by the `EventDispatcher`. Custom events can added to this list at setup + time, generally via the `Ember.Application.customEvents` hash. Only override this + default set to prevent the EventDispatcher from listening on some events all together. + + This set will be modified by `setup` to also include any events added at that time. + + @property events + @type Object + */ + events: { + touchstart : 'touchStart', + touchmove : 'touchMove', + touchend : 'touchEnd', + touchcancel : 'touchCancel', + keydown : 'keyDown', + keyup : 'keyUp', + keypress : 'keyPress', + mousedown : 'mouseDown', + mouseup : 'mouseUp', + contextmenu : 'contextMenu', + click : 'click', + dblclick : 'doubleClick', + mousemove : 'mouseMove', + focusin : 'focusIn', + focusout : 'focusOut', + mouseenter : 'mouseEnter', + mouseleave : 'mouseLeave', + submit : 'submit', + input : 'input', + change : 'change', + dragstart : 'dragStart', + drag : 'drag', + dragenter : 'dragEnter', + dragleave : 'dragLeave', + dragover : 'dragOver', + drop : 'drop', + dragend : 'dragEnd' + }, + + /** + The root DOM element to which event listeners should be attached. Event + listeners will be attached to the document unless this is overridden. + + Can be specified as a DOMElement or a selector string. + + The default body is a string since this may be evaluated before document.body + exists in the DOM. + + @private + @property rootElement + @type DOMElement + @default 'body' + */ + rootElement: 'body', + + /** + It enables events to be dispatched to the view's `eventManager.` When present, + this object takes precedence over handling of events on the view itself. + + Note that most Ember applications do not use this feature. If your app also + does not use it, consider setting this property to false to gain some performance + improvement by allowing the EventDispatcher to skip the search for the + `eventManager` on the view tree. + + ```javascript + var EventDispatcher = Em.EventDispatcher.extend({ + events: { + click : 'click', + focusin : 'focusIn', + focusout : 'focusOut', + change : 'change' + }, + canDispatchToEventManager: false + }); + container.register('event_dispatcher:main', EventDispatcher); + ``` + + @property canDispatchToEventManager + @type boolean + @default 'true' + @since 1.7.0 + */ + canDispatchToEventManager: true, + + /** + Sets up event listeners for standard browser events. + + This will be called after the browser sends a `DOMContentReady` event. By + default, it will set up all of the listeners on the document body. If you + would like to register the listeners on a different element, set the event + dispatcher's `root` property. + + @private + @method setup + @param addedEvents {Hash} + */ + setup: function(addedEvents, rootElement) { + var event, events = get(this, 'events'); + + merge(events, addedEvents || {}); + + if (!isNone(rootElement)) { + set(this, 'rootElement', rootElement); + } + + rootElement = jQuery(get(this, 'rootElement')); + + Ember.assert(fmt('You cannot use the same root element (%@) multiple times in an Ember.Application', [rootElement.selector || rootElement[0].tagName]), !rootElement.is('.ember-application')); + Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length); + Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length); + + rootElement.addClass('ember-application'); + + Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application')); + + for (event in events) { + if (events.hasOwnProperty(event)) { + this.setupHandler(rootElement, event, events[event]); + } + } + }, + + /** + Registers an event listener on the rootElement. If the given event is + triggered, the provided event handler will be triggered on the target view. + + If the target view does not implement the event handler, or if the handler + returns `false`, the parent view will be called. The event will continue to + bubble to each successive parent view until it reaches the top. + + @private + @method setupHandler + @param {Element} rootElement + @param {String} event the browser-originated event to listen to + @param {String} eventName the name of the method to call on the view + */ + setupHandler: function(rootElement, event, eventName) { + var self = this; + + rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) { + var view = View.views[this.id]; + var result = true; + + var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null; + + if (manager && manager !== triggeringManager) { + result = self._dispatchEvent(manager, evt, eventName, view); + } else if (view) { + result = self._bubbleEvent(view, evt, eventName); + } + + return result; + }); + + rootElement.on(event + '.ember', '[data-ember-action]', function(evt) { + var actionId = jQuery(evt.currentTarget).attr('data-ember-action'); + var action = ActionManager.registeredActions[actionId]; + + // We have to check for action here since in some cases, jQuery will trigger + // an event on `removeChild` (i.e. focusout) after we've already torn down the + // action handlers for the view. + if (action && action.eventName === eventName) { + return action.handler(evt); + } + }); + }, + + _findNearestEventManager: function(view, eventName) { + var manager = null; + + while (view) { + manager = get(view, 'eventManager'); + if (manager && manager[eventName]) { break; } + + view = get(view, 'parentView'); + } + + return manager; + }, + + _dispatchEvent: function(object, evt, eventName, view) { + var result = true; + + var handler = object[eventName]; + if (typeOf(handler) === 'function') { + result = run(object, handler, evt, view); + // Do not preventDefault in eventManagers. + evt.stopPropagation(); + } + else { + result = this._bubbleEvent(view, evt, eventName); + } + + return result; + }, + + _bubbleEvent: function(view, evt, eventName) { + return run(view, view.handleEvent, eventName, evt); + }, + + destroy: function() { + var rootElement = get(this, 'rootElement'); + jQuery(rootElement).off('.ember', '**').removeClass('ember-application'); + return this._super(); + }, + + toString: function() { + return '(EventDispatcher)'; + } + }); + }); +define("ember-views/system/ext", + ["ember-metal/run_loop"], + function(__dependency1__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + var run = __dependency1__["default"]; + + // Add a new named queue for rendering views that happens + // after bindings have synced, and a queue for scheduling actions + // that that should occur after view rendering. + var queues = run.queues; + run._addQueue('render', 'actions'); + run._addQueue('afterRender', 'render'); + }); +define("ember-views/system/jquery", + ["ember-metal/core","ember-runtime/system/string","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var w = __dependency2__.w; + + // ES6TODO: the functions on EnumerableUtils need their own exports + var forEach = __dependency3__.forEach; + + /** + Ember Views + + @module ember + @submodule ember-views + @requires ember-runtime + @main ember-views + */ + + var jQuery = (Ember.imports && Ember.imports.jQuery) || (this && this.jQuery); + if (!jQuery && typeof require === 'function') { + jQuery = require('jquery'); + } + + Ember.assert("Ember Views require jQuery between 1.7 and 2.1", jQuery && (jQuery().jquery.match(/^((1\.(7|8|9|10|11))|(2\.(0|1)))(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY)); + + /** + @module ember + @submodule ember-views + */ + if (jQuery) { + // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents + var dragEvents = w('dragstart drag dragenter dragleave dragover drop dragend'); + + // Copies the `dataTransfer` property from a browser event object onto the + // jQuery event object for the specified events + forEach(dragEvents, function(eventName) { + jQuery.event.fixHooks[eventName] = { props: ['dataTransfer'] }; + }); + } + + __exports__["default"] = jQuery; + }); +define("ember-views/system/render_buffer", + ["ember-views/system/jquery","morph","ember-metal/core","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + var jQuery = __dependency1__["default"]; + var DOMHelper = __dependency2__.DOMHelper; + var Ember = __dependency3__["default"]; + + // The HTML spec allows for "omitted start tags". These tags are optional + // when their intended child is the first thing in the parent tag. For + // example, this is a tbody start tag: + // + // + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
    + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup, but with a special allowance for disregarding + // + ``` + + And associate it by name using a view's `templateName` property: + + ```javascript + AView = Ember.View.extend({ + templateName: 'some-template' + }); + ``` + + If you have nested resources, your Handlebars template will look like this: + + ```html + + ``` + + And `templateName` property: + + ```javascript + AView = Ember.View.extend({ + templateName: 'posts/new' + }); + ``` + + Using a value for `templateName` that does not have a Handlebars template + with a matching `data-template-name` attribute will throw an error. + + For views classes that may have a template later defined (e.g. as the block + portion of a `{{view}}` Handlebars helper call in another template or in + a subclass), you can provide a `defaultTemplate` property set to compiled + template function. If a template is not later provided for the view instance + the `defaultTemplate` value will be used: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default'), + template: null, + templateName: null + }); + ``` + + Will result in instances with an HTML representation of: + + ```html +
    I was the default
    + ``` + + If a `template` or `templateName` is provided it will take precedence over + `defaultTemplate`: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default') + }); + + aView = AView.create({ + template: Ember.Handlebars.compile('I was the template, not default') + }); + ``` + + Will result in the following HTML representation when rendered: + + ```html +
    I was the template, not default
    + ``` + + ## View Context + + The default context of the compiled template is the view's controller: + + ```javascript + AView = Ember.View.extend({ + template: Ember.Handlebars.compile('Hello {{excitedGreeting}}') + }); + + aController = Ember.Object.create({ + firstName: 'Barry', + excitedGreeting: function() { + return this.get("content.firstName") + "!!!" + }.property() + }); + + aView = AView.create({ + controller: aController + }); + ``` + + Will result in an HTML representation of: + + ```html +
    Hello Barry!!!
    + ``` + + A context can also be explicitly supplied through the view's `context` + property. If the view has neither `context` nor `controller` properties, the + `parentView`'s context will be used. + + ## Layouts + + Views can have a secondary template that wraps their main template. Like + primary templates, layouts can be any function that accepts an optional + context parameter and returns a string of HTML that will be inserted inside + view's tag. Views whose HTML element is self closing (e.g. ``) + cannot have a layout and this property will be ignored. + + Most typically in Ember a layout will be a compiled `Ember.Handlebars` + template. + + A view's layout can be set directly with the `layout` property or reference + an existing Handlebars template by name with the `layoutName` property. + + A template used as a layout must contain a single use of the Handlebars + `{{yield}}` helper. The HTML contents of a view's rendered `template` will be + inserted at this location: + + ```javascript + AViewWithLayout = Ember.View.extend({ + layout: Ember.Handlebars.compile("
    {{yield}}
    "), + template: Ember.Handlebars.compile("I got wrapped") + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    +
    + I got wrapped +
    +
    + ``` + + See [Ember.Handlebars.helpers.yield](/api/classes/Ember.Handlebars.helpers.html#method_yield) + for more information. + + ## Responding to Browser Events + + Views can respond to user-initiated events in one of three ways: method + implementation, through an event manager, and through `{{action}}` helper use + in their template or layout. + + ### Method Implementation + + Views can respond to user-initiated events by implementing a method that + matches the event name. A `jQuery.Event` object will be passed as the + argument to this method. + + ```javascript + AView = Ember.View.extend({ + click: function(event) { + // will be called when when an instance's + // rendered element is clicked + } + }); + ``` + + ### Event Managers + + Views can define an object as their `eventManager` property. This object can + then implement methods that match the desired event names. Matching events + that occur on the view's rendered HTML or the rendered HTML of any of its DOM + descendants will trigger this method. A `jQuery.Event` object will be passed + as the first argument to the method and an `Ember.View` object as the + second. The `Ember.View` will be the view whose rendered HTML was interacted + with. This may be the view with the `eventManager` property or one of its + descendent views. + + ```javascript + AView = Ember.View.extend({ + eventManager: Ember.Object.create({ + doubleClick: function(event, view) { + // will be called when when an instance's + // rendered element or any rendering + // of this views's descendent + // elements is clicked + } + }) + }); + ``` + + An event defined for an event manager takes precedence over events of the + same name handled through methods on the view. + + ```javascript + AView = Ember.View.extend({ + mouseEnter: function(event) { + // will never trigger. + }, + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // takes precedence over AView#mouseEnter + } + }) + }); + ``` + + Similarly a view's event manager will take precedence for events of any views + rendered as a descendent. A method name that matches an event name will not + be called if the view instance was rendered inside the HTML representation of + a view that has an `eventManager` property defined that handles events of the + name. Events not handled by the event manager will still trigger method calls + on the descendent. + + ```javascript + var App = Ember.Application.create(); + App.OuterView = Ember.View.extend({ + template: Ember.Handlebars.compile("outer {{#view 'inner'}}inner{{/view}} outer"), + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // view might be instance of either + // OuterView or InnerView depending on + // where on the page the user interaction occured + } + }) + }); + + App.InnerView = Ember.View.extend({ + click: function(event) { + // will be called if rendered inside + // an OuterView because OuterView's + // eventManager doesn't handle click events + }, + mouseEnter: function(event) { + // will never be called if rendered inside + // an OuterView. + } + }); + ``` + + ### Handlebars `{{action}}` Helper + + See [Handlebars.helpers.action](/api/classes/Ember.Handlebars.helpers.html#method_action). + + ### Event Names + + All of the event handling approaches described above respond to the same set + of events. The names of the built-in events are listed below. (The hash of + built-in events exists in `Ember.EventDispatcher`.) Additional, custom events + can be registered by using `Ember.Application.customEvents`. + + Touch events: + + * `touchStart` + * `touchMove` + * `touchEnd` + * `touchCancel` + + Keyboard events + + * `keyDown` + * `keyUp` + * `keyPress` + + Mouse events + + * `mouseDown` + * `mouseUp` + * `contextMenu` + * `click` + * `doubleClick` + * `mouseMove` + * `focusIn` + * `focusOut` + * `mouseEnter` + * `mouseLeave` + + Form events: + + * `submit` + * `change` + * `focusIn` + * `focusOut` + * `input` + + HTML5 drag and drop events: + + * `dragStart` + * `drag` + * `dragEnter` + * `dragLeave` + * `dragOver` + * `dragEnd` + * `drop` + + ## Handlebars `{{view}}` Helper + + Other `Ember.View` instances can be included as part of a view's template by + using the `{{view}}` Handlebars helper. See [Ember.Handlebars.helpers.view](/api/classes/Ember.Handlebars.helpers.html#method_view) + for additional information. + + @class View + @namespace Ember + @extends Ember.CoreView + */ + var View = CoreView.extend({ + + concatenatedProperties: ['classNames', 'classNameBindings', 'attributeBindings'], + + /** + @property isView + @type Boolean + @default true + @static + */ + isView: true, + + // .......................................................... + // TEMPLATE SUPPORT + // + + /** + The name of the template to lookup if no template is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property templateName + @type String + @default null + */ + templateName: null, + + /** + The name of the layout to lookup if no layout is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property layoutName + @type String + @default null + */ + layoutName: null, + + /** + Used to identify this view during debugging + + @property instrumentDisplay + @type String + */ + instrumentDisplay: computed(function() { + if (this.helperName) { + return '{{' + this.helperName + '}}'; + } + }), + + /** + The template used to render the view. This should be a function that + accepts an optional context parameter and returns a string of HTML that + will be inserted into the DOM relative to its parent view. + + In general, you should set the `templateName` property instead of setting + the template yourself. + + @property template + @type Function + */ + template: computed('templateName', function(key, value) { + if (value !== undefined) { return value; } + + var templateName = get(this, 'templateName'); + var template = this.templateForName(templateName, 'template'); + + Ember.assert("You specified the templateName " + templateName + " for " + this + ", but it did not exist.", !templateName || template); + + return template || get(this, 'defaultTemplate'); + }), + + /** + The controller managing this view. If this property is set, it will be + made available for use by the template. + + @property controller + @type Object + */ + controller: computed('_parentView', function(key) { + var parentView = get(this, '_parentView'); + return parentView ? get(parentView, 'controller') : null; + }), + + /** + A view may contain a layout. A layout is a regular template but + supersedes the `template` property during rendering. It is the + responsibility of the layout template to retrieve the `template` + property from the view (or alternatively, call `Handlebars.helpers.yield`, + `{{yield}}`) to render it in the correct location. + + This is useful for a view that has a shared wrapper, but which delegates + the rendering of the contents of the wrapper to the `template` property + on a subclass. + + @property layout + @type Function + */ + layout: computed(function(key) { + var layoutName = get(this, 'layoutName'); + var layout = this.templateForName(layoutName, 'layout'); + + Ember.assert("You specified the layoutName " + layoutName + " for " + this + ", but it did not exist.", !layoutName || layout); + + return layout || get(this, 'defaultLayout'); + }).property('layoutName'), + + _yield: function(context, options) { + var template = get(this, 'template'); + if (template) { template(context, options); } + }, + + templateForName: function(name, type) { + if (!name) { return; } + Ember.assert("templateNames are not allowed to contain periods: "+name, name.indexOf('.') === -1); + + if (!this.container) { + throw new EmberError('Container was not found when looking up a views template. ' + + 'This is most likely due to manually instantiating an Ember.View. ' + + 'See: http://git.io/EKPpnA'); + } + + return this.container.lookup('template:' + name); + }, + + /** + The object from which templates should access properties. + + This object will be passed to the template function each time the render + method is called, but it is up to the individual function to decide what + to do with it. + + By default, this will be the view's controller. + + @property context + @type Object + */ + context: computed(function(key, value) { + if (arguments.length === 2) { + set(this, '_context', value); + return value; + } else { + return get(this, '_context'); + } + })["volatile"](), + + /** + Private copy of the view's template context. This can be set directly + by Handlebars without triggering the observer that causes the view + to be re-rendered. + + The context of a view is looked up as follows: + + 1. Supplied context (usually by Handlebars) + 2. Specified controller + 3. `parentView`'s context (for a child of a ContainerView) + + The code in Handlebars that overrides the `_context` property first + checks to see whether the view has a specified controller. This is + something of a hack and should be revisited. + + @property _context + @private + */ + _context: computed(function(key) { + var parentView, controller; + + if (controller = get(this, 'controller')) { + return controller; + } + + parentView = this._parentView; + if (parentView) { + return get(parentView, '_context'); + } + + return null; + }), + + /** + If a value that affects template rendering changes, the view should be + re-rendered to reflect the new value. + + @method _contextDidChange + @private + */ + _contextDidChange: observer('context', function() { + this.rerender(); + }), + + /** + If `false`, the view will appear hidden in DOM. + + @property isVisible + @type Boolean + @default null + */ + isVisible: true, + + /** + Array of child views. You should never edit this array directly. + Instead, use `appendChild` and `removeFromParent`. + + @property childViews + @type Array + @default [] + @private + */ + childViews: childViewsProperty, + + _childViews: EMPTY_ARRAY, + + // When it's a virtual view, we need to notify the parent that their + // childViews will change. + _childViewsWillChange: beforeObserver('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { propertyWillChange(parentView, 'childViews'); } + } + }), + + // When it's a virtual view, we need to notify the parent that their + // childViews did change. + _childViewsDidChange: observer('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { propertyDidChange(parentView, 'childViews'); } + } + }), + + /** + Return the nearest ancestor that is an instance of the provided + class. + + @method nearestInstanceOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + @deprecated + */ + nearestInstanceOf: function(klass) { + Ember.deprecate("nearestInstanceOf is deprecated and will be removed from future releases. Use nearestOfType."); + var view = get(this, 'parentView'); + + while (view) { + if (view instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that is an instance of the provided + class or mixin. + + @method nearestOfType + @param {Class,Mixin} klass Subclass of Ember.View (or Ember.View itself), + or an instance of Ember.Mixin. + @return Ember.View + */ + nearestOfType: function(klass) { + var view = get(this, 'parentView'); + var isOfType = klass instanceof Mixin ? + function(view) { return klass.detect(view); } : + function(view) { return klass.detect(view.constructor); }; + + while (view) { + if (isOfType(view)) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that has a given property. + + @method nearestWithProperty + @param {String} property A property name + @return Ember.View + */ + nearestWithProperty: function(property) { + var view = get(this, 'parentView'); + + while (view) { + if (property in view) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor whose parent is an instance of + `klass`. + + @method nearestChildOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + */ + nearestChildOf: function(klass) { + var view = get(this, 'parentView'); + + while (view) { + if (get(view, 'parentView') instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + When the parent view changes, recursively invalidate `controller` + + @method _parentViewDidChange + @private + */ + _parentViewDidChange: observer('_parentView', function() { + if (this.isDestroying) { return; } + + this.trigger('parentViewDidChange'); + + if (get(this, 'parentView.controller') && !get(this, 'controller')) { + this.notifyPropertyChange('controller'); + } + }), + + _controllerDidChange: observer('controller', function() { + if (this.isDestroying) { return; } + + this.rerender(); + + this.forEachChildView(function(view) { + view.propertyDidChange('controller'); + }); + }), + + cloneKeywords: function() { + var templateData = get(this, 'templateData'); + + var keywords = templateData ? copy(templateData.keywords) : {}; + set(keywords, 'view', this.isVirtual ? keywords.view : this); + set(keywords, '_view', this); + set(keywords, 'controller', get(this, 'controller')); + + return keywords; + }, + + /** + Called on your view when it should push strings of HTML into a + `Ember.RenderBuffer`. Most users will want to override the `template` + or `templateName` properties instead of this method. + + By default, `Ember.View` will look for a function in the `template` + property and invoke it with the value of `context`. The value of + `context` will be the view's controller unless you override it. + + @method render + @param {Ember.RenderBuffer} buffer The render buffer + */ + render: function(buffer) { + // If this view has a layout, it is the responsibility of the + // the layout to render the view's template. Otherwise, render the template + // directly. + var template = get(this, 'layout') || get(this, 'template'); + + if (template) { + var context = get(this, 'context'); + var keywords = this.cloneKeywords(); + var output; + + var data = { + view: this, + buffer: buffer, + isRenderData: true, + keywords: keywords, + insideGroup: get(this, 'templateData.insideGroup') + }; + + // Invoke the template with the provided template context, which + // is the view's controller by default. A hash of data is also passed that provides + // the template with access to the view and render buffer. + + Ember.assert('template must be a function. Did you mean to call Ember.Handlebars.compile("...") or specify templateName instead?', typeof template === 'function'); + // The template should write directly to the render buffer instead + // of returning a string. + output = template(context, { data: data }); + + // If the template returned a string instead of writing to the buffer, + // push the string onto the buffer. + if (output !== undefined) { buffer.push(output); } + } + }, + + /** + Renders the view again. This will work regardless of whether the + view is already in the DOM or not. If the view is in the DOM, the + rendering process will be deferred to give bindings a chance + to synchronize. + + If children were added during the rendering process using `appendChild`, + `rerender` will remove them, because they will be added again + if needed by the next `render`. + + In general, if the display of your view changes, you should modify + the DOM element directly instead of manually calling `rerender`, which can + be slow. + + @method rerender + */ + rerender: function() { + return this.currentState.rerender(this); + }, + + /** + Iterates over the view's `classNameBindings` array, inserts the value + of the specified property into the `classNames` array, then creates an + observer to update the view's element if the bound property ever changes + in the future. + + @method _applyClassNameBindings + @private + */ + _applyClassNameBindings: function(classBindings) { + var classNames = this.classNames; + var elem, newClass, dasherizedClass; + + // Loop through all of the configured bindings. These will be either + // property names ('isUrgent') or property paths relative to the view + // ('content.isUrgent') + forEach(classBindings, function(binding) { + + Ember.assert("classNameBindings must not have spaces in them. Multiple class name bindings can be provided as elements of an array, e.g. ['foo', ':bar']", binding.indexOf(' ') === -1); + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + // Extract just the property name from bindings like 'foo:bar' + var parsedPath = View._parsePropertyPath(binding); + + // Set up an observer on the context. If the property changes, toggle the + // class name. + var observer = function() { + // Get the current value of the property + newClass = this._classStringForProperty(binding); + elem = this.$(); + + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + // Also remove from classNames so that if the view gets rerendered, + // the class doesn't get added back to the DOM. + classNames.removeObject(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + }; + + // Get the class name for the property at its current value + dasherizedClass = this._classStringForProperty(binding); + + if (dasherizedClass) { + // Ensure that it gets into the classNames array + // so it is displayed when we render. + addObject(classNames, dasherizedClass); + + // Save a reference to the class name so we can remove it + // if the observer fires. Remember that this variable has + // been closed over by the observer. + oldClass = dasherizedClass; + } + + this.registerObserver(this, parsedPath.path, observer); + // Remove className so when the view is rerendered, + // the className is added based on binding reevaluation + this.one('willClearRender', function() { + if (oldClass) { + classNames.removeObject(oldClass); + oldClass = null; + } + }); + + }, this); + }, + + _unspecifiedAttributeBindings: null, + + /** + Iterates through the view's attribute bindings, sets up observers for each, + then applies the current value of the attributes to the passed render buffer. + + @method _applyAttributeBindings + @param {Ember.RenderBuffer} buffer + @private + */ + _applyAttributeBindings: function(buffer, attributeBindings) { + var attributeValue; + var unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {}; + + forEach(attributeBindings, function(binding) { + var split = binding.split(':'); + var property = split[0]; + var attributeName = split[1] || property; + + if (property in this) { + this._setupAttributeBindingObservation(property, attributeName); + + // Determine the current value and add it to the render buffer + // if necessary. + attributeValue = get(this, property); + View.applyAttributeBindings(buffer, attributeName, attributeValue); + } else { + unspecifiedAttributeBindings[property] = attributeName; + } + }, this); + + // Lazily setup setUnknownProperty after attributeBindings are initially applied + this.setUnknownProperty = this._setUnknownProperty; + }, + + _setupAttributeBindingObservation: function(property, attributeName) { + var attributeValue, elem; + + // Create an observer to add/remove/change the attribute if the + // JavaScript property changes. + var observer = function() { + elem = this.$(); + + attributeValue = get(this, property); + + View.applyAttributeBindings(elem, attributeName, attributeValue); + }; + + this.registerObserver(this, property, observer); + }, + + /** + We're using setUnknownProperty as a hook to setup attributeBinding observers for + properties that aren't defined on a view at initialization time. + + Note: setUnknownProperty will only be called once for each property. + + @method setUnknownProperty + @param key + @param value + @private + */ + setUnknownProperty: null, // Gets defined after initialization by _applyAttributeBindings + + _setUnknownProperty: function(key, value) { + var attributeName = this._unspecifiedAttributeBindings && this._unspecifiedAttributeBindings[key]; + if (attributeName) { + this._setupAttributeBindingObservation(key, attributeName); + } + + defineProperty(this, key); + return set(this, key, value); + }, + + /** + Given a property name, returns a dasherized version of that + property name if the property evaluates to a non-falsy value. + + For example, if the view has property `isUrgent` that evaluates to true, + passing `isUrgent` to this method will return `"is-urgent"`. + + @method _classStringForProperty + @param property + @private + */ + _classStringForProperty: function(property) { + var parsedPath = View._parsePropertyPath(property); + var path = parsedPath.path; + + var val = get(this, path); + if (val === undefined && isGlobalPath(path)) { + val = get(Ember.lookup, path); + } + + return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }, + + // .......................................................... + // ELEMENT SUPPORT + // + + /** + Returns the current DOM element for the view. + + @property element + @type DOMElement + */ + element: null, + + /** + Returns a jQuery object for this view's element. If you pass in a selector + string, this method will return a jQuery object, using the current element + as its buffer. + + For example, calling `view.$('li')` will return a jQuery object containing + all of the `li` elements inside the DOM element of this view. + + @method $ + @param {String} [selector] a jQuery-compatible selector string + @return {jQuery} the jQuery object for the DOM node + */ + $: function(sel) { + return this.currentState.$(this, sel); + }, + + mutateChildViews: function(callback) { + var childViews = this._childViews; + var idx = childViews.length; + var view; + + while(--idx >= 0) { + view = childViews[idx]; + callback(this, view, idx); + } + + return this; + }, + + forEachChildView: function(callback) { + var childViews = this._childViews; + + if (!childViews) { return this; } + + var len = childViews.length; + var view, idx; + + for (idx = 0; idx < len; idx++) { + view = childViews[idx]; + callback(view); + } + + return this; + }, + + /** + Appends the view's element to the specified parent element. + + If the view does not have an HTML representation yet, `createElement()` + will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing. + + This is not typically a function that you will need to call directly when + building your application. You might consider using `Ember.ContainerView` + instead. If you do need to use `appendTo`, be sure that the target element + you are providing is associated with an `Ember.Application` and does not + have an ancestor element that is associated with an Ember view. + + @method appendTo + @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object + @return {Ember.View} receiver + */ + appendTo: function(selector) { + var target = jQuery(selector); + + Ember.assert("You tried to append to (" + selector + ") but that isn't in the DOM", target.length > 0); + Ember.assert("You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.", !target.is('.ember-view') && !target.parents().is('.ember-view')); + + this.constructor.renderer.appendTo(this, target[0]); + + return this; + }, + + /** + Replaces the content of the specified parent element with this view's + element. If the view does not have an HTML representation yet, + `createElement()` will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing + + @method replaceIn + @param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object + @return {Ember.View} received + */ + replaceIn: function(selector) { + var target = jQuery(selector); + + Ember.assert("You tried to replace in (" + selector + ") but that isn't in the DOM", target.length > 0); + Ember.assert("You cannot replace an existing Ember.View. Consider using Ember.ContainerView instead.", !target.is('.ember-view') && !target.parents().is('.ember-view')); + + this.constructor.renderer.replaceIn(this, target[0]); + + return this; + }, + + /** + Appends the view's element to the document body. If the view does + not have an HTML representation yet, `createElement()` will be called + automatically. + + If your application uses the `rootElement` property, you must append + the view within that element. Rendering views outside of the `rootElement` + is not supported. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the document body until all bindings have + finished synchronizing. + + @method append + @return {Ember.View} receiver + */ + append: function() { + return this.appendTo(document.body); + }, + + /** + Removes the view's element from the element to which it is attached. + + @method remove + @return {Ember.View} receiver + */ + remove: function() { + // What we should really do here is wait until the end of the run loop + // to determine if the element has been re-appended to a different + // element. + // In the interim, we will just re-render if that happens. It is more + // important than elements get garbage collected. + if (!this.removedFromDOM) { this.destroyElement(); } + }, + + elementId: null, + + /** + Attempts to discover the element in the parent element. The default + implementation looks for an element with an ID of `elementId` (or the + view's guid if `elementId` is null). You can override this method to + provide your own form of lookup. For example, if you want to discover your + element using a CSS class name instead of an ID. + + @method findElementInParentElement + @param {DOMElement} parentElement The parent's DOM element + @return {DOMElement} The discovered element + */ + findElementInParentElement: function(parentElem) { + var id = "#" + this.elementId; + return jQuery(id)[0] || jQuery(id, parentElem)[0]; + }, + + /** + Creates a DOM representation of the view and all of its child views by + recursively calling the `render()` method. + + After the element has been inserted into the DOM, `didInsertElement` will + be called on this view and all of its child views. + + @method createElement + @return {Ember.View} receiver + */ + createElement: function() { + if (this.element) { return this; } + + this._didCreateElementWithoutMorph = true; + this.constructor.renderer.renderTree(this); + + return this; + }, + + /** + Called when a view is going to insert an element into the DOM. + + @event willInsertElement + */ + willInsertElement: Ember.K, + + /** + Called when the element of the view has been inserted into the DOM + or after the view was re-rendered. Override this function to do any + set up that requires an element in the document body. + + When a view has children, didInsertElement will be called on the + child view(s) first, bubbling upwards through the hierarchy. + + @event didInsertElement + */ + didInsertElement: Ember.K, + + /** + Called when the view is about to rerender, but before anything has + been torn down. This is a good opportunity to tear down any manual + observers you have installed based on the DOM state + + @event willClearRender + */ + willClearRender: Ember.K, + + /** + Destroys any existing element along with the element for any child views + as well. If the view does not currently have a element, then this method + will do nothing. + + If you implement `willDestroyElement()` on your view, then this method will + be invoked on your view before your element is destroyed to give you a + chance to clean up any event handlers, etc. + + If you write a `willDestroyElement()` handler, you can assume that your + `didInsertElement()` handler was called earlier for the same element. + + You should not call or override this method yourself, but you may + want to implement the above callbacks. + + @method destroyElement + @return {Ember.View} receiver + */ + destroyElement: function() { + return this.currentState.destroyElement(this); + }, + + /** + Called when the element of the view is going to be destroyed. Override + this function to do any teardown that requires an element, like removing + event listeners. + + Please note: any property changes made during this event will have no + effect on object observers. + + @event willDestroyElement + */ + willDestroyElement: Ember.K, + + /** + Called when the parentView property has changed. + + @event parentViewDidChange + */ + parentViewDidChange: Ember.K, + + instrumentName: 'view', + + instrumentDetails: function(hash) { + hash.template = get(this, 'templateName'); + this._super(hash); + }, + + beforeRender: function(buffer) {}, + + afterRender: function(buffer) {}, + + applyAttributesToBuffer: function(buffer) { + // Creates observers for all registered class name and attribute bindings, + // then adds them to the element. + var classNameBindings = get(this, 'classNameBindings'); + if (classNameBindings.length) { + this._applyClassNameBindings(classNameBindings); + } + + // Pass the render buffer so the method can apply attributes directly. + // This isn't needed for class name bindings because they use the + // existing classNames infrastructure. + var attributeBindings = get(this, 'attributeBindings'); + if (attributeBindings.length) { + this._applyAttributeBindings(buffer, attributeBindings); + } + + buffer.setClasses(this.classNames); + buffer.id(this.elementId); + + var role = get(this, 'ariaRole'); + if (role) { + buffer.attr('role', role); + } + + if (get(this, 'isVisible') === false) { + buffer.style('display', 'none'); + } + }, + + // .......................................................... + // STANDARD RENDER PROPERTIES + // + + /** + Tag name for the view's outer element. The tag name is only used when an + element is first created. If you change the `tagName` for an element, you + must destroy and recreate the view element. + + By default, the render buffer will use a `
    ` tag for views. + + @property tagName + @type String + @default null + */ + + // We leave this null by default so we can tell the difference between + // the default case and a user-specified tag. + tagName: null, + + /** + The WAI-ARIA role of the control represented by this view. For example, a + button may have a role of type 'button', or a pane may have a role of + type 'alertdialog'. This property is used by assistive software to help + visually challenged users navigate rich web applications. + + The full list of valid WAI-ARIA roles is available at: + [http://www.w3.org/TR/wai-aria/roles#roles_categorization](http://www.w3.org/TR/wai-aria/roles#roles_categorization) + + @property ariaRole + @type String + @default null + */ + ariaRole: null, + + /** + Standard CSS class names to apply to the view's outer element. This + property automatically inherits any class names defined by the view's + superclasses as well. + + @property classNames + @type Array + @default ['ember-view'] + */ + classNames: ['ember-view'], + + /** + A list of properties of the view to apply as class names. If the property + is a string value, the value of that string will be applied as a class + name. + + ```javascript + // Applies the 'high' class to the view element + Ember.View.extend({ + classNameBindings: ['priority'] + priority: 'high' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as a dasherized class name. + + ```javascript + // Applies the 'is-urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent'] + isUrgent: true + }); + ``` + + If you would prefer to use a custom value instead of the dasherized + property name, you can pass a binding like this: + + ```javascript + // Applies the 'urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent:urgent'] + isUrgent: true + }); + ``` + + This list of properties is inherited from the view's superclasses as well. + + @property classNameBindings + @type Array + @default [] + */ + classNameBindings: EMPTY_ARRAY, + + /** + A list of properties of the view to apply as attributes. If the property is + a string value, the value of that string will be applied as the attribute. + + ```javascript + // Applies the type attribute to the element + // with the value "button", like
    + Ember.View.extend({ + attributeBindings: ['type'], + type: 'button' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as an attribute. + + ```javascript + // Renders something like
    + Ember.View.extend({ + attributeBindings: ['enabled'], + enabled: true + }); + ``` + + @property attributeBindings + */ + attributeBindings: EMPTY_ARRAY, + + // ....................................................... + // CORE DISPLAY METHODS + // + + /** + Setup a view, but do not finish waking it up. + + * configure `childViews` + * register the view with the global views hash, which is used for event + dispatch + + @method init + @private + */ + init: function() { + if (!this.isVirtual && !this.elementId) { + this.elementId = guidFor(this); + } + + this._super(); + + // setup child views. be sure to clone the child views array first + this._childViews = this._childViews.slice(); + + Ember.assert("Only arrays are allowed for 'classNameBindings'", typeOf(this.classNameBindings) === 'array'); + this.classNameBindings = emberA(this.classNameBindings.slice()); + + Ember.assert("Only arrays are allowed for 'classNames'", typeOf(this.classNames) === 'array'); + this.classNames = emberA(this.classNames.slice()); + }, + + appendChild: function(view, options) { + return this.currentState.appendChild(this, view, options); + }, + + /** + Removes the child view from the parent view. + + @method removeChild + @param {Ember.View} view + @return {Ember.View} receiver + */ + removeChild: function(view) { + // If we're destroying, the entire subtree will be + // freed, and the DOM will be handled separately, + // so no need to mess with childViews. + if (this.isDestroying) { return; } + + // update parent node + set(view, '_parentView', null); + + // remove view from childViews array. + var childViews = this._childViews; + + removeObject(childViews, view); + + this.propertyDidChange('childViews'); // HUH?! what happened to will change? + + return this; + }, + + /** + Removes all children from the `parentView`. + + @method removeAllChildren + @return {Ember.View} receiver + */ + removeAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + parentView.removeChild(view); + }); + }, + + destroyAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + view.destroy(); + }); + }, + + /** + Removes the view from its `parentView`, if one is found. Otherwise + does nothing. + + @method removeFromParent + @return {Ember.View} receiver + */ + removeFromParent: function() { + var parent = this._parentView; + + // Remove DOM element from parent + this.remove(); + + if (parent) { parent.removeChild(this); } + return this; + }, + + /** + You must call `destroy` on a view to destroy the view (and all of its + child views). This will remove the view from any parent node, then make + sure that the DOM element managed by the view can be released by the + memory manager. + + @method destroy + */ + destroy: function() { + var childViews = this._childViews; + // get parentView before calling super because it'll be destroyed + var nonVirtualParentView = get(this, 'parentView'); + var viewName = this.viewName; + var childLen, i; + + if (!this._super()) { return; } + + // remove from non-virtual parent view if viewName was specified + if (viewName && nonVirtualParentView) { + nonVirtualParentView.set(viewName, null); + } + + return this; + }, + + /** + Instantiates a view to be added to the childViews array during view + initialization. You generally will not call this method directly unless + you are overriding `createChildViews()`. Note that this method will + automatically configure the correct settings on the new view instance to + act as a child of the parent. + + @method createChildView + @param {Class|String} viewClass + @param {Hash} [attrs] Attributes to add + @return {Ember.View} new instance + */ + createChildView: function(view, attrs) { + if (!view) { + throw new TypeError("createChildViews first argument must exist"); + } + + if (view.isView && view._parentView === this && view.container === this.container) { + return view; + } + + attrs = attrs || {}; + attrs._parentView = this; + + if (CoreView.detect(view)) { + attrs.templateData = attrs.templateData || get(this, 'templateData'); + + attrs.container = this.container; + view = view.create(attrs); + + // don't set the property on a virtual view, as they are invisible to + // consumers of the view API + if (view.viewName) { + set(get(this, 'concreteView'), view.viewName, view); + } + } else if ('string' === typeof view) { + var fullName = 'view:' + view; + var ViewKlass = this.container.lookupFactory(fullName); + + Ember.assert("Could not find view: '" + fullName + "'", !!ViewKlass); + + attrs.templateData = get(this, 'templateData'); + view = ViewKlass.create(attrs); + } else { + Ember.assert('You must pass instance or subclass of View', view.isView); + attrs.container = this.container; + + if (!get(view, 'templateData')) { + attrs.templateData = get(this, 'templateData'); + } + + setProperties(view, attrs); + + } + + return view; + }, + + becameVisible: Ember.K, + becameHidden: Ember.K, + + /** + When the view's `isVisible` property changes, toggle the visibility + element of the actual DOM element. + + @method _isVisibleDidChange + @private + */ + _isVisibleDidChange: observer('isVisible', function() { + if (this._isVisible === get(this, 'isVisible')) { return ; } + run.scheduleOnce('render', this, this._toggleVisibility); + }), + + _toggleVisibility: function() { + var $el = this.$(); + var isVisible = get(this, 'isVisible'); + + if (this._isVisible === isVisible) { return ; } + + // It's important to keep these in sync, even if we don't yet have + // an element in the DOM to manipulate: + this._isVisible = isVisible; + + if (!$el) { return; } + + $el.toggle(isVisible); + + if (this._isAncestorHidden()) { return; } + + if (isVisible) { + this._notifyBecameVisible(); + } else { + this._notifyBecameHidden(); + } + }, + + _notifyBecameVisible: function() { + this.trigger('becameVisible'); + + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameVisible(); + } + }); + }, + + _notifyBecameHidden: function() { + this.trigger('becameHidden'); + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameHidden(); + } + }); + }, + + _isAncestorHidden: function() { + var parent = get(this, 'parentView'); + + while (parent) { + if (get(parent, 'isVisible') === false) { return true; } + + parent = get(parent, 'parentView'); + } + + return false; + }, + transitionTo: function(state, children) { + Ember.deprecate("Ember.View#transitionTo has been deprecated, it is for internal use only"); + this._transitionTo(state, children); + }, + _transitionTo: function(state, children) { + var priorState = this.currentState; + var currentState = this.currentState = this._states[state]; + this._state = state; + + if (priorState && priorState.exit) { priorState.exit(this); } + if (currentState.enter) { currentState.enter(this); } + }, + + // ....................................................... + // EVENT HANDLING + // + + /** + Handle events from `Ember.EventDispatcher` + + @method handleEvent + @param eventName {String} + @param evt {Event} + @private + */ + handleEvent: function(eventName, evt) { + return this.currentState.handleEvent(this, eventName, evt); + }, + + registerObserver: function(root, path, target, observer) { + if (!observer && 'function' === typeof target) { + observer = target; + target = null; + } + + if (!root || typeof root !== 'object') { + return; + } + + var view = this; + var stateCheckedObserver = function() { + view.currentState.invokeObserver(this, observer); + }; + var scheduledObserver = function() { + run.scheduleOnce('render', this, stateCheckedObserver); + }; + + addObserver(root, path, target, scheduledObserver); + + this.one('willClearRender', function() { + removeObserver(root, path, target, scheduledObserver); + }); + } + + }); + deprecateProperty(View.prototype, 'state', '_state'); + deprecateProperty(View.prototype, 'states', '_states'); + + /* + Describe how the specified actions should behave in the various + states that a view can exist in. Possible states: + + * preRender: when a view is first instantiated, and after its + element was destroyed, it is in the preRender state + * inBuffer: once a view has been rendered, but before it has + been inserted into the DOM, it is in the inBuffer state + * hasElement: the DOM representation of the view is created, + and is ready to be inserted + * inDOM: once a view has been inserted into the DOM it is in + the inDOM state. A view spends the vast majority of its + existence in this state. + * destroyed: once a view has been destroyed (using the destroy + method), it is in this state. No further actions can be invoked + on a destroyed view. + */ + + // in the destroyed state, everything is illegal + + // before rendering has begun, all legal manipulations are noops. + + // inside the buffer, legal manipulations are done on the buffer + + // once the view has been inserted into the DOM, legal manipulations + // are done on the DOM element. + + function notifyMutationListeners() { + run.once(View, 'notifyMutationListeners'); + } + + View.reopenClass({ + + /** + Parse a path and return an object which holds the parsed properties. + + For example a path like "content.isEnabled:enabled:disabled" will return the + following object: + + ```javascript + { + path: "content.isEnabled", + className: "enabled", + falsyClassName: "disabled", + classNames: ":enabled:disabled" + } + ``` + + @method _parsePropertyPath + @static + @private + */ + _parsePropertyPath: function(path) { + var split = path.split(':'); + var propertyPath = split[0]; + var classNames = ""; + var className, falsyClassName; + + // check if the property is defined as prop:class or prop:trueClass:falseClass + if (split.length > 1) { + className = split[1]; + if (split.length === 3) { falsyClassName = split[2]; } + + classNames = ':' + className; + if (falsyClassName) { classNames += ":" + falsyClassName; } + } + + return { + path: propertyPath, + classNames: classNames, + className: (className === '') ? undefined : className, + falsyClassName: falsyClassName + }; + }, + + /** + Get the class name for a given value, based on the path, optional + `className` and optional `falsyClassName`. + + - if a `className` or `falsyClassName` has been specified: + - if the value is truthy and `className` has been specified, + `className` is returned + - if the value is falsy and `falsyClassName` has been specified, + `falsyClassName` is returned + - otherwise `null` is returned + - if the value is `true`, the dasherized last part of the supplied path + is returned + - if the value is not `false`, `undefined` or `null`, the `value` + is returned + - if none of the above rules apply, `null` is returned + + @method _classStringForValue + @param path + @param val + @param className + @param falsyClassName + @static + @private + */ + _classStringForValue: function(path, val, className, falsyClassName) { + if(isArray(val)) { + val = get(val, 'length') !== 0; + } + + // When using the colon syntax, evaluate the truthiness or falsiness + // of the value to determine which className to return + if (className || falsyClassName) { + if (className && !!val) { + return className; + + } else if (falsyClassName && !val) { + return falsyClassName; + + } else { + return null; + } + + // If value is a Boolean and true, return the dasherized property + // name. + } else if (val === true) { + // Normalize property path to be suitable for use + // as a class name. For exaple, content.foo.barBaz + // becomes bar-baz. + var parts = path.split('.'); + return dasherize(parts[parts.length-1]); + + // If the value is not false, undefined, or null, return the current + // value of the property. + } else if (val !== false && val != null) { + return val; + + // Nothing to display. Return null so that the old class is removed + // but no new class is added. + } else { + return null; + } + } + }); + + var mutation = EmberObject.extend(Evented).create(); + // TODO MOVE TO RENDERER HOOKS + View.addMutationListener = function(callback) { + mutation.on('change', callback); + }; + + View.removeMutationListener = function(callback) { + mutation.off('change', callback); + }; + + View.notifyMutationListeners = function() { + mutation.trigger('change'); + }; + + /** + Global views hash + + @property views + @static + @type Hash + */ + View.views = {}; + + // If someone overrides the child views computed property when + // defining their class, we want to be able to process the user's + // supplied childViews and then restore the original computed property + // at view initialization time. This happens in Ember.ContainerView's init + // method. + View.childViewsProperty = childViewsProperty; + + View.applyAttributeBindings = function(elem, name, value) { + var type = typeOf(value); + + // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js + if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) { + if (value !== elem.attr(name)) { + elem.attr(name, value); + } + } else if (name === 'value' || type === 'boolean') { + if (isNone(value) || value === false) { + // `null`, `undefined` or `false` should remove attribute + elem.removeAttr(name); + // In IE8 `prop` couldn't remove attribute when name is `required`. + if (name === 'required') { + elem.removeProp(name); + } else { + elem.prop(name, ''); + } + } else if (value !== elem.prop(name)) { + // value should always be properties + elem.prop(name, value); + } + } else if (!value) { + elem.removeAttr(name); + } + }; + + __exports__["default"] = View; + }); +define("ember", + ["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { + "use strict"; + /* global navigator */ + // require the main entry points for each of these packages + // this is so that the global exports occur properly + + // do this to ensure that Ember.Test is defined properly on the global + // if it is present. + if (Ember.__loader.registry['ember-testing']) { + requireModule('ember-testing'); + } + + /** + Ember + + @module ember + */ + + Ember.deprecate('Usage of Ember is deprecated for Internet Explorer 6 and 7, support will be removed in the next major version.', !navigator.userAgent.match(/MSIE [67]/)); + }); +define("morph", + ["./morph/morph","./morph/dom-helper","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Morph = __dependency1__["default"]; + var Morph; + __exports__.Morph = Morph; + var DOMHelper = __dependency2__["default"]; + var DOMHelper; + __exports__.DOMHelper = DOMHelper; + }); +define("morph/dom-helper", + ["../morph/morph","./dom-helper/build-html-dom","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Morph = __dependency1__["default"]; + var buildHTMLDOM = __dependency2__.buildHTMLDOM; + var svgNamespace = __dependency2__.svgNamespace; + var svgHTMLIntegrationPoints = __dependency2__.svgHTMLIntegrationPoints; + + var deletesBlankTextNodes = (function(){ + var element = document.createElement('div'); + element.appendChild( document.createTextNode('') ); + var clonedElement = element.cloneNode(true); + return clonedElement.childNodes.length === 0; + })(); + + var ignoresCheckedAttribute = (function(){ + var element = document.createElement('input'); + element.setAttribute('checked', 'checked'); + var clonedElement = element.cloneNode(false); + return !clonedElement.checked; + })(); + + function isSVG(ns){ + return ns === svgNamespace; + } + + // This is not the namespace of the element, but of + // the elements inside that elements. + function interiorNamespace(element){ + if ( + element && + element.namespaceURI === svgNamespace && + !svgHTMLIntegrationPoints[element.tagName] + ) { + return svgNamespace; + } else { + return null; + } + } + + // The HTML spec allows for "omitted start tags". These tags are optional + // when their intended child is the first thing in the parent tag. For + // example, this is a tbody start tag: + // + //
    + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
    + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup. + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags + // describes which tags are omittable. The spec for tbody and colgroup + // explains this behavior: + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element + // + + var omittedStartTagChildTest = /<([\w:]+)/; + function detectOmittedStartTag(string, contextualElement){ + // Omitted start tags are only inside table tags. + if (contextualElement.tagName === 'TABLE') { + var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); + if (omittedStartTagChildMatch) { + var omittedStartTagChild = omittedStartTagChildMatch[1]; + // It is already asserted that the contextual element is a table + // and not the proper start tag. Just see if a tag was omitted. + return omittedStartTagChild === 'tr' || + omittedStartTagChild === 'col'; + } + } + } + + function buildSVGDOM(html, dom){ + var div = dom.document.createElement('div'); + div.innerHTML = ''+html+''; + return div.firstChild.childNodes; + } + + /* + * A class wrapping DOM functions to address environment compatibility, + * namespaces, contextual elements for morph un-escaped content + * insertion. + * + * When entering a template, a DOMHelper should be passed: + * + * template(context, { hooks: hooks, dom: new DOMHelper() }); + * + * TODO: support foreignObject as a passed contextual element. It has + * a namespace (svg) that does not match its internal namespace + * (xhtml). + * + * @class DOMHelper + * @constructor + * @param {HTMLDocument} _document The document DOM methods are proxied to + */ + function DOMHelper(_document){ + this.document = _document || window.document; + this.namespace = null; + } + + var prototype = DOMHelper.prototype; + prototype.constructor = DOMHelper; + + prototype.insertBefore = function(element, childElement, referenceChild) { + return element.insertBefore(childElement, referenceChild); + }; + + prototype.appendChild = function(element, childElement) { + return element.appendChild(childElement); + }; + + prototype.appendText = function(element, text) { + return element.appendChild(this.document.createTextNode(text)); + }; + + prototype.setAttribute = function(element, name, value) { + element.setAttribute(name, value); + }; + + if (document.createElementNS) { + // Only opt into namespace detection if a contextualElement + // is passed. + prototype.createElement = function(tagName, contextualElement) { + var namespace = this.namespace; + if (contextualElement) { + if (tagName === 'svg') { + namespace = svgNamespace; + } else { + namespace = interiorNamespace(contextualElement); + } + } + if (namespace) { + return this.document.createElementNS(namespace, tagName); + } else { + return this.document.createElement(tagName); + } + }; + } else { + prototype.createElement = function(tagName) { + return this.document.createElement(tagName); + }; + } + + prototype.setNamespace = function(ns) { + this.namespace = ns; + }; + + prototype.detectNamespace = function(element) { + this.namespace = interiorNamespace(element); + }; + + prototype.createDocumentFragment = function(){ + return this.document.createDocumentFragment(); + }; + + prototype.createTextNode = function(text){ + return this.document.createTextNode(text); + }; + + prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ + if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { + for (var i=0, len=blankChildTextNodes.length;i]*)>", 'i'))[0]; + var endTag = ''; + + var wrappedHTML = [startTag, html, endTag]; + + var i = wrappingTags.length; + var wrappedDepth = 1 + i; + while(i--) { + wrappedHTML.unshift('<'+wrappingTags[i]+'>'); + wrappedHTML.push(''); + } + + var wrapper = document.createElement('div'); + scriptSafeInnerHTML(wrapper, wrappedHTML.join('')); + var element = wrapper; + while (wrappedDepth--) { + element = element.firstChild; + while (element && element.nodeType !== 1) { + element = element.nextSibling; + } + } + while (element && element.tagName !== tagName) { + element = element.nextSibling; + } + return element ? element.childNodes : []; + } + + var buildDOM; + if (needsShy) { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + scriptSafeInnerHTML(contextualElement, html); + return contextualElement.childNodes; + }; + } else { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + contextualElement.innerHTML = html; + return contextualElement.childNodes; + }; + } + + + var buildHTMLDOM; + // Really, this just means IE8 and IE9 get a slower buildHTMLDOM + if (tagNamesRequiringInnerHTMLFix.length > 0 || movesWhitespace) { + buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom) { + // Make a list of the leading text on script nodes. Include + // script tags without any whitespace for easier processing later. + var spacesBefore = []; + var spacesAfter = []; + html = html.replace(/(\s*)()(\s*)/g, function(match, tag, spaces) { + spacesAfter.push(spaces); + return tag; + }); + + // Fetch nodes + var nodes; + if (tagNamesRequiringInnerHTMLFix[contextualElement.tagName.toLowerCase()]) { + // buildDOMWithFix uses string wrappers for problematic innerHTML. + nodes = buildDOMWithFix(html, contextualElement); + } else { + nodes = buildDOM(html, contextualElement, dom); + } + + // Build a list of script tags, the nodes themselves will be + // mutated as we add test nodes. + var i, j, node, nodeScriptNodes; + var scriptNodes = []; + for (i=0;node=nodes[i];i++) { + if (node.nodeType !== 1) { + continue; + } + if (node.tagName === 'SCRIPT') { + scriptNodes.push(node); + } else { + nodeScriptNodes = node.getElementsByTagName('script'); + for (j=0;j 0) { + textNode = dom.document.createTextNode(spaceBefore); + scriptNode.parentNode.insertBefore(textNode, scriptNode); + } + + spaceAfter = spacesAfter[i]; + if (spaceAfter && spaceAfter.length > 0) { + textNode = dom.document.createTextNode(spaceAfter); + scriptNode.parentNode.insertBefore(textNode, scriptNode.nextSibling); + } + } + + return nodes; + }; + } else if (needsIntegrationPointFix) { + buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom){ + if (svgHTMLIntegrationPoints[contextualElement.tagName]) { + return buildDOM(html, document.createElement('div'), dom); + } else { + return buildDOM(html, contextualElement, dom); + } + }; + } else { + buildHTMLDOM = buildDOM; + } + + __exports__.buildHTMLDOM = buildHTMLDOM; + }); +define("morph/morph", + ["exports"], + function(__exports__) { + "use strict"; + var splice = Array.prototype.splice; + + function ensureStartEnd(start, end) { + if (start === null || end === null) { + throw new Error('a fragment parent must have boundary nodes in order to detect insertion'); + } + } + + function ensureContext(contextualElement) { + if (!contextualElement || contextualElement.nodeType !== 1) { + throw new Error('An element node must be provided for a contextualElement, you provided ' + + (contextualElement ? 'nodeType ' + contextualElement.nodeType : 'nothing')); + } + } + + // TODO: this is an internal API, this should be an assert + function Morph(parent, start, end, domHelper, contextualElement) { + if (parent.nodeType === 11) { + ensureStartEnd(start, end); + this.element = null; + } else { + this.element = parent; + } + this._parent = parent; + this.start = start; + this.end = end; + this.domHelper = domHelper; + ensureContext(contextualElement); + this.contextualElement = contextualElement; + this.reset(); + } + + Morph.prototype.reset = function() { + this.text = null; + this.owner = null; + this.morphs = null; + this.before = null; + this.after = null; + this.escaped = true; + }; + + Morph.prototype.parent = function () { + if (!this.element) { + var parent = this.start.parentNode; + if (this._parent !== parent) { + this.element = this._parent = parent; + } + } + return this._parent; + }; + + Morph.prototype.destroy = function () { + if (this.owner) { + this.owner.removeMorph(this); + } else { + clear(this.element || this.parent(), this.start, this.end); + } + }; + + Morph.prototype.removeMorph = function (morph) { + var morphs = this.morphs; + for (var i=0, l=morphs.length; i 0 ? morphs[index-1] : null; + var after = index < morphs.length ? morphs[index] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var morph = new Morph(parent, start, end, this.domHelper, this.contextualElement); + + morph.owner = this; + morph._update(parent, node); + + if (before !== null) { + morph.before = before; + before.end = start.nextSibling; + before.after = morph; + } + + if (after !== null) { + morph.after = after; + after.before = morph; + after.start = end.previousSibling; + } + + this.morphs.splice(index, 0, morph); + return morph; + }; + + Morph.prototype.replace = function (index, removedLength, addedNodes) { + if (this.morphs === null) this.morphs = []; + var parent = this.element || this.parent(); + var morphs = this.morphs; + var before = index > 0 ? morphs[index-1] : null; + var after = index+removedLength < morphs.length ? morphs[index+removedLength] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var addedLength = addedNodes === undefined ? 0 : addedNodes.length; + var args, i, current; + + if (removedLength > 0) { + clear(parent, start, end); + } + + if (addedLength === 0) { + if (before !== null) { + before.after = after; + before.end = end; + } + if (after !== null) { + after.before = before; + after.start = start; + } + morphs.splice(index, removedLength); + return; + } + + args = new Array(addedLength+2); + if (addedLength > 0) { + for (i=0; i " + n.nextStates.map(function(s) { return s.debug() }).join(" or ") + " )"; + }).join(", ") + } + END IF **/ + + // This is a somewhat naive strategy, but should work in a lot of cases + // A better strategy would properly resolve /posts/:id/new and /posts/edit/:id. + // + // This strategy generally prefers more static and less dynamic matching. + // Specifically, it + // + // * prefers fewer stars to more, then + // * prefers using stars for less of the match to more, then + // * prefers fewer dynamic segments to more, then + // * prefers more static segments to more + function sortSolutions(states) { + return states.sort(function(a, b) { + if (a.types.stars !== b.types.stars) { return a.types.stars - b.types.stars; } + + if (a.types.stars) { + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } + if (a.types.dynamics !== b.types.dynamics) { return b.types.dynamics - a.types.dynamics; } + } + + if (a.types.dynamics !== b.types.dynamics) { return a.types.dynamics - b.types.dynamics; } + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } + + return 0; + }); + } + + function recognizeChar(states, ch) { + var nextStates = []; + + for (var i=0, l=states.length; i 2 && key.slice(keyLength -2) === '[]') { + isArray = true; + key = key.slice(0, keyLength - 2); + if(!queryParams[key]) { + queryParams[key] = []; + } + } + value = pair[1] ? decodeURIComponent(pair[1]) : ''; + } + if (isArray) { + queryParams[key].push(value); + } else { + queryParams[key] = value; + } + } + return queryParams; + }, + + recognize: function(path) { + var states = [ this.rootState ], + pathLen, i, l, queryStart, queryParams = {}, + isSlashDropped = false; + + queryStart = path.indexOf('?'); + if (queryStart !== -1) { + var queryString = path.substr(queryStart + 1, path.length); + path = path.substr(0, queryStart); + queryParams = this.parseQueryString(queryString); + } + + path = decodeURI(path); + + // DEBUG GROUP path + + if (path.charAt(0) !== "/") { path = "/" + path; } + + pathLen = path.length; + if (pathLen > 1 && path.charAt(pathLen - 1) === "/") { + path = path.substr(0, pathLen - 1); + isSlashDropped = true; + } + + for (i=0, l=path.length; i= 0 && proceed; --i) { + var route = routes[i]; + recognizer.add(routes, { as: route.handler }); + proceed = route.path === '/' || route.path === '' || route.handler.slice(-6) === '.index'; + } + }); + }, + + hasRoute: function(route) { + return this.recognizer.hasRoute(route); + }, + + queryParamsTransition: function(changelist, wasTransitioning, oldState, newState) { + var router = this; + + fireQueryParamDidChange(this, newState, changelist); + + if (!wasTransitioning && this.activeTransition) { + // One of the handlers in queryParamsDidChange + // caused a transition. Just return that transition. + return this.activeTransition; + } else { + // Running queryParamsDidChange didn't change anything. + // Just update query params and be on our way. + + // We have to return a noop transition that will + // perform a URL update at the end. This gives + // the user the ability to set the url update + // method (default is replaceState). + var newTransition = new Transition(this); + newTransition.queryParamsOnly = true; + + oldState.queryParams = finalizeQueryParamChange(this, newState.handlerInfos, newState.queryParams, newTransition); + + newTransition.promise = newTransition.promise.then(function(result) { + updateURL(newTransition, oldState, true); + if (router.didTransition) { + router.didTransition(router.currentHandlerInfos); + } + return result; + }, null, promiseLabel("Transition complete")); + return newTransition; + } + }, + + // NOTE: this doesn't really belong here, but here + // it shall remain until our ES6 transpiler can + // handle cyclical deps. + transitionByIntent: function(intent, isIntermediate) { + try { + return getTransitionByIntent.apply(this, arguments); + } catch(e) { + return new Transition(this, intent, null, e); + } + }, + + /** + Clears the current and target route handlers and triggers exit + on each of them starting at the leaf and traversing up through + its ancestors. + */ + reset: function() { + if (this.state) { + forEach(this.state.handlerInfos.slice().reverse(), function(handlerInfo) { + var handler = handlerInfo.handler; + callHook(handler, 'exit'); + }); + } + + this.state = new TransitionState(); + this.currentHandlerInfos = null; + }, + + activeTransition: null, + + /** + var handler = handlerInfo.handler; + The entry point for handling a change to the URL (usually + via the back and forward button). + + Returns an Array of handlers and the parameters associated + with those parameters. + + @param {String} url a URL to process + + @return {Array} an Array of `[handler, parameter]` tuples + */ + handleURL: function(url) { + // Perform a URL-based transition, but don't change + // the URL afterward, since it already happened. + var args = slice.call(arguments); + if (url.charAt(0) !== '/') { args[0] = '/' + url; } + + return doTransition(this, args).method(null); + }, + + /** + Hook point for updating the URL. + + @param {String} url a URL to update to + */ + updateURL: function() { + throw new Error("updateURL is not implemented"); + }, + + /** + Hook point for replacing the current URL, i.e. with replaceState + + By default this behaves the same as `updateURL` + + @param {String} url a URL to update to + */ + replaceURL: function(url) { + this.updateURL(url); + }, + + /** + Transition into the specified named route. + + If necessary, trigger the exit callback on any handlers + that are no longer represented by the target route. + + @param {String} name the name of the route + */ + transitionTo: function(name) { + return doTransition(this, arguments); + }, + + intermediateTransitionTo: function(name) { + return doTransition(this, arguments, true); + }, + + refresh: function(pivotHandler) { + var state = this.activeTransition ? this.activeTransition.state : this.state; + var handlerInfos = state.handlerInfos; + var params = {}; + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + params[handlerInfo.name] = handlerInfo.params || {}; + } + + log(this, "Starting a refresh transition"); + var intent = new NamedTransitionIntent({ + name: handlerInfos[handlerInfos.length - 1].name, + pivotHandler: pivotHandler || handlerInfos[0].handler, + contexts: [], // TODO collect contexts...? + queryParams: this._changedQueryParams || state.queryParams || {} + }); + + return this.transitionByIntent(intent, false); + }, + + /** + Identical to `transitionTo` except that the current URL will be replaced + if possible. + + This method is intended primarily for use with `replaceState`. + + @param {String} name the name of the route + */ + replaceWith: function(name) { + return doTransition(this, arguments).method('replace'); + }, + + /** + Take a named route and context objects and generate a + URL. + + @param {String} name the name of the route to generate + a URL for + @param {...Object} objects a list of objects to serialize + + @return {String} a URL + */ + generate: function(handlerName) { + + var partitionedArgs = extractQueryParams(slice.call(arguments, 1)), + suppliedParams = partitionedArgs[0], + queryParams = partitionedArgs[1]; + + // Construct a TransitionIntent with the provided params + // and apply it to the present state of the router. + var intent = new NamedTransitionIntent({ name: handlerName, contexts: suppliedParams }); + var state = intent.applyToState(this.state, this.recognizer, this.getHandler); + var params = {}; + + for (var i = 0, len = state.handlerInfos.length; i < len; ++i) { + var handlerInfo = state.handlerInfos[i]; + var handlerParams = handlerInfo.serialize(); + merge(params, handlerParams); + } + params.queryParams = queryParams; + + return this.recognizer.generate(handlerName, params); + }, + + applyIntent: function(handlerName, contexts) { + var intent = new NamedTransitionIntent({ + name: handlerName, + contexts: contexts + }); + + var state = this.activeTransition && this.activeTransition.state || this.state; + return intent.applyToState(state, this.recognizer, this.getHandler); + }, + + isActiveIntent: function(handlerName, contexts, queryParams) { + var targetHandlerInfos = this.state.handlerInfos, + found = false, names, object, handlerInfo, handlerObj, i, len; + + if (!targetHandlerInfos.length) { return false; } + + var targetHandler = targetHandlerInfos[targetHandlerInfos.length - 1].name; + var recogHandlers = this.recognizer.handlersFor(targetHandler); + + var index = 0; + for (len = recogHandlers.length; index < len; ++index) { + handlerInfo = targetHandlerInfos[index]; + if (handlerInfo.name === handlerName) { break; } + } + + if (index === recogHandlers.length) { + // The provided route name isn't even in the route hierarchy. + return false; + } + + var state = new TransitionState(); + state.handlerInfos = targetHandlerInfos.slice(0, index + 1); + recogHandlers = recogHandlers.slice(0, index + 1); + + var intent = new NamedTransitionIntent({ + name: targetHandler, + contexts: contexts + }); + + var newState = intent.applyToHandlers(state, recogHandlers, this.getHandler, targetHandler, true, true); + + var handlersEqual = handlerInfosEqual(newState.handlerInfos, state.handlerInfos); + if (!queryParams || !handlersEqual) { + return handlersEqual; + } + + // Get a hash of QPs that will still be active on new route + var activeQPsOnNewHandler = {}; + merge(activeQPsOnNewHandler, queryParams); + + var activeQueryParams = this.state.queryParams; + for (var key in activeQueryParams) { + if (activeQueryParams.hasOwnProperty(key) && + activeQPsOnNewHandler.hasOwnProperty(key)) { + activeQPsOnNewHandler[key] = activeQueryParams[key]; + } + } + + return handlersEqual && !getChangelist(activeQPsOnNewHandler, queryParams); + }, + + isActive: function(handlerName) { + var partitionedArgs = extractQueryParams(slice.call(arguments, 1)); + return this.isActiveIntent(handlerName, partitionedArgs[0], partitionedArgs[1]); + }, + + trigger: function(name) { + var args = slice.call(arguments); + trigger(this, this.currentHandlerInfos, false, args); + }, + + /** + Hook point for logging transition status updates. + + @param {String} message The message to log. + */ + log: null, + + _willChangeContextEvent: 'willChangeContext', + _triggerWillChangeContext: function(handlerInfos, newTransition) { + trigger(this, handlerInfos, true, [this._willChangeContextEvent, newTransition]); + }, + + _triggerWillLeave: function(handlerInfos, newTransition, leavingChecker) { + trigger(this, handlerInfos, true, ['willLeave', newTransition, leavingChecker]); + } + }; + + /** + @private + + Fires queryParamsDidChange event + */ + function fireQueryParamDidChange(router, newState, queryParamChangelist) { + // If queryParams changed trigger event + if (queryParamChangelist) { + + // This is a little hacky but we need some way of storing + // changed query params given that no activeTransition + // is guaranteed to have occurred. + router._changedQueryParams = queryParamChangelist.all; + trigger(router, newState.handlerInfos, true, ['queryParamsDidChange', queryParamChangelist.changed, queryParamChangelist.all, queryParamChangelist.removed]); + router._changedQueryParams = null; + } + } + + /** + @private + + Takes an Array of `HandlerInfo`s, figures out which ones are + exiting, entering, or changing contexts, and calls the + proper handler hooks. + + For example, consider the following tree of handlers. Each handler is + followed by the URL segment it handles. + + ``` + |~index ("/") + | |~posts ("/posts") + | | |-showPost ("/:id") + | | |-newPost ("/new") + | | |-editPost ("/edit") + | |~about ("/about/:id") + ``` + + Consider the following transitions: + + 1. A URL transition to `/posts/1`. + 1. Triggers the `*model` callbacks on the + `index`, `posts`, and `showPost` handlers + 2. Triggers the `enter` callback on the same + 3. Triggers the `setup` callback on the same + 2. A direct transition to `newPost` + 1. Triggers the `exit` callback on `showPost` + 2. Triggers the `enter` callback on `newPost` + 3. Triggers the `setup` callback on `newPost` + 3. A direct transition to `about` with a specified + context object + 1. Triggers the `exit` callback on `newPost` + and `posts` + 2. Triggers the `serialize` callback on `about` + 3. Triggers the `enter` callback on `about` + 4. Triggers the `setup` callback on `about` + + @param {Router} transition + @param {TransitionState} newState + */ + function setupContexts(router, newState, transition) { + var partition = partitionHandlers(router.state, newState); + + forEach(partition.exited, function(handlerInfo) { + var handler = handlerInfo.handler; + delete handler.context; + + callHook(handler, 'reset', true, transition); + callHook(handler, 'exit', transition); + }); + + var oldState = router.oldState = router.state; + router.state = newState; + var currentHandlerInfos = router.currentHandlerInfos = partition.unchanged.slice(); + + try { + forEach(partition.reset, function(handlerInfo) { + var handler = handlerInfo.handler; + callHook(handler, 'reset', false, transition); + }); + + forEach(partition.updatedContext, function(handlerInfo) { + return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, false, transition); + }); + + forEach(partition.entered, function(handlerInfo) { + return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, true, transition); + }); + } catch(e) { + router.state = oldState; + router.currentHandlerInfos = oldState.handlerInfos; + throw e; + } + + router.state.queryParams = finalizeQueryParamChange(router, currentHandlerInfos, newState.queryParams, transition); + } + + + /** + @private + + Helper method used by setupContexts. Handles errors or redirects + that may happen in enter/setup. + */ + function handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, enter, transition) { + + var handler = handlerInfo.handler, + context = handlerInfo.context; + + if (enter) { + callHook(handler, 'enter', transition); + } + if (transition && transition.isAborted) { + throw new TransitionAborted(); + } + + handler.context = context; + callHook(handler, 'contextDidChange'); + + callHook(handler, 'setup', context, transition); + if (transition && transition.isAborted) { + throw new TransitionAborted(); + } + + currentHandlerInfos.push(handlerInfo); + + return true; + } + + + /** + @private + + This function is called when transitioning from one URL to + another to determine which handlers are no longer active, + which handlers are newly active, and which handlers remain + active but have their context changed. + + Take a list of old handlers and new handlers and partition + them into four buckets: + + * unchanged: the handler was active in both the old and + new URL, and its context remains the same + * updated context: the handler was active in both the + old and new URL, but its context changed. The handler's + `setup` method, if any, will be called with the new + context. + * exited: the handler was active in the old URL, but is + no longer active. + * entered: the handler was not active in the old URL, but + is now active. + + The PartitionedHandlers structure has four fields: + + * `updatedContext`: a list of `HandlerInfo` objects that + represent handlers that remain active but have a changed + context + * `entered`: a list of `HandlerInfo` objects that represent + handlers that are newly active + * `exited`: a list of `HandlerInfo` objects that are no + longer active. + * `unchanged`: a list of `HanderInfo` objects that remain active. + + @param {Array[HandlerInfo]} oldHandlers a list of the handler + information for the previous URL (or `[]` if this is the + first handled transition) + @param {Array[HandlerInfo]} newHandlers a list of the handler + information for the new URL + + @return {Partition} + */ + function partitionHandlers(oldState, newState) { + var oldHandlers = oldState.handlerInfos; + var newHandlers = newState.handlerInfos; + + var handlers = { + updatedContext: [], + exited: [], + entered: [], + unchanged: [] + }; + + var handlerChanged, contextChanged = false, i, l; + + for (i=0, l=newHandlers.length; i= 0; --i) { + var handlerInfo = handlerInfos[i]; + merge(params, handlerInfo.params); + if (handlerInfo.handler.inaccessibleByURL) { + urlMethod = null; + } + } + + if (urlMethod) { + params.queryParams = transition._visibleQueryParams || state.queryParams; + var url = router.recognizer.generate(handlerName, params); + + if (urlMethod === 'replace') { + router.replaceURL(url); + } else { + router.updateURL(url); + } + } + } + + /** + @private + + Updates the URL (if necessary) and calls `setupContexts` + to update the router's array of `currentHandlerInfos`. + */ + function finalizeTransition(transition, newState) { + + try { + log(transition.router, transition.sequence, "Resolved all models on destination route; finalizing transition."); + + var router = transition.router, + handlerInfos = newState.handlerInfos, + seq = transition.sequence; + + // Run all the necessary enter/setup/exit hooks + setupContexts(router, newState, transition); + + // Check if a redirect occurred in enter/setup + if (transition.isAborted) { + // TODO: cleaner way? distinguish b/w targetHandlerInfos? + router.state.handlerInfos = router.currentHandlerInfos; + return Promise.reject(logAbort(transition)); + } + + updateURL(transition, newState, transition.intent.url); + + transition.isActive = false; + router.activeTransition = null; + + trigger(router, router.currentHandlerInfos, true, ['didTransition']); + + if (router.didTransition) { + router.didTransition(router.currentHandlerInfos); + } + + log(router, transition.sequence, "TRANSITION COMPLETE."); + + // Resolve with the final handler. + return handlerInfos[handlerInfos.length - 1].handler; + } catch(e) { + if (!((e instanceof TransitionAborted))) { + //var erroneousHandler = handlerInfos.pop(); + var infos = transition.state.handlerInfos; + transition.trigger(true, 'error', e, transition, infos[infos.length-1].handler); + transition.abort(); + } + + throw e; + } + } + + /** + @private + + Begins and returns a Transition based on the provided + arguments. Accepts arguments in the form of both URL + transitions and named transitions. + + @param {Router} router + @param {Array[Object]} args arguments passed to transitionTo, + replaceWith, or handleURL + */ + function doTransition(router, args, isIntermediate) { + // Normalize blank transitions to root URL transitions. + var name = args[0] || '/'; + + var lastArg = args[args.length-1]; + var queryParams = {}; + if (lastArg && lastArg.hasOwnProperty('queryParams')) { + queryParams = pop.call(args).queryParams; + } + + var intent; + if (args.length === 0) { + + log(router, "Updating query params"); + + // A query param update is really just a transition + // into the route you're already on. + var handlerInfos = router.state.handlerInfos; + intent = new NamedTransitionIntent({ + name: handlerInfos[handlerInfos.length - 1].name, + contexts: [], + queryParams: queryParams + }); + + } else if (name.charAt(0) === '/') { + + log(router, "Attempting URL transition to " + name); + intent = new URLTransitionIntent({ url: name }); + + } else { + + log(router, "Attempting transition to " + name); + intent = new NamedTransitionIntent({ + name: args[0], + contexts: slice.call(args, 1), + queryParams: queryParams + }); + } + + return router.transitionByIntent(intent, isIntermediate); + } + + function handlerInfosEqual(handlerInfos, otherHandlerInfos) { + if (handlerInfos.length !== otherHandlerInfos.length) { + return false; + } + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + if (handlerInfos[i] !== otherHandlerInfos[i]) { + return false; + } + } + return true; + } + + function finalizeQueryParamChange(router, resolvedHandlers, newQueryParams, transition) { + // We fire a finalizeQueryParamChange event which + // gives the new route hierarchy a chance to tell + // us which query params it's consuming and what + // their final values are. If a query param is + // no longer consumed in the final route hierarchy, + // its serialized segment will be removed + // from the URL. + + for (var k in newQueryParams) { + if (newQueryParams.hasOwnProperty(k) && + newQueryParams[k] === null) { + delete newQueryParams[k]; + } + } + + var finalQueryParamsArray = []; + trigger(router, resolvedHandlers, true, ['finalizeQueryParamChange', newQueryParams, finalQueryParamsArray, transition]); + + if (transition) { + transition._visibleQueryParams = {}; + } + + var finalQueryParams = {}; + for (var i = 0, len = finalQueryParamsArray.length; i < len; ++i) { + var qp = finalQueryParamsArray[i]; + finalQueryParams[qp.key] = qp.value; + if (transition && qp.visible !== false) { + transition._visibleQueryParams[qp.key] = qp.value; + } + } + return finalQueryParams; + } + + function notifyExistingHandlers(router, newState, newTransition) { + var oldHandlers = router.state.handlerInfos, + changing = [], + leavingIndex = null, + leaving, leavingChecker, i, oldHandlerLen, oldHandler, newHandler; + + oldHandlerLen = oldHandlers.length; + for (i = 0; i < oldHandlerLen; i++) { + oldHandler = oldHandlers[i]; + newHandler = newState.handlerInfos[i]; + + if (!newHandler || oldHandler.name !== newHandler.name) { + leavingIndex = i; + break; + } + + if (!newHandler.isResolved) { + changing.push(oldHandler); + } + } + + if (leavingIndex !== null) { + leaving = oldHandlers.slice(leavingIndex, oldHandlerLen); + leavingChecker = function(name) { + for (var h = 0, len = leaving.length; h < len; h++) { + if (leaving[h].name === name) { + return true; + } + } + return false; + }; + + router._triggerWillLeave(leaving, newTransition, leavingChecker); + } + + if (changing.length > 0) { + router._triggerWillChangeContext(changing, newTransition); + } + + trigger(router, oldHandlers, true, ['willTransition', newTransition]); + } + + __exports__["default"] = Router; + }); +define("router/transition-intent", + ["./utils","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var merge = __dependency1__.merge; + + function TransitionIntent(props) { + this.initialize(props); + + // TODO: wat + this.data = this.data || {}; + } + + TransitionIntent.prototype = { + initialize: null, + applyToState: null + }; + + __exports__["default"] = TransitionIntent; + }); +define("router/transition-intent/named-transition-intent", + ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var TransitionIntent = __dependency1__["default"]; + var TransitionState = __dependency2__["default"]; + var handlerInfoFactory = __dependency3__["default"]; + var isParam = __dependency4__.isParam; + var extractQueryParams = __dependency4__.extractQueryParams; + var merge = __dependency4__.merge; + var subclass = __dependency4__.subclass; + + __exports__["default"] = subclass(TransitionIntent, { + name: null, + pivotHandler: null, + contexts: null, + queryParams: null, + + initialize: function(props) { + this.name = props.name; + this.pivotHandler = props.pivotHandler; + this.contexts = props.contexts || []; + this.queryParams = props.queryParams; + }, + + applyToState: function(oldState, recognizer, getHandler, isIntermediate) { + + var partitionedArgs = extractQueryParams([this.name].concat(this.contexts)), + pureArgs = partitionedArgs[0], + queryParams = partitionedArgs[1], + handlers = recognizer.handlersFor(pureArgs[0]); + + var targetRouteName = handlers[handlers.length-1].handler; + + return this.applyToHandlers(oldState, handlers, getHandler, targetRouteName, isIntermediate); + }, + + applyToHandlers: function(oldState, handlers, getHandler, targetRouteName, isIntermediate, checkingIfActive) { + + var i, len; + var newState = new TransitionState(); + var objects = this.contexts.slice(0); + + var invalidateIndex = handlers.length; + + // Pivot handlers are provided for refresh transitions + if (this.pivotHandler) { + for (i = 0, len = handlers.length; i < len; ++i) { + if (getHandler(handlers[i].handler) === this.pivotHandler) { + invalidateIndex = i; + break; + } + } + } + + var pivotHandlerFound = !this.pivotHandler; + + for (i = handlers.length - 1; i >= 0; --i) { + var result = handlers[i]; + var name = result.handler; + var handler = getHandler(name); + + var oldHandlerInfo = oldState.handlerInfos[i]; + var newHandlerInfo = null; + + if (result.names.length > 0) { + if (i >= invalidateIndex) { + newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); + } else { + newHandlerInfo = this.getHandlerInfoForDynamicSegment(name, handler, result.names, objects, oldHandlerInfo, targetRouteName, i); + } + } else { + // This route has no dynamic segment. + // Therefore treat as a param-based handlerInfo + // with empty params. This will cause the `model` + // hook to be called with empty params, which is desirable. + newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); + } + + if (checkingIfActive) { + // If we're performing an isActive check, we want to + // serialize URL params with the provided context, but + // ignore mismatches between old and new context. + newHandlerInfo = newHandlerInfo.becomeResolved(null, newHandlerInfo.context); + var oldContext = oldHandlerInfo && oldHandlerInfo.context; + if (result.names.length > 0 && newHandlerInfo.context === oldContext) { + // If contexts match in isActive test, assume params also match. + // This allows for flexibility in not requiring that every last + // handler provide a `serialize` method + newHandlerInfo.params = oldHandlerInfo && oldHandlerInfo.params; + } + newHandlerInfo.context = oldContext; + } + + var handlerToUse = oldHandlerInfo; + if (i >= invalidateIndex || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { + invalidateIndex = Math.min(i, invalidateIndex); + handlerToUse = newHandlerInfo; + } + + if (isIntermediate && !checkingIfActive) { + handlerToUse = handlerToUse.becomeResolved(null, handlerToUse.context); + } + + newState.handlerInfos.unshift(handlerToUse); + } + + if (objects.length > 0) { + throw new Error("More context objects were passed than there are dynamic segments for the route: " + targetRouteName); + } + + if (!isIntermediate) { + this.invalidateChildren(newState.handlerInfos, invalidateIndex); + } + + merge(newState.queryParams, this.queryParams || {}); + + return newState; + }, + + invalidateChildren: function(handlerInfos, invalidateIndex) { + for (var i = invalidateIndex, l = handlerInfos.length; i < l; ++i) { + var handlerInfo = handlerInfos[i]; + handlerInfos[i] = handlerInfos[i].getUnresolved(); + } + }, + + getHandlerInfoForDynamicSegment: function(name, handler, names, objects, oldHandlerInfo, targetRouteName, i) { + + var numNames = names.length; + var objectToUse; + if (objects.length > 0) { + + // Use the objects provided for this transition. + objectToUse = objects[objects.length - 1]; + if (isParam(objectToUse)) { + return this.createParamHandlerInfo(name, handler, names, objects, oldHandlerInfo); + } else { + objects.pop(); + } + } else if (oldHandlerInfo && oldHandlerInfo.name === name) { + // Reuse the matching oldHandlerInfo + return oldHandlerInfo; + } else { + if (this.preTransitionState) { + var preTransitionHandlerInfo = this.preTransitionState.handlerInfos[i]; + objectToUse = preTransitionHandlerInfo && preTransitionHandlerInfo.context; + } else { + // Ideally we should throw this error to provide maximal + // information to the user that not enough context objects + // were provided, but this proves too cumbersome in Ember + // in cases where inner template helpers are evaluated + // before parent helpers un-render, in which cases this + // error somewhat prematurely fires. + //throw new Error("Not enough context objects were provided to complete a transition to " + targetRouteName + ". Specifically, the " + name + " route needs an object that can be serialized into its dynamic URL segments [" + names.join(', ') + "]"); + return oldHandlerInfo; + } + } + + return handlerInfoFactory('object', { + name: name, + handler: handler, + context: objectToUse, + names: names + }); + }, + + createParamHandlerInfo: function(name, handler, names, objects, oldHandlerInfo) { + var params = {}; + + // Soak up all the provided string/numbers + var numNames = names.length; + while (numNames--) { + + // Only use old params if the names match with the new handler + var oldParams = (oldHandlerInfo && name === oldHandlerInfo.name && oldHandlerInfo.params) || {}; + + var peek = objects[objects.length - 1]; + var paramName = names[numNames]; + if (isParam(peek)) { + params[paramName] = "" + objects.pop(); + } else { + // If we're here, this means only some of the params + // were string/number params, so try and use a param + // value from a previous handler. + if (oldParams.hasOwnProperty(paramName)) { + params[paramName] = oldParams[paramName]; + } else { + throw new Error("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route " + name); + } + } + } + + return handlerInfoFactory('param', { + name: name, + handler: handler, + params: params + }); + } + }); + }); +define("router/transition-intent/url-transition-intent", + ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var TransitionIntent = __dependency1__["default"]; + var TransitionState = __dependency2__["default"]; + var handlerInfoFactory = __dependency3__["default"]; + var oCreate = __dependency4__.oCreate; + var merge = __dependency4__.merge; + var subclass = __dependency4__.subclass; + + __exports__["default"] = subclass(TransitionIntent, { + url: null, + + initialize: function(props) { + this.url = props.url; + }, + + applyToState: function(oldState, recognizer, getHandler) { + var newState = new TransitionState(); + + var results = recognizer.recognize(this.url), + queryParams = {}, + i, len; + + if (!results) { + throw new UnrecognizedURLError(this.url); + } + + var statesDiffer = false; + + for (i = 0, len = results.length; i < len; ++i) { + var result = results[i]; + var name = result.handler; + var handler = getHandler(name); + + if (handler.inaccessibleByURL) { + throw new UnrecognizedURLError(this.url); + } + + var newHandlerInfo = handlerInfoFactory('param', { + name: name, + handler: handler, + params: result.params + }); + + var oldHandlerInfo = oldState.handlerInfos[i]; + if (statesDiffer || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { + statesDiffer = true; + newState.handlerInfos[i] = newHandlerInfo; + } else { + newState.handlerInfos[i] = oldHandlerInfo; + } + } + + merge(newState.queryParams, results.queryParams); + + return newState; + } + }); + + /** + Promise reject reasons passed to promise rejection + handlers for failed transitions. + */ + function UnrecognizedURLError(message) { + this.message = (message || "UnrecognizedURLError"); + this.name = "UnrecognizedURLError"; + } + }); +define("router/transition-state", + ["./handler-info","./utils","rsvp/promise","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var ResolvedHandlerInfo = __dependency1__.ResolvedHandlerInfo; + var forEach = __dependency2__.forEach; + var promiseLabel = __dependency2__.promiseLabel; + var callHook = __dependency2__.callHook; + var Promise = __dependency3__["default"]; + + function TransitionState(other) { + this.handlerInfos = []; + this.queryParams = {}; + this.params = {}; + } + + TransitionState.prototype = { + handlerInfos: null, + queryParams: null, + params: null, + + promiseLabel: function(label) { + var targetName = ''; + forEach(this.handlerInfos, function(handlerInfo) { + if (targetName !== '') { + targetName += '.'; + } + targetName += handlerInfo.name; + }); + return promiseLabel("'" + targetName + "': " + label); + }, + + resolve: function(shouldContinue, payload) { + var self = this; + // First, calculate params for this state. This is useful + // information to provide to the various route hooks. + var params = this.params; + forEach(this.handlerInfos, function(handlerInfo) { + params[handlerInfo.name] = handlerInfo.params || {}; + }); + + payload = payload || {}; + payload.resolveIndex = 0; + + var currentState = this; + var wasAborted = false; + + // The prelude RSVP.resolve() asyncs us into the promise land. + return Promise.resolve(null, this.promiseLabel("Start transition")) + .then(resolveOneHandlerInfo, null, this.promiseLabel('Resolve handler'))['catch'](handleError, this.promiseLabel('Handle error')); + + function innerShouldContinue() { + return Promise.resolve(shouldContinue(), currentState.promiseLabel("Check if should continue"))['catch'](function(reason) { + // We distinguish between errors that occurred + // during resolution (e.g. beforeModel/model/afterModel), + // and aborts due to a rejecting promise from shouldContinue(). + wasAborted = true; + return Promise.reject(reason); + }, currentState.promiseLabel("Handle abort")); + } + + function handleError(error) { + // This is the only possible + // reject value of TransitionState#resolve + var handlerInfos = currentState.handlerInfos; + var errorHandlerIndex = payload.resolveIndex >= handlerInfos.length ? + handlerInfos.length - 1 : payload.resolveIndex; + return Promise.reject({ + error: error, + handlerWithError: currentState.handlerInfos[errorHandlerIndex].handler, + wasAborted: wasAborted, + state: currentState + }); + } + + function proceed(resolvedHandlerInfo) { + var wasAlreadyResolved = currentState.handlerInfos[payload.resolveIndex].isResolved; + + // Swap the previously unresolved handlerInfo with + // the resolved handlerInfo + currentState.handlerInfos[payload.resolveIndex++] = resolvedHandlerInfo; + + if (!wasAlreadyResolved) { + // Call the redirect hook. The reason we call it here + // vs. afterModel is so that redirects into child + // routes don't re-run the model hooks for this + // already-resolved route. + var handler = resolvedHandlerInfo.handler; + callHook(handler, 'redirect', resolvedHandlerInfo.context, payload); + } + + // Proceed after ensuring that the redirect hook + // didn't abort this transition by transitioning elsewhere. + return innerShouldContinue().then(resolveOneHandlerInfo, null, currentState.promiseLabel('Resolve handler')); + } + + function resolveOneHandlerInfo() { + if (payload.resolveIndex === currentState.handlerInfos.length) { + // This is is the only possible + // fulfill value of TransitionState#resolve + return { + error: null, + state: currentState + }; + } + + var handlerInfo = currentState.handlerInfos[payload.resolveIndex]; + + return handlerInfo.resolve(innerShouldContinue, payload) + .then(proceed, null, currentState.promiseLabel('Proceed')); + } + } + }; + + __exports__["default"] = TransitionState; + }); +define("router/transition", + ["rsvp/promise","./handler-info","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var ResolvedHandlerInfo = __dependency2__.ResolvedHandlerInfo; + var trigger = __dependency3__.trigger; + var slice = __dependency3__.slice; + var log = __dependency3__.log; + var promiseLabel = __dependency3__.promiseLabel; + + /** + @private + + A Transition is a thennable (a promise-like object) that represents + an attempt to transition to another route. It can be aborted, either + explicitly via `abort` or by attempting another transition while a + previous one is still underway. An aborted transition can also + be `retry()`d later. + */ + function Transition(router, intent, state, error) { + var transition = this; + this.state = state || router.state; + this.intent = intent; + this.router = router; + this.data = this.intent && this.intent.data || {}; + this.resolvedModels = {}; + this.queryParams = {}; + + if (error) { + this.promise = Promise.reject(error); + return; + } + + if (state) { + this.params = state.params; + this.queryParams = state.queryParams; + this.handlerInfos = state.handlerInfos; + + var len = state.handlerInfos.length; + if (len) { + this.targetName = state.handlerInfos[len-1].name; + } + + for (var i = 0; i < len; ++i) { + var handlerInfo = state.handlerInfos[i]; + + // TODO: this all seems hacky + if (!handlerInfo.isResolved) { break; } + this.pivotHandler = handlerInfo.handler; + } + + this.sequence = Transition.currentSequence++; + this.promise = state.resolve(checkForAbort, this)['catch'](function(result) { + if (result.wasAborted || transition.isAborted) { + return Promise.reject(logAbort(transition)); + } else { + transition.trigger('error', result.error, transition, result.handlerWithError); + transition.abort(); + return Promise.reject(result.error); + } + }, promiseLabel('Handle Abort')); + } else { + this.promise = Promise.resolve(this.state); + this.params = {}; + } + + function checkForAbort() { + if (transition.isAborted) { + return Promise.reject(undefined, promiseLabel("Transition aborted - reject")); + } + } + } + + Transition.currentSequence = 0; + + Transition.prototype = { + targetName: null, + urlMethod: 'update', + intent: null, + params: null, + pivotHandler: null, + resolveIndex: 0, + handlerInfos: null, + resolvedModels: null, + isActive: true, + state: null, + queryParamsOnly: false, + + isTransition: true, + + isExiting: function(handler) { + var handlerInfos = this.handlerInfos; + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + if (handlerInfo.name === handler || handlerInfo.handler === handler) { + return false; + } + } + return true; + }, + + /** + @public + + The Transition's internal promise. Calling `.then` on this property + is that same as calling `.then` on the Transition object itself, but + this property is exposed for when you want to pass around a + Transition's promise, but not the Transition object itself, since + Transition object can be externally `abort`ed, while the promise + cannot. + */ + promise: null, + + /** + @public + + Custom state can be stored on a Transition's `data` object. + This can be useful for decorating a Transition within an earlier + hook and shared with a later hook. Properties set on `data` will + be copied to new transitions generated by calling `retry` on this + transition. + */ + data: null, + + /** + @public + + A standard promise hook that resolves if the transition + succeeds and rejects if it fails/redirects/aborts. + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @param {Function} onFulfilled + @param {Function} onRejected + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + then: function(onFulfilled, onRejected, label) { + return this.promise.then(onFulfilled, onRejected, label); + }, + + /** + @public + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @method catch + @param {Function} onRejection + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + "catch": function(onRejection, label) { + return this.promise["catch"](onRejection, label); + }, + + /** + @public + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @method finally + @param {Function} callback + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + "finally": function(callback, label) { + return this.promise["finally"](callback, label); + }, + + /** + @public + + Aborts the Transition. Note you can also implicitly abort a transition + by initiating another transition while a previous one is underway. + */ + abort: function() { + if (this.isAborted) { return this; } + log(this.router, this.sequence, this.targetName + ": transition was aborted"); + this.intent.preTransitionState = this.router.state; + this.isAborted = true; + this.isActive = false; + this.router.activeTransition = null; + return this; + }, + + /** + @public + + Retries a previously-aborted transition (making sure to abort the + transition if it's still active). Returns a new transition that + represents the new attempt to transition. + */ + retry: function() { + // TODO: add tests for merged state retry()s + this.abort(); + return this.router.transitionByIntent(this.intent, false); + }, + + /** + @public + + Sets the URL-changing method to be employed at the end of a + successful transition. By default, a new Transition will just + use `updateURL`, but passing 'replace' to this method will + cause the URL to update using 'replaceWith' instead. Omitting + a parameter will disable the URL change, allowing for transitions + that don't update the URL at completion (this is also used for + handleURL, since the URL has already changed before the + transition took place). + + @param {String} method the type of URL-changing method to use + at the end of a transition. Accepted values are 'replace', + falsy values, or any other non-falsy value (which is + interpreted as an updateURL transition). + + @return {Transition} this transition + */ + method: function(method) { + this.urlMethod = method; + return this; + }, + + /** + @public + + Fires an event on the current list of resolved/resolving + handlers within this transition. Useful for firing events + on route hierarchies that haven't fully been entered yet. + + Note: This method is also aliased as `send` + + @param {Boolean} [ignoreFailure=false] a boolean specifying whether unhandled events throw an error + @param {String} name the name of the event to fire + */ + trigger: function (ignoreFailure) { + var args = slice.call(arguments); + if (typeof ignoreFailure === 'boolean') { + args.shift(); + } else { + // Throw errors on unhandled trigger events by default + ignoreFailure = false; + } + trigger(this.router, this.state.handlerInfos.slice(0, this.resolveIndex + 1), ignoreFailure, args); + }, + + /** + @public + + Transitions are aborted and their promises rejected + when redirects occur; this method returns a promise + that will follow any redirects that occur and fulfill + with the value fulfilled by any redirecting transitions + that occur. + + @return {Promise} a promise that fulfills with the same + value that the final redirecting transition fulfills with + */ + followRedirects: function() { + var router = this.router; + return this.promise['catch'](function(reason) { + if (router.activeTransition) { + return router.activeTransition.followRedirects(); + } + return Promise.reject(reason); + }); + }, + + toString: function() { + return "Transition (sequence " + this.sequence + ")"; + }, + + /** + @private + */ + log: function(message) { + log(this.router, this.sequence, message); + } + }; + + // Alias 'trigger' as 'send' + Transition.prototype.send = Transition.prototype.trigger; + + /** + @private + + Logs and returns a TransitionAborted error. + */ + function logAbort(transition) { + log(transition.router, transition.sequence, "detected abort."); + return new TransitionAborted(); + } + + function TransitionAborted(message) { + this.message = (message || "TransitionAborted"); + this.name = "TransitionAborted"; + } + + __exports__.Transition = Transition; + __exports__.logAbort = logAbort; + __exports__.TransitionAborted = TransitionAborted; + }); +define("router/utils", + ["exports"], + function(__exports__) { + "use strict"; + var slice = Array.prototype.slice; + + var _isArray; + if (!Array.isArray) { + _isArray = function (x) { + return Object.prototype.toString.call(x) === "[object Array]"; + }; + } else { + _isArray = Array.isArray; + } + + var isArray = _isArray; + __exports__.isArray = isArray; + function merge(hash, other) { + for (var prop in other) { + if (other.hasOwnProperty(prop)) { hash[prop] = other[prop]; } + } + } + + var oCreate = Object.create || function(proto) { + function F() {} + F.prototype = proto; + return new F(); + }; + __exports__.oCreate = oCreate; + /** + @private + + Extracts query params from the end of an array + **/ + function extractQueryParams(array) { + var len = (array && array.length), head, queryParams; + + if(len && len > 0 && array[len - 1] && array[len - 1].hasOwnProperty('queryParams')) { + queryParams = array[len - 1].queryParams; + head = slice.call(array, 0, len - 1); + return [head, queryParams]; + } else { + return [array, null]; + } + } + + __exports__.extractQueryParams = extractQueryParams;/** + @private + + Coerces query param properties and array elements into strings. + **/ + function coerceQueryParamsToString(queryParams) { + for (var key in queryParams) { + if (typeof queryParams[key] === 'number') { + queryParams[key] = '' + queryParams[key]; + } else if (isArray(queryParams[key])) { + for (var i = 0, l = queryParams[key].length; i < l; i++) { + queryParams[key][i] = '' + queryParams[key][i]; + } + } + } + } + /** + @private + */ + function log(router, sequence, msg) { + if (!router.log) { return; } + + if (arguments.length === 3) { + router.log("Transition #" + sequence + ": " + msg); + } else { + msg = sequence; + router.log(msg); + } + } + + __exports__.log = log;function bind(context, fn) { + var boundArgs = arguments; + return function(value) { + var args = slice.call(boundArgs, 2); + args.push(value); + return fn.apply(context, args); + }; + } + + __exports__.bind = bind;function isParam(object) { + return (typeof object === "string" || object instanceof String || typeof object === "number" || object instanceof Number); + } + + + function forEach(array, callback) { + for (var i=0, l=array.length; i=0; i--) { + var handlerInfo = handlerInfos[i], + handler = handlerInfo.handler; + + if (handler.events && handler.events[name]) { + if (handler.events[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (!eventWasHandled && !ignoreFailure) { + throw new Error("Nothing handled the event '" + name + "'."); + } + } + + __exports__.trigger = trigger;function getChangelist(oldObject, newObject) { + var key; + var results = { + all: {}, + changed: {}, + removed: {} + }; + + merge(results.all, newObject); + + var didChange = false; + coerceQueryParamsToString(oldObject); + coerceQueryParamsToString(newObject); + + // Calculate removals + for (key in oldObject) { + if (oldObject.hasOwnProperty(key)) { + if (!newObject.hasOwnProperty(key)) { + didChange = true; + results.removed[key] = oldObject[key]; + } + } + } + + // Calculate changes + for (key in newObject) { + if (newObject.hasOwnProperty(key)) { + if (isArray(oldObject[key]) && isArray(newObject[key])) { + if (oldObject[key].length !== newObject[key].length) { + results.changed[key] = newObject[key]; + didChange = true; + } else { + for (var i = 0, l = oldObject[key].length; i < l; i++) { + if (oldObject[key][i] !== newObject[key][i]) { + results.changed[key] = newObject[key]; + didChange = true; + } + } + } + } + else { + if (oldObject[key] !== newObject[key]) { + results.changed[key] = newObject[key]; + didChange = true; + } + } + } + } + + return didChange && results; + } + + __exports__.getChangelist = getChangelist;function promiseLabel(label) { + return 'Router: ' + label; + } + + __exports__.promiseLabel = promiseLabel;function subclass(parentConstructor, proto) { + function C(props) { + parentConstructor.call(this, props || {}); + } + C.prototype = oCreate(parentConstructor.prototype); + merge(C.prototype, proto); + return C; + } + + __exports__.subclass = subclass;function resolveHook(obj, hookName) { + if (!obj) { return; } + var underscored = "_" + hookName; + return obj[underscored] && underscored || + obj[hookName] && hookName; + } + + function callHook(obj, hookName) { + var args = slice.call(arguments, 2); + return applyHook(obj, hookName, args); + } + + function applyHook(obj, _hookName, args) { + var hookName = resolveHook(obj, _hookName); + if (hookName) { + return obj[hookName].apply(obj, args); + } + } + + __exports__.merge = merge; + __exports__.slice = slice; + __exports__.isParam = isParam; + __exports__.coerceQueryParamsToString = coerceQueryParamsToString; + __exports__.callHook = callHook; + __exports__.resolveHook = resolveHook; + __exports__.applyHook = applyHook; + }); +define("rsvp", + ["./rsvp/promise","./rsvp/events","./rsvp/node","./rsvp/all","./rsvp/all-settled","./rsvp/race","./rsvp/hash","./rsvp/hash-settled","./rsvp/rethrow","./rsvp/defer","./rsvp/config","./rsvp/map","./rsvp/resolve","./rsvp/reject","./rsvp/filter","./rsvp/asap","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var EventTarget = __dependency2__["default"]; + var denodeify = __dependency3__["default"]; + var all = __dependency4__["default"]; + var allSettled = __dependency5__["default"]; + var race = __dependency6__["default"]; + var hash = __dependency7__["default"]; + var hashSettled = __dependency8__["default"]; + var rethrow = __dependency9__["default"]; + var defer = __dependency10__["default"]; + var config = __dependency11__.config; + var configure = __dependency11__.configure; + var map = __dependency12__["default"]; + var resolve = __dependency13__["default"]; + var reject = __dependency14__["default"]; + var filter = __dependency15__["default"]; + var asap = __dependency16__["default"]; + + config.async = asap; // default async is asap; + var cast = resolve; + function async(callback, arg) { + config.async(callback, arg); + } + + function on() { + config.on.apply(config, arguments); + } + + function off() { + config.off.apply(config, arguments); + } + + // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__` + if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') { + var callbacks = window['__PROMISE_INSTRUMENTATION__']; + configure('instrument', true); + for (var eventName in callbacks) { + if (callbacks.hasOwnProperty(eventName)) { + on(eventName, callbacks[eventName]); + } + } + } + + __exports__.cast = cast; + __exports__.Promise = Promise; + __exports__.EventTarget = EventTarget; + __exports__.all = all; + __exports__.allSettled = allSettled; + __exports__.race = race; + __exports__.hash = hash; + __exports__.hashSettled = hashSettled; + __exports__.rethrow = rethrow; + __exports__.defer = defer; + __exports__.denodeify = denodeify; + __exports__.configure = configure; + __exports__.on = on; + __exports__.off = off; + __exports__.resolve = resolve; + __exports__.reject = reject; + __exports__.async = async; + __exports__.map = map; + __exports__.filter = filter; + }); +define("rsvp.umd", + ["./rsvp"], + function(__dependency1__) { + "use strict"; + var Promise = __dependency1__.Promise; + var allSettled = __dependency1__.allSettled; + var hash = __dependency1__.hash; + var hashSettled = __dependency1__.hashSettled; + var denodeify = __dependency1__.denodeify; + var on = __dependency1__.on; + var off = __dependency1__.off; + var map = __dependency1__.map; + var filter = __dependency1__.filter; + var resolve = __dependency1__.resolve; + var reject = __dependency1__.reject; + var rethrow = __dependency1__.rethrow; + var all = __dependency1__.all; + var defer = __dependency1__.defer; + var EventTarget = __dependency1__.EventTarget; + var configure = __dependency1__.configure; + var race = __dependency1__.race; + var async = __dependency1__.async; + + var RSVP = { + 'race': race, + 'Promise': Promise, + 'allSettled': allSettled, + 'hash': hash, + 'hashSettled': hashSettled, + 'denodeify': denodeify, + 'on': on, + 'off': off, + 'map': map, + 'filter': filter, + 'resolve': resolve, + 'reject': reject, + 'all': all, + 'rethrow': rethrow, + 'defer': defer, + 'EventTarget': EventTarget, + 'configure': configure, + 'async': async + }; + + /* global define:true module:true window: true */ + if (typeof define === 'function' && define['amd']) { + define(function() { return RSVP; }); + } else if (typeof module !== 'undefined' && module['exports']) { + module['exports'] = RSVP; + } else if (typeof this !== 'undefined') { + this['RSVP'] = RSVP; + } + }); +define("rsvp/-internal", + ["./utils","./instrument","./config","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var objectOrFunction = __dependency1__.objectOrFunction; + var isFunction = __dependency1__.isFunction; + + var instrument = __dependency2__["default"]; + + var config = __dependency3__.config; + + function withOwnPromise() { + return new TypeError('A promises callback cannot return that same promise.'); + } + + function noop() {} + + var PENDING = void 0; + var FULFILLED = 1; + var REJECTED = 2; + + var GET_THEN_ERROR = new ErrorObject(); + + function getThen(promise) { + try { + return promise.then; + } catch(error) { + GET_THEN_ERROR.error = error; + return GET_THEN_ERROR; + } + } + + function tryThen(then, value, fulfillmentHandler, rejectionHandler) { + try { + then.call(value, fulfillmentHandler, rejectionHandler); + } catch(e) { + return e; + } + } + + function handleForeignThenable(promise, thenable, then) { + config.async(function(promise) { + var sealed = false; + var error = tryThen(then, thenable, function(value) { + if (sealed) { return; } + sealed = true; + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function(reason) { + if (sealed) { return; } + sealed = true; + + reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + reject(promise, error); + } + }, promise); + } + + function handleOwnThenable(promise, thenable) { + if (thenable._state === FULFILLED) { + fulfill(promise, thenable._result); + } else if (promise._state === REJECTED) { + reject(promise, thenable._result); + } else { + subscribe(thenable, undefined, function(value) { + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function(reason) { + reject(promise, reason); + }); + } + } + + function handleMaybeThenable(promise, maybeThenable) { + if (maybeThenable.constructor === promise.constructor) { + handleOwnThenable(promise, maybeThenable); + } else { + var then = getThen(maybeThenable); + + if (then === GET_THEN_ERROR) { + reject(promise, GET_THEN_ERROR.error); + } else if (then === undefined) { + fulfill(promise, maybeThenable); + } else if (isFunction(then)) { + handleForeignThenable(promise, maybeThenable, then); + } else { + fulfill(promise, maybeThenable); + } + } + } + + function resolve(promise, value) { + if (promise === value) { + fulfill(promise, value); + } else if (objectOrFunction(value)) { + handleMaybeThenable(promise, value); + } else { + fulfill(promise, value); + } + } + + function publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + publish(promise); + } + + function fulfill(promise, value) { + if (promise._state !== PENDING) { return; } + + promise._result = value; + promise._state = FULFILLED; + + if (promise._subscribers.length === 0) { + if (config.instrument) { + instrument('fulfilled', promise); + } + } else { + config.async(publish, promise); + } + } + + function reject(promise, reason) { + if (promise._state !== PENDING) { return; } + promise._state = REJECTED; + promise._result = reason; + + config.async(publishRejection, promise); + } + + function subscribe(parent, child, onFulfillment, onRejection) { + var subscribers = parent._subscribers; + var length = subscribers.length; + + parent._onerror = null; + + subscribers[length] = child; + subscribers[length + FULFILLED] = onFulfillment; + subscribers[length + REJECTED] = onRejection; + + if (length === 0 && parent._state) { + config.async(publish, parent); + } + } + + function publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (config.instrument) { + instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); + } + + if (subscribers.length === 0) { return; } + + var child, callback, detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; + } + + function ErrorObject() { + this.error = null; + } + + var TRY_CATCH_ERROR = new ErrorObject(); + + function tryCatch(callback, detail) { + try { + return callback(detail); + } catch(e) { + TRY_CATCH_ERROR.error = e; + return TRY_CATCH_ERROR; + } + } + + function invokeCallback(settled, promise, callback, detail) { + var hasCallback = isFunction(callback), + value, error, succeeded, failed; + + if (hasCallback) { + value = tryCatch(callback, detail); + + if (value === TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value = null; + } else { + succeeded = true; + } + + if (promise === value) { + reject(promise, withOwnPromise()); + return; + } + + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== PENDING) { + // noop + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (failed) { + reject(promise, error); + } else if (settled === FULFILLED) { + fulfill(promise, value); + } else if (settled === REJECTED) { + reject(promise, value); + } + } + + function initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value){ + resolve(promise, value); + }, function rejectPromise(reason) { + reject(promise, reason); + }); + } catch(e) { + reject(promise, e); + } + } + + __exports__.noop = noop; + __exports__.resolve = resolve; + __exports__.reject = reject; + __exports__.fulfill = fulfill; + __exports__.subscribe = subscribe; + __exports__.publish = publish; + __exports__.publishRejection = publishRejection; + __exports__.initializePromise = initializePromise; + __exports__.invokeCallback = invokeCallback; + __exports__.FULFILLED = FULFILLED; + __exports__.REJECTED = REJECTED; + __exports__.PENDING = PENDING; + }); +define("rsvp/all-settled", + ["./enumerator","./promise","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + var makeSettledResult = __dependency1__.makeSettledResult; + var Promise = __dependency2__["default"]; + var o_create = __dependency3__.o_create; + + function AllSettled(Constructor, entries, label) { + this._superConstructor(Constructor, entries, false /* don't abort on reject */, label); + } + + AllSettled.prototype = o_create(Enumerator.prototype); + AllSettled.prototype._superConstructor = Enumerator; + AllSettled.prototype._makeResult = makeSettledResult; + AllSettled.prototype._validationError = function() { + return new Error('allSettled must be called with an array'); + }; + + /** + `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing + a fail-fast method, it waits until all the promises have returned and + shows you all the results. This is useful if you want to handle multiple + promises' failure states together as a set. + + Returns a promise that is fulfilled when all the given promises have been + settled. The return promise is fulfilled with an array of the states of + the promises passed into the `promises` array argument. + + Each state object will either indicate fulfillment or rejection, and + provide the corresponding value or reason. The states will take one of + the following formats: + + ```javascript + { state: 'fulfilled', value: value } + or + { state: 'rejected', reason: reason } + ``` + + Example: + + ```javascript + var promise1 = RSVP.Promise.resolve(1); + var promise2 = RSVP.Promise.reject(new Error('2')); + var promise3 = RSVP.Promise.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.allSettled(promises).then(function(array){ + // array == [ + // { state: 'fulfilled', value: 1 }, + // { state: 'rejected', reason: Error }, + // { state: 'rejected', reason: Error } + // ] + // Note that for the second item, reason.message will be '2', and for the + // third item, reason.message will be '3'. + }, function(error) { + // Not run. (This block would only be called if allSettled had failed, + // for instance if passed an incorrect argument type.) + }); + ``` + + @method allSettled + @static + @for RSVP + @param {Array} promises + @param {String} label - optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled with an array of the settled + states of the constituent promises. + */ + + __exports__["default"] = function allSettled(entries, label) { + return new AllSettled(Promise, entries, label).promise; + } + }); +define("rsvp/all", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.all`. + + @method all + @static + @for RSVP + @param {Array} array Array of promises. + @param {String} label An optional label. This is useful + for tooling. + */ + __exports__["default"] = function all(array, label) { + return Promise.all(array, label); + } + }); +define("rsvp/asap", + ["exports"], + function(__exports__) { + "use strict"; + var len = 0; + + __exports__["default"] = function asap(callback, arg) { + queue[len] = callback; + queue[len + 1] = arg; + len += 2; + if (len === 2) { + // If len is 1, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + scheduleFlush(); + } + } + + var browserWindow = (typeof window !== 'undefined') ? window : undefined + var browserGlobal = browserWindow || {}; + var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; + + // test for web worker but not in IE10 + var isWorker = typeof Uint8ClampedArray !== 'undefined' && + typeof importScripts !== 'undefined' && + typeof MessageChannel !== 'undefined'; + + // node + function useNextTick() { + return function() { + process.nextTick(flush); + }; + } + + // vertx + function useVertxTimer() { + return function() { + vertxNext(flush); + }; + } + + function useMutationObserver() { + var iterations = 0; + var observer = new BrowserMutationObserver(flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function() { + node.data = (iterations = ++iterations % 2); + }; + } + + // web worker + function useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = flush; + return function () { + channel.port2.postMessage(0); + }; + } + + function useSetTimeout() { + return function() { + setTimeout(flush, 1); + }; + } + + var queue = new Array(1000); + function flush() { + for (var i = 0; i < len; i+=2) { + var callback = queue[i]; + var arg = queue[i+1]; + + callback(arg); + + queue[i] = undefined; + queue[i+1] = undefined; + } + + len = 0; + } + + function attemptVertex() { + try { + var vertx = require('vertx'); + var vertxNext = vertx.runOnLoop || vertx.runOnContext; + return useVertxTimer(); + } catch(e) { + return useSetTimeout(); + } + } + + var scheduleFlush; + // Decide what async method to use to triggering processing of queued callbacks: + if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { + scheduleFlush = useNextTick(); + } else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); + } else if (isWorker) { + scheduleFlush = useMessageChannel(); + } else if (browserWindow === undefined && typeof require === 'function') { + scheduleFlush = attemptVertex(); + } else { + scheduleFlush = useSetTimeout(); + } + }); +define("rsvp/config", + ["./events","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EventTarget = __dependency1__["default"]; + + var config = { + instrument: false + }; + + EventTarget.mixin(config); + + function configure(name, value) { + if (name === 'onerror') { + // handle for legacy users that expect the actual + // error to be passed to their function added via + // `RSVP.configure('onerror', someFunctionHere);` + config.on('error', value); + return; + } + + if (arguments.length === 2) { + config[name] = value; + } else { + return config[name]; + } + } + + __exports__.config = config; + __exports__.configure = configure; + }); +define("rsvp/defer", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + `RSVP.defer` returns an object similar to jQuery's `$.Deferred`. + `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s + interface. New code should use the `RSVP.Promise` constructor instead. + + The object returned from `RSVP.defer` is a plain object with three properties: + + * promise - an `RSVP.Promise`. + * reject - a function that causes the `promise` property on this object to + become rejected + * resolve - a function that causes the `promise` property on this object to + become fulfilled. + + Example: + + ```javascript + var deferred = RSVP.defer(); + + deferred.resolve("Success!"); + + defered.promise.then(function(value){ + // value here is "Success!" + }); + ``` + + @method defer + @static + @for RSVP + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Object} + */ + + __exports__["default"] = function defer(label) { + var deferred = { }; + + deferred['promise'] = new Promise(function(resolve, reject) { + deferred['resolve'] = resolve; + deferred['reject'] = reject; + }, label); + + return deferred; + } + }); +define("rsvp/enumerator", + ["./utils","./-internal","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var isArray = __dependency1__.isArray; + var isMaybeThenable = __dependency1__.isMaybeThenable; + + var noop = __dependency2__.noop; + var reject = __dependency2__.reject; + var fulfill = __dependency2__.fulfill; + var subscribe = __dependency2__.subscribe; + var FULFILLED = __dependency2__.FULFILLED; + var REJECTED = __dependency2__.REJECTED; + var PENDING = __dependency2__.PENDING; + + function makeSettledResult(state, position, value) { + if (state === FULFILLED) { + return { + state: 'fulfilled', + value: value + }; + } else { + return { + state: 'rejected', + reason: value + }; + } + } + + __exports__.makeSettledResult = makeSettledResult;function Enumerator(Constructor, input, abortOnReject, label) { + this._instanceConstructor = Constructor; + this.promise = new Constructor(noop, label); + this._abortOnReject = abortOnReject; + + if (this._validateInput(input)) { + this._input = input; + this.length = input.length; + this._remaining = input.length; + + this._init(); + + if (this.length === 0) { + fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(); + if (this._remaining === 0) { + fulfill(this.promise, this._result); + } + } + } else { + reject(this.promise, this._validationError()); + } + } + + Enumerator.prototype._validateInput = function(input) { + return isArray(input); + }; + + Enumerator.prototype._validationError = function() { + return new Error('Array Methods must be provided an Array'); + }; + + Enumerator.prototype._init = function() { + this._result = new Array(this.length); + }; + + __exports__["default"] = Enumerator; + + Enumerator.prototype._enumerate = function() { + var length = this.length; + var promise = this.promise; + var input = this._input; + + for (var i = 0; promise._state === PENDING && i < length; i++) { + this._eachEntry(input[i], i); + } + }; + + Enumerator.prototype._eachEntry = function(entry, i) { + var c = this._instanceConstructor; + if (isMaybeThenable(entry)) { + if (entry.constructor === c && entry._state !== PENDING) { + entry._onerror = null; + this._settledAt(entry._state, i, entry._result); + } else { + this._willSettleAt(c.resolve(entry), i); + } + } else { + this._remaining--; + this._result[i] = this._makeResult(FULFILLED, i, entry); + } + }; + + Enumerator.prototype._settledAt = function(state, i, value) { + var promise = this.promise; + + if (promise._state === PENDING) { + this._remaining--; + + if (this._abortOnReject && state === REJECTED) { + reject(promise, value); + } else { + this._result[i] = this._makeResult(state, i, value); + } + } + + if (this._remaining === 0) { + fulfill(promise, this._result); + } + }; + + Enumerator.prototype._makeResult = function(state, i, value) { + return value; + }; + + Enumerator.prototype._willSettleAt = function(promise, i) { + var enumerator = this; + + subscribe(promise, undefined, function(value) { + enumerator._settledAt(FULFILLED, i, value); + }, function(reason) { + enumerator._settledAt(REJECTED, i, reason); + }); + }; + }); +define("rsvp/events", + ["exports"], + function(__exports__) { + "use strict"; + function indexOf(callbacks, callback) { + for (var i=0, l=callbacks.length; i 1; + }; + + RSVP.filter(promises, filterFn).then(function(result){ + // result is [ 2, 3 ] + }); + ``` + + If any of the `promises` given to `RSVP.filter` are rejected, the first promise + that is rejected will be given as an argument to the returned promise's + rejection handler. For example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error('2')); + var promise3 = RSVP.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + var filterFn = function(item){ + return item > 1; + }; + + RSVP.filter(promises, filterFn).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === '2' + }); + ``` + + `RSVP.filter` will also wait for any promises returned from `filterFn`. + For instance, you may want to fetch a list of users then return a subset + of those users based on some asynchronous operation: + + ```javascript + + var alice = { name: 'alice' }; + var bob = { name: 'bob' }; + var users = [ alice, bob ]; + + var promises = users.map(function(user){ + return RSVP.resolve(user); + }); + + var filterFn = function(user){ + // Here, Alice has permissions to create a blog post, but Bob does not. + return getPrivilegesForUser(user).then(function(privs){ + return privs.can_create_blog_post === true; + }); + }; + RSVP.filter(promises, filterFn).then(function(users){ + // true, because the server told us only Alice can create a blog post. + users.length === 1; + // false, because Alice is the only user present in `users` + users[0] === bob; + }); + ``` + + @method filter + @static + @for RSVP + @param {Array} promises + @param {Function} filterFn - function to be called on each resolved value to + filter the final results. + @param {String} label optional string describing the promise. Useful for + tooling. + @return {Promise} + */ + __exports__["default"] = function filter(promises, filterFn, label) { + return Promise.all(promises, label).then(function(values) { + if (!isFunction(filterFn)) { + throw new TypeError("You must pass a function as filter's second argument."); + } + + var length = values.length; + var filtered = new Array(length); + + for (var i = 0; i < length; i++) { + filtered[i] = filterFn(values[i]); + } + + return Promise.all(filtered, label).then(function(filtered) { + var results = new Array(length); + var newLength = 0; + + for (var i = 0; i < length; i++) { + if (filtered[i]) { + results[newLength] = values[i]; + newLength++; + } + } + + results.length = newLength; + + return results; + }); + }); + } + }); +define("rsvp/hash-settled", + ["./promise","./enumerator","./promise-hash","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var makeSettledResult = __dependency2__.makeSettledResult; + var PromiseHash = __dependency3__["default"]; + var Enumerator = __dependency2__["default"]; + var o_create = __dependency4__.o_create; + + function HashSettled(Constructor, object, label) { + this._superConstructor(Constructor, object, false, label); + } + + HashSettled.prototype = o_create(PromiseHash.prototype); + HashSettled.prototype._superConstructor = Enumerator; + HashSettled.prototype._makeResult = makeSettledResult; + + HashSettled.prototype._validationError = function() { + return new Error('hashSettled must be called with an object'); + }; + + /** + `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object + instead of an array for its `promises` argument. + + Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method, + but like `RSVP.allSettled`, `hashSettled` waits until all the + constituent promises have returned and then shows you all the results + with their states and values/reasons. This is useful if you want to + handle multiple promises' failure states together as a set. + + Returns a promise that is fulfilled when all the given promises have been + settled, or rejected if the passed parameters are invalid. + + The returned promise is fulfilled with a hash that has the same key names as + the `promises` object argument. If any of the values in the object are not + promises, they will be copied over to the fulfilled object and marked with state + 'fulfilled'. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.Promise.resolve(1), + yourPromise: RSVP.Promise.resolve(2), + theirPromise: RSVP.Promise.resolve(3), + notAPromise: 4 + }; + + RSVP.hashSettled(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: { state: 'fulfilled', value: 1 }, + // yourPromise: { state: 'fulfilled', value: 2 }, + // theirPromise: { state: 'fulfilled', value: 3 }, + // notAPromise: { state: 'fulfilled', value: 4 } + // } + }); + ``` + + If any of the `promises` given to `RSVP.hash` are rejected, the state will + be set to 'rejected' and the reason for rejection provided. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.Promise.resolve(1), + rejectedPromise: RSVP.Promise.reject(new Error('rejection')), + anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')), + }; + + RSVP.hashSettled(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: { state: 'fulfilled', value: 1 }, + // rejectedPromise: { state: 'rejected', reason: Error }, + // anotherRejectedPromise: { state: 'rejected', reason: Error }, + // } + // Note that for rejectedPromise, reason.message == 'rejection', + // and for anotherRejectedPromise, reason.message == 'more rejection'. + }); + ``` + + An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that + are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype + chains. + + Example: + + ```javascript + function MyConstructor(){ + this.example = RSVP.Promise.resolve('Example'); + } + + MyConstructor.prototype = { + protoProperty: RSVP.Promise.resolve('Proto Property') + }; + + var myObject = new MyConstructor(); + + RSVP.hashSettled(myObject).then(function(hash){ + // protoProperty will not be present, instead you will just have an + // object that looks like: + // { + // example: { state: 'fulfilled', value: 'Example' } + // } + // + // hash.hasOwnProperty('protoProperty'); // false + // 'undefined' === typeof hash.protoProperty + }); + ``` + + @method hashSettled + @for RSVP + @param {Object} promises + @param {String} label optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when when all properties of `promises` + have been settled. + @static + */ + __exports__["default"] = function hashSettled(object, label) { + return new HashSettled(Promise, object, label).promise; + } + }); +define("rsvp/hash", + ["./promise","./promise-hash","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var PromiseHash = __dependency2__["default"]; + + /** + `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array + for its `promises` argument. + + Returns a promise that is fulfilled when all the given promises have been + fulfilled, or rejected if any of them become rejected. The returned promise + is fulfilled with a hash that has the same key names as the `promises` object + argument. If any of the values in the object are not promises, they will + simply be copied over to the fulfilled object. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.resolve(1), + yourPromise: RSVP.resolve(2), + theirPromise: RSVP.resolve(3), + notAPromise: 4 + }; + + RSVP.hash(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: 1, + // yourPromise: 2, + // theirPromise: 3, + // notAPromise: 4 + // } + }); + ```` + + If any of the `promises` given to `RSVP.hash` are rejected, the first promise + that is rejected will be given as the reason to the rejection handler. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.resolve(1), + rejectedPromise: RSVP.reject(new Error('rejectedPromise')), + anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')), + }; + + RSVP.hash(promises).then(function(hash){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === 'rejectedPromise' + }); + ``` + + An important note: `RSVP.hash` is intended for plain JavaScript objects that + are just a set of keys and values. `RSVP.hash` will NOT preserve prototype + chains. + + Example: + + ```javascript + function MyConstructor(){ + this.example = RSVP.resolve('Example'); + } + + MyConstructor.prototype = { + protoProperty: RSVP.resolve('Proto Property') + }; + + var myObject = new MyConstructor(); + + RSVP.hash(myObject).then(function(hash){ + // protoProperty will not be present, instead you will just have an + // object that looks like: + // { + // example: 'Example' + // } + // + // hash.hasOwnProperty('protoProperty'); // false + // 'undefined' === typeof hash.protoProperty + }); + ``` + + @method hash + @static + @for RSVP + @param {Object} promises + @param {String} label optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all properties of `promises` + have been fulfilled, or rejected if any of them become rejected. + */ + __exports__["default"] = function hash(object, label) { + return new PromiseHash(Promise, object, label).promise; + } + }); +define("rsvp/instrument", + ["./config","./utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var now = __dependency2__.now; + + var queue = []; + + function scheduleFlush() { + setTimeout(function() { + var entry; + for (var i = 0; i < queue.length; i++) { + entry = queue[i]; + + var payload = entry.payload; + + payload.guid = payload.key + payload.id; + payload.childGuid = payload.key + payload.childId; + if (payload.error) { + payload.stack = payload.error.stack; + } + + config.trigger(entry.name, entry.payload); + } + queue.length = 0; + }, 50); + } + + __exports__["default"] = function instrument(eventName, promise, child) { + if (1 === queue.push({ + name: eventName, + payload: { + key: promise._guidKey, + id: promise._id, + eventName: eventName, + detail: promise._result, + childId: child && child._id, + label: promise._label, + timeStamp: now(), + error: config["instrument-with-stack"] ? new Error(promise._label) : null + }})) { + scheduleFlush(); + } + } + }); +define("rsvp/map", + ["./promise","./utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var isFunction = __dependency2__.isFunction; + + /** + `RSVP.map` is similar to JavaScript's native `map` method, except that it + waits for all promises to become fulfilled before running the `mapFn` on + each item in given to `promises`. `RSVP.map` returns a promise that will + become fulfilled with the result of running `mapFn` on the values the promises + become fulfilled with. + + For example: + + ```javascript + + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.resolve(2); + var promise3 = RSVP.resolve(3); + var promises = [ promise1, promise2, promise3 ]; + + var mapFn = function(item){ + return item + 1; + }; + + RSVP.map(promises, mapFn).then(function(result){ + // result is [ 2, 3, 4 ] + }); + ``` + + If any of the `promises` given to `RSVP.map` are rejected, the first promise + that is rejected will be given as an argument to the returned promise's + rejection handler. For example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error('2')); + var promise3 = RSVP.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + var mapFn = function(item){ + return item + 1; + }; + + RSVP.map(promises, mapFn).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === '2' + }); + ``` + + `RSVP.map` will also wait if a promise is returned from `mapFn`. For example, + say you want to get all comments from a set of blog posts, but you need + the blog posts first because they contain a url to those comments. + + ```javscript + + var mapFn = function(blogPost){ + // getComments does some ajax and returns an RSVP.Promise that is fulfilled + // with some comments data + return getComments(blogPost.comments_url); + }; + + // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled + // with some blog post data + RSVP.map(getBlogPosts(), mapFn).then(function(comments){ + // comments is the result of asking the server for the comments + // of all blog posts returned from getBlogPosts() + }); + ``` + + @method map + @static + @for RSVP + @param {Array} promises + @param {Function} mapFn function to be called on each fulfilled promise. + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled with the result of calling + `mapFn` on each fulfilled promise or value when they become fulfilled. + The promise will be rejected if any of the given `promises` become rejected. + @static + */ + __exports__["default"] = function map(promises, mapFn, label) { + return Promise.all(promises, label).then(function(values) { + if (!isFunction(mapFn)) { + throw new TypeError("You must pass a function as map's second argument."); + } + + var length = values.length; + var results = new Array(length); + + for (var i = 0; i < length; i++) { + results[i] = mapFn(values[i]); + } + + return Promise.all(results, label); + }); + } + }); +define("rsvp/node", + ["./promise","./-internal","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var noop = __dependency2__.noop; + var resolve = __dependency2__.resolve; + var reject = __dependency2__.reject; + var isArray = __dependency3__.isArray; + + function Result() { + this.value = undefined; + } + + var ERROR = new Result(); + var GET_THEN_ERROR = new Result(); + + function getThen(obj) { + try { + return obj.then; + } catch(error) { + ERROR.value= error; + return ERROR; + } + } + + + function tryApply(f, s, a) { + try { + f.apply(s, a); + } catch(error) { + ERROR.value = error; + return ERROR; + } + } + + function makeObject(_, argumentNames) { + var obj = {}; + var name; + var i; + var length = _.length; + var args = new Array(length); + + for (var x = 0; x < length; x++) { + args[x] = _[x]; + } + + for (i = 0; i < argumentNames.length; i++) { + name = argumentNames[i]; + obj[name] = args[i + 1]; + } + + return obj; + } + + function arrayResult(_) { + var length = _.length; + var args = new Array(length - 1); + + for (var i = 1; i < length; i++) { + args[i - 1] = _[i]; + } + + return args; + } + + function wrapThenable(then, promise) { + return { + then: function(onFulFillment, onRejection) { + return then.call(promise, onFulFillment, onRejection); + } + }; + } + + /** + `RSVP.denodeify` takes a 'node-style' function and returns a function that + will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the + browser when you'd prefer to use promises over using callbacks. For example, + `denodeify` transforms the following: + + ```javascript + var fs = require('fs'); + + fs.readFile('myfile.txt', function(err, data){ + if (err) return handleError(err); + handleData(data); + }); + ``` + + into: + + ```javascript + var fs = require('fs'); + var readFile = RSVP.denodeify(fs.readFile); + + readFile('myfile.txt').then(handleData, handleError); + ``` + + If the node function has multiple success parameters, then `denodeify` + just returns the first one: + + ```javascript + var request = RSVP.denodeify(require('request')); + + request('http://example.com').then(function(res) { + // ... + }); + ``` + + However, if you need all success parameters, setting `denodeify`'s + second parameter to `true` causes it to return all success parameters + as an array: + + ```javascript + var request = RSVP.denodeify(require('request'), true); + + request('http://example.com').then(function(result) { + // result[0] -> res + // result[1] -> body + }); + ``` + + Or if you pass it an array with names it returns the parameters as a hash: + + ```javascript + var request = RSVP.denodeify(require('request'), ['res', 'body']); + + request('http://example.com').then(function(result) { + // result.res + // result.body + }); + ``` + + Sometimes you need to retain the `this`: + + ```javascript + var app = require('express')(); + var render = RSVP.denodeify(app.render.bind(app)); + ``` + + The denodified function inherits from the original function. It works in all + environments, except IE 10 and below. Consequently all properties of the original + function are available to you. However, any properties you change on the + denodeified function won't be changed on the original function. Example: + + ```javascript + var request = RSVP.denodeify(require('request')), + cookieJar = request.jar(); // <- Inheritance is used here + + request('http://example.com', {jar: cookieJar}).then(function(res) { + // cookieJar.cookies holds now the cookies returned by example.com + }); + ``` + + Using `denodeify` makes it easier to compose asynchronous operations instead + of using callbacks. For example, instead of: + + ```javascript + var fs = require('fs'); + + fs.readFile('myfile.txt', function(err, data){ + if (err) { ... } // Handle error + fs.writeFile('myfile2.txt', data, function(err){ + if (err) { ... } // Handle error + console.log('done') + }); + }); + ``` + + you can chain the operations together using `then` from the returned promise: + + ```javascript + var fs = require('fs'); + var readFile = RSVP.denodeify(fs.readFile); + var writeFile = RSVP.denodeify(fs.writeFile); + + readFile('myfile.txt').then(function(data){ + return writeFile('myfile2.txt', data); + }).then(function(){ + console.log('done') + }).catch(function(error){ + // Handle error + }); + ``` + + @method denodeify + @static + @for RSVP + @param {Function} nodeFunc a 'node-style' function that takes a callback as + its last argument. The callback expects an error to be passed as its first + argument (if an error occurred, otherwise null), and the value from the + operation as its second argument ('function(err, value){ }'). + @param {Boolean|Array} argumentNames An optional paramter that if set + to `true` causes the promise to fulfill with the callback's success arguments + as an array. This is useful if the node function has multiple success + paramters. If you set this paramter to an array with names, the promise will + fulfill with a hash with these names as keys and the success parameters as + values. + @return {Function} a function that wraps `nodeFunc` to return an + `RSVP.Promise` + @static + */ + __exports__["default"] = function denodeify(nodeFunc, options) { + var fn = function() { + var self = this; + var l = arguments.length; + var args = new Array(l + 1); + var arg; + var promiseInput = false; + + for (var i = 0; i < l; ++i) { + arg = arguments[i]; + + if (!promiseInput) { + // TODO: clean this up + promiseInput = needsPromiseInput(arg); + if (promiseInput === GET_THEN_ERROR) { + var p = new Promise(noop); + reject(p, GET_THEN_ERROR.value); + return p; + } else if (promiseInput && promiseInput !== true) { + arg = wrapThenable(promiseInput, arg); + } + } + args[i] = arg; + } + + var promise = new Promise(noop); + + args[l] = function(err, val) { + if (err) + reject(promise, err); + else if (options === undefined) + resolve(promise, val); + else if (options === true) + resolve(promise, arrayResult(arguments)); + else if (isArray(options)) + resolve(promise, makeObject(arguments, options)); + else + resolve(promise, val); + }; + + if (promiseInput) { + return handlePromiseInput(promise, args, nodeFunc, self); + } else { + return handleValueInput(promise, args, nodeFunc, self); + } + }; + + fn.__proto__ = nodeFunc; + + return fn; + } + + function handleValueInput(promise, args, nodeFunc, self) { + var result = tryApply(nodeFunc, self, args); + if (result === ERROR) { + reject(promise, result.value); + } + return promise; + } + + function handlePromiseInput(promise, args, nodeFunc, self){ + return Promise.all(args).then(function(args){ + var result = tryApply(nodeFunc, self, args); + if (result === ERROR) { + reject(promise, result.value); + } + return promise; + }); + } + + function needsPromiseInput(arg) { + if (arg && typeof arg === 'object') { + if (arg.constructor === Promise) { + return true; + } else { + return getThen(arg); + } + } else { + return false; + } + } + }); +define("rsvp/promise-hash", + ["./enumerator","./-internal","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + var PENDING = __dependency2__.PENDING; + var o_create = __dependency3__.o_create; + + function PromiseHash(Constructor, object, label) { + this._superConstructor(Constructor, object, true, label); + } + + __exports__["default"] = PromiseHash; + + PromiseHash.prototype = o_create(Enumerator.prototype); + PromiseHash.prototype._superConstructor = Enumerator; + PromiseHash.prototype._init = function() { + this._result = {}; + }; + + PromiseHash.prototype._validateInput = function(input) { + return input && typeof input === 'object'; + }; + + PromiseHash.prototype._validationError = function() { + return new Error('Promise.hash must be called with an object'); + }; + + PromiseHash.prototype._enumerate = function() { + var promise = this.promise; + var input = this._input; + var results = []; + + for (var key in input) { + if (promise._state === PENDING && input.hasOwnProperty(key)) { + results.push({ + position: key, + entry: input[key] + }); + } + } + + var length = results.length; + this._remaining = length; + var result; + + for (var i = 0; promise._state === PENDING && i < length; i++) { + result = results[i]; + this._eachEntry(result.entry, result.position); + } + }; + }); +define("rsvp/promise", + ["./config","./instrument","./utils","./-internal","./promise/all","./promise/race","./promise/resolve","./promise/reject","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var instrument = __dependency2__["default"]; + + var isFunction = __dependency3__.isFunction; + var now = __dependency3__.now; + + var noop = __dependency4__.noop; + var subscribe = __dependency4__.subscribe; + var initializePromise = __dependency4__.initializePromise; + var invokeCallback = __dependency4__.invokeCallback; + var FULFILLED = __dependency4__.FULFILLED; + var REJECTED = __dependency4__.REJECTED; + + var all = __dependency5__["default"]; + var race = __dependency6__["default"]; + var Resolve = __dependency7__["default"]; + var Reject = __dependency8__["default"]; + + var guidKey = 'rsvp_' + now() + '-'; + var counter = 0; + + function needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); + } + + function needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); + } + __exports__["default"] = Promise; + /** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise’s eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + var promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + var xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class RSVP.Promise + @param {function} resolver + @param {String} label optional string for labeling the promise. + Useful for tooling. + @constructor + */ + function Promise(resolver, label) { + this._id = counter++; + this._label = label; + this._state = undefined; + this._result = undefined; + this._subscribers = []; + + if (config.instrument) { + instrument('created', this); + } + + if (noop !== resolver) { + if (!isFunction(resolver)) { + needsResolver(); + } + + if (!(this instanceof Promise)) { + needsNew(); + } + + initializePromise(this, resolver); + } + } + + Promise.cast = Resolve; // deprecated + Promise.all = all; + Promise.race = race; + Promise.resolve = Resolve; + Promise.reject = Reject; + + Promise.prototype = { + constructor: Promise, + + _guidKey: guidKey, + + _onerror: function (reason) { + config.trigger('error', reason); + }, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + var result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + var author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + then: function(onFulfillment, onRejection, label) { + var parent = this; + var state = parent._state; + + if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) { + if (config.instrument) { + instrument('chained', this, this); + } + return this; + } + + parent._onerror = null; + + var child = new this.constructor(noop, label); + var result = parent._result; + + if (config.instrument) { + instrument('chained', parent, child); + } + + if (state) { + var callback = arguments[state - 1]; + config.async(function(){ + invokeCallback(state, child, callback, result); + }); + } else { + subscribe(parent, child, onFulfillment, onRejection); + } + + return child; + }, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + 'catch': function(onRejection, label) { + return this.then(null, onRejection, label); + }, + + /** + `finally` will be invoked regardless of the promise's fate just as native + try/catch/finally behaves + + Synchronous example: + + ```js + findAuthor() { + if (Math.random() > 0.5) { + throw new Error(); + } + return new Author(); + } + + try { + return findAuthor(); // succeed or fail + } catch(error) { + return findOtherAuther(); + } finally { + // always runs + // doesn't affect the return value + } + ``` + + Asynchronous example: + + ```js + findAuthor().catch(function(reason){ + return findOtherAuther(); + }).finally(function(){ + // author was either found, or not + }); + ``` + + @method finally + @param {Function} callback + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + 'finally': function(callback, label) { + var constructor = this.constructor; + + return this.then(function(value) { + return constructor.resolve(callback()).then(function(){ + return value; + }); + }, function(reason) { + return constructor.resolve(callback()).then(function(){ + throw reason; + }); + }, label); + } + }; + }); +define("rsvp/promise/all", + ["../enumerator","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + + /** + `RSVP.Promise.all` accepts an array of promises, and returns a new promise which + is fulfilled with an array of fulfillment values for the passed promises, or + rejected with the reason of the first passed promise to be rejected. It casts all + elements of the passed iterable to promises as it runs this algorithm. + + Example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.resolve(2); + var promise3 = RSVP.resolve(3); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.Promise.all(promises).then(function(array){ + // The array here would be [ 1, 2, 3 ]; + }); + ``` + + If any of the `promises` given to `RSVP.all` are rejected, the first promise + that is rejected will be given as an argument to the returned promises's + rejection handler. For example: + + Example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error("2")); + var promise3 = RSVP.reject(new Error("3")); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.Promise.all(promises).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(error) { + // error.message === "2" + }); + ``` + + @method all + @static + @param {Array} entries array of promises + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all `promises` have been + fulfilled, or rejected if any of them become rejected. + @static + */ + __exports__["default"] = function all(entries, label) { + return new Enumerator(this, entries, true /* abort on reject */, label).promise; + } + }); +define("rsvp/promise/race", + ["../utils","../-internal","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var isArray = __dependency1__.isArray; + + var noop = __dependency2__.noop; + var resolve = __dependency2__.resolve; + var reject = __dependency2__.reject; + var subscribe = __dependency2__.subscribe; + var PENDING = __dependency2__.PENDING; + + /** + `RSVP.Promise.race` returns a new promise which is settled in the same way as the + first passed promise to settle. + + Example: + + ```javascript + var promise1 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + var promise2 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 2'); + }, 100); + }); + + RSVP.Promise.race([promise1, promise2]).then(function(result){ + // result === 'promise 2' because it was resolved before promise1 + // was resolved. + }); + ``` + + `RSVP.Promise.race` is deterministic in that only the state of the first + settled promise matters. For example, even if other promises given to the + `promises` array argument are resolved, but the first settled promise has + become rejected before the other promises became fulfilled, the returned + promise will become rejected: + + ```javascript + var promise1 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + var promise2 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + reject(new Error('promise 2')); + }, 100); + }); + + RSVP.Promise.race([promise1, promise2]).then(function(result){ + // Code here never runs + }, function(reason){ + // reason.message === 'promise 2' because promise 2 became rejected before + // promise 1 became fulfilled + }); + ``` + + An example real-world use case is implementing timeouts: + + ```javascript + RSVP.Promise.race([ajax('foo.json'), timeout(5000)]) + ``` + + @method race + @static + @param {Array} promises array of promises to observe + @param {String} label optional string for describing the promise returned. + Useful for tooling. + @return {Promise} a promise which settles in the same way as the first passed + promise to settle. + */ + __exports__["default"] = function race(entries, label) { + /*jshint validthis:true */ + var Constructor = this; + + var promise = new Constructor(noop, label); + + if (!isArray(entries)) { + reject(promise, new TypeError('You must pass an array to race.')); + return promise; + } + + var length = entries.length; + + function onFulfillment(value) { + resolve(promise, value); + } + + function onRejection(reason) { + reject(promise, reason); + } + + for (var i = 0; promise._state === PENDING && i < length; i++) { + subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); + } + + return promise; + } + }); +define("rsvp/promise/reject", + ["../-internal","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var noop = __dependency1__.noop; + var _reject = __dependency1__.reject; + + /** + `RSVP.Promise.reject` returns a promise rejected with the passed `reason`. + It is shorthand for the following: + + ```javascript + var promise = new RSVP.Promise(function(resolve, reject){ + reject(new Error('WHOOPS')); + }); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + var promise = RSVP.Promise.reject(new Error('WHOOPS')); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + @method reject + @static + @param {Any} reason value that the returned promise will be rejected with. + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. + */ + __exports__["default"] = function reject(reason, label) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(noop, label); + _reject(promise, reason); + return promise; + } + }); +define("rsvp/promise/resolve", + ["../-internal","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var noop = __dependency1__.noop; + var _resolve = __dependency1__.resolve; + + /** + `RSVP.Promise.resolve` returns a promise that will become resolved with the + passed `value`. It is shorthand for the following: + + ```javascript + var promise = new RSVP.Promise(function(resolve, reject){ + resolve(1); + }); + + promise.then(function(value){ + // value === 1 + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + var promise = RSVP.Promise.resolve(1); + + promise.then(function(value){ + // value === 1 + }); + ``` + + @method resolve + @static + @param {Any} value value that the returned promise will be resolved with + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` + */ + __exports__["default"] = function resolve(object, label) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(noop, label); + _resolve(promise, object); + return promise; + } + }); +define("rsvp/race", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.race`. + + @method race + @static + @for RSVP + @param {Array} array Array of promises. + @param {String} label An optional label. This is useful + for tooling. + */ + __exports__["default"] = function race(array, label) { + return Promise.race(array, label); + } + }); +define("rsvp/reject", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.reject`. + + @method reject + @static + @for RSVP + @param {Any} reason value that the returned promise will be rejected with. + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. + */ + __exports__["default"] = function reject(reason, label) { + return Promise.reject(reason, label); + } + }); +define("rsvp/resolve", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.resolve`. + + @method resolve + @static + @for RSVP + @param {Any} value value that the returned promise will be resolved with + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` + */ + __exports__["default"] = function resolve(value, label) { + return Promise.resolve(value, label); + } + }); +define("rsvp/rethrow", + ["exports"], + function(__exports__) { + "use strict"; + /** + `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event + loop in order to aid debugging. + + Promises A+ specifies that any exceptions that occur with a promise must be + caught by the promises implementation and bubbled to the last handler. For + this reason, it is recommended that you always specify a second rejection + handler function to `then`. However, `RSVP.rethrow` will throw the exception + outside of the promise, so it bubbles up to your console if in the browser, + or domain/cause uncaught exception in Node. `rethrow` will also throw the + error again so the error can be handled by the promise per the spec. + + ```javascript + function throws(){ + throw new Error('Whoops!'); + } + + var promise = new RSVP.Promise(function(resolve, reject){ + throws(); + }); + + promise.catch(RSVP.rethrow).then(function(){ + // Code here doesn't run because the promise became rejected due to an + // error! + }, function (err){ + // handle the error here + }); + ``` + + The 'Whoops' error will be thrown on the next turn of the event loop + and you can watch for it in your console. You can also handle it using a + rejection handler given to `.then` or `.catch` on the returned promise. + + @method rethrow + @static + @for RSVP + @param {Error} reason reason the promise became rejected. + @throws Error + @static + */ + __exports__["default"] = function rethrow(reason) { + setTimeout(function() { + throw reason; + }); + throw reason; + } + }); +define("rsvp/utils", + ["exports"], + function(__exports__) { + "use strict"; + function objectOrFunction(x) { + return typeof x === 'function' || (typeof x === 'object' && x !== null); + } + + __exports__.objectOrFunction = objectOrFunction;function isFunction(x) { + return typeof x === 'function'; + } + + __exports__.isFunction = isFunction;function isMaybeThenable(x) { + return typeof x === 'object' && x !== null; + } + + __exports__.isMaybeThenable = isMaybeThenable;var _isArray; + if (!Array.isArray) { + _isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; + } else { + _isArray = Array.isArray; + } + + var isArray = _isArray; + __exports__.isArray = isArray; + // Date.now is not available in browsers < IE9 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility + var now = Date.now || function() { return new Date().getTime(); }; + __exports__.now = now; + function F() { } + + var o_create = (Object.create || function (o) { + if (arguments.length > 1) { + throw new Error('Second argument not supported'); + } + if (typeof o !== 'object') { + throw new TypeError('Argument must be an object'); + } + F.prototype = o; + return new F(); + }); + __exports__.o_create = o_create; + }); +requireModule("ember"); + +})(); \ No newline at end of file diff --git a/ajax/libs/ember.js/1.8.0-beta.4/ember.min.js b/ajax/libs/ember.js/1.8.0-beta.4/ember.min.js new file mode 100644 index 000000000..6a55357d9 --- /dev/null +++ b/ajax/libs/ember.js/1.8.0-beta.4/ember.min.js @@ -0,0 +1,12 @@ +!function(){var e,t,r,n,i;!function(){if(i=this.Ember=this.Ember||{},"undefined"==typeof i&&(i={}),"undefined"==typeof i.__loader){var a={},s={};e=function(e,t,r){a[e]={deps:t,callback:r}},n=r=t=function(e){function r(t){if("."!==t.charAt(0))return t;for(var r=t.split("/"),n=e.split("/").slice(0,-1),i=0,a=r.length;a>i;i++){var s=r[i];if(".."===s)n.pop();else{if("."===s)continue;n.push(s)}}return n.join("/")}if(s.hasOwnProperty(e))return s[e];if(s[e]={},!a[e])throw new Error("Could not find module "+e);for(var n,i=a[e],o=i.deps,u=i.callback,l=[],c=0,h=o.length;h>c;c++)l.push("exports"===o[c]?n={}:t(r(o[c])));var p=u.apply(this,l);return s[e]=n||p},n._eak_seen=a,i.__loader={define:e,require:r,registry:a}}else e=i.__loader.define,n=r=t=i.__loader.require}(),e("backburner",["backburner/utils","backburner/platform","backburner/binary-search","backburner/deferred-action-queues","exports"],function(e,t,r,n,i){"use strict";function a(e,t){this.queueNames=e,this.options=t||{},this.options.defaultQueue||(this.options.defaultQueue=e[0]),this.instanceStack=[],this._debouncees=[],this._throttlers=[],this._timers=[]}function s(e){return e.onError||e.onErrorTarget&&e.onErrorTarget[e.onErrorMethod]}function o(e){e.begin(),e._autorun=P.setTimeout(function(){e._autorun=null,e.end()})}function u(e,t,r){var n=y();(!e._laterTimer||tr;r+=2)e.schedule(e.options.defaultQueue,null,t[r])}),e._timers.length&&u(e,e._timers[0],e._timers[0]-i)}function c(e,t,r){return p(e,t,r)}function h(e,t,r){return p(e,t,r)}function p(e,t,r){for(var n,i=-1,a=0,s=r.length;s>a;a++)if(n=r[a],n[0]===e&&n[1]===t){i=a;break}return i}var m=e.each,f=e.isString,d=e.isFunction,v=e.isNumber,b=e.isCoercableNumber,g=e.wrapInTryCatch,y=e.now,_=t.needsIETryCatchFix,w=r["default"],x=n["default"],C=[].slice,O=[].pop,P=this;if(a.prototype={begin:function(){var e=this.options,t=e&&e.onBegin,r=this.currentInstance;r&&this.instanceStack.push(r),this.currentInstance=new x(this.queueNames,e),t&&t(this.currentInstance,r)},end:function(){var e=this.options,t=e&&e.onEnd,r=this.currentInstance,n=null,i=!1;try{r.flush()}finally{i||(i=!0,this.currentInstance=null,this.instanceStack.length&&(n=this.instanceStack.pop(),this.currentInstance=n),t&&t(r,n))}},run:function(e,t){var r=s(this.options);this.begin(),t||(t=e,e=null),f(t)&&(t=e[t]);var n=C.call(arguments,2),i=!1;if(r)try{return t.apply(e,n)}catch(a){r(a)}finally{i||(i=!0,this.end())}else try{return t.apply(e,n)}finally{i||(i=!0,this.end())}},defer:function(e,t,r){r||(r=t,t=null),f(r)&&(r=t[r]);var n,i=this.DEBUG?new Error:void 0,a=arguments.length;if(a>3){n=new Array(a-3);for(var s=3;a>s;s++)n[s-3]=arguments[s]}else n=void 0;return this.currentInstance||o(this),this.currentInstance.schedule(e,t,r,n,!1,i)},deferOnce:function(e,t,r){r||(r=t,t=null),f(r)&&(r=t[r]);var n,i=this.DEBUG?new Error:void 0,a=arguments.length;if(a>3){n=new Array(a-3);for(var s=3;a>s;s++)n[s-3]=arguments[s]}else n=void 0;return this.currentInstance||o(this),this.currentInstance.schedule(e,t,r,n,!0,i)},setTimeout:function(){function e(){if(g)try{i.apply(o,r)}catch(e){g(e)}else i.apply(o,r)}for(var t=arguments.length,r=new Array(t),n=0;t>n;n++)r[n]=arguments[n];var i,a,o,l,c,h,p=r.length;if(0!==p){if(1===p)i=r.shift(),a=0;else if(2===p)l=r[0],c=r[1],d(c)||d(l[c])?(o=r.shift(),i=r.shift(),a=0):b(c)?(i=r.shift(),a=r.shift()):(i=r.shift(),a=0);else{var m=r[r.length-1];a=b(m)?r.pop():0,l=r[0],h=r[1],d(h)||f(h)&&null!==l&&h in l?(o=r.shift(),i=r.shift()):i=r.shift()}var v=y()+parseInt(a,10);f(i)&&(i=o[i]);var g=s(this.options),_=w(v,this._timers);return this._timers.splice(_,0,v,e),u(this,v,a),e}},throttle:function(e,t){var r,n,i,a,s=this,o=arguments,u=O.call(o);return v(u)||f(u)?(r=u,u=!0):r=O.call(o),r=parseInt(r,10),i=h(e,t,this._throttlers),i>-1?this._throttlers[i]:(a=P.setTimeout(function(){u||s.run.apply(s,o);var r=h(e,t,s._throttlers);r>-1&&s._throttlers.splice(r,1)},r),u&&this.run.apply(this,o),n=[e,t,a],this._throttlers.push(n),n)},debounce:function(e,t){var r,n,i,a,s=this,o=arguments,u=O.call(o);return v(u)||f(u)?(r=u,u=!1):r=O.call(o),r=parseInt(r,10),n=c(e,t,this._debouncees),n>-1&&(i=this._debouncees[n],this._debouncees.splice(n,1),clearTimeout(i[2])),a=P.setTimeout(function(){u||s.run.apply(s,o);var r=c(e,t,s._debouncees);r>-1&&s._debouncees.splice(r,1)},r),u&&-1===n&&s.run.apply(s,o),i=[e,t,a],s._debouncees.push(i),i},cancelTimers:function(){var e=function(e){clearTimeout(e[2])};m(this._throttlers,e),this._throttlers=[],m(this._debouncees,e),this._debouncees=[],this._laterTimer&&(clearTimeout(this._laterTimer),this._laterTimer=null),this._timers=[],this._autorun&&(clearTimeout(this._autorun),this._autorun=null)},hasTimers:function(){return!!this._timers.length||!!this._debouncees.length||!!this._throttlers.length||this._autorun},cancel:function(e){var t=typeof e;if(e&&"object"===t&&e.queue&&e.method)return e.queue.cancel(e);if("function"!==t)return"[object Array]"===Object.prototype.toString.call(e)?this._cancelItem(h,this._throttlers,e)||this._cancelItem(c,this._debouncees,e):void 0;for(var r=0,n=this._timers.length;n>r;r+=2)if(this._timers[r+1]===e)return this._timers.splice(r,2),0===r&&(this._laterTimer&&(clearTimeout(this._laterTimer),this._laterTimer=null),this._timers.length>0&&u(this,this._timers[0],this._timers[0]-y())),!0},_cancelItem:function(e,t,r){var n,i;return r.length<3?!1:(i=e(r[0],r[1],t),i>-1&&(n=t[i],n[2]===r[2])?(t.splice(i,1),clearTimeout(r[2]),!0):!1)}},a.prototype.schedule=a.prototype.defer,a.prototype.scheduleOnce=a.prototype.deferOnce,a.prototype.later=a.prototype.setTimeout,_){var E=a.prototype.run;a.prototype.run=g(E);var A=a.prototype.end;a.prototype.end=g(A)}i["default"]=a}),e("backburner.umd",["./backburner"],function(t){"use strict";var r=t["default"];"function"==typeof e&&e.amd?e(function(){return r}):"undefined"!=typeof module&&module.exports?module.exports=r:"undefined"!=typeof this&&(this.Backburner=r)}),e("backburner/binary-search",["exports"],function(e){"use strict";e["default"]=function(e,t){for(var r,n,i=0,a=t.length-2;a>i;)n=(a-i)/2,r=i+n-n%2,e>=t[r]?i=r+2:a=r;return e>=t[i]?i+2:i}}),e("backburner/deferred-action-queues",["./utils","./queue","exports"],function(e,t,r){"use strict";function n(e,t){var r=this.queues={};this.queueNames=e=e||[],this.options=t,s(e,function(e){r[e]=new u(e,t[e],t)})}function i(e){throw new Error("You attempted to schedule an action in a queue ("+e+") that doesn't exist")}function a(e,t){for(var r,n,i=0,a=t;a>=i;i++)if(r=e.queueNames[i],n=e.queues[r],n._queue.length)return i;return-1}var s=e.each,o=e.isString,u=t["default"];n.prototype={schedule:function(e,t,r,n,a,s){var o=this.queues,u=o[e];return u||i(e),a?u.pushUnique(t,r,n,s):u.push(t,r,n,s)},invoke:function(e,t,r){r&&r.length>0?t.apply(e,r):t.call(e)},invokeWithOnError:function(e,t,r,n,i){try{r&&r.length>0?t.apply(e,r):t.call(e)}catch(a){n(a,i)}},flush:function(){for(var e,t,r,n,i=this.queues,s=this.queueNames,u=0,l=s.length,c=this.options,h=c.onError||c.onErrorTarget&&c.onErrorTarget[c.onErrorMethod],p=h?this.invokeWithOnError:this.invoke;l>u;){e=s[u],t=i[e],r=t._queueBeingFlushed=t._queue.slice(),t._queue=[],t.targetQueues=Object.create(null);var m,f,d,v,b=t.options,g=b&&b.before,y=b&&b.after,_=0,w=r.length;for(w&&g&&g();w>_;)m=r[_],f=r[_+1],d=r[_+2],v=r[_+3],o(f)&&(f=m[f]),f&&p(m,f,d,h,v),_+=4;t._queueBeingFlushed=null,w&&y&&y(),-1!==(n=a(this,u))?u=n:u++}}},r["default"]=n}),e("backburner/platform",["exports"],function(e){"use strict";var t=function(e,t){try{t()}catch(e){}return!!e}();e.needsIETryCatchFix=t}),e("backburner/queue",["exports"],function(e){"use strict";function t(e,t,r){this.name=e,this.globalOptions=r||{},this.options=t,this._queue=[],this.targetQueues=Object.create(null),this._queueBeingFlushed=void 0}t.prototype={push:function(e,t,r,n){var i=this._queue;return i.push(e,t,r,n),{queue:this,target:e,method:t}},pushUniqueWithoutGuid:function(e,t,r,n){for(var i=this._queue,a=0,s=i.length;s>a;a+=4){var o=i[a],u=i[a+1];if(o===e&&u===t)return i[a+2]=r,void(i[a+3]=n)}i.push(e,t,r,n)},targetQueue:function(e,t,r,n,i){for(var a=this._queue,s=0,o=e.length;o>s;s+=4){var u=e[s],l=e[s+1];if(u===r)return a[l+2]=n,void(a[l+3]=i)}e.push(r,a.push(t,r,n,i)-4)},pushUniqueWithGuid:function(e,t,r,n,i){var a=this.targetQueues[e];return a?this.targetQueue(a,t,r,n,i):this.targetQueues[e]=[r,this._queue.push(t,r,n,i)-4],{queue:this,target:t,method:r}},pushUnique:function(e,t,r,n){var i=(this._queue,this.globalOptions.GUID_KEY);if(e&&i){var a=e[i];if(a)return this.pushUniqueWithGuid(a,e,t,r,n)}return this.pushUniqueWithoutGuid(e,t,r,n),{queue:this,target:e,method:t}},flush:function(){var e,t,r,n,i,a=this._queue,s=this.globalOptions,o=this.options,u=o&&o.before,l=o&&o.after,c=s.onError||s.onErrorTarget&&s.onErrorTarget[s.onErrorMethod],h=a.length;for(this.targetQueues=Object.create(null),h&&u&&u(),i=0;h>i;i+=4)if(e=a[i],t=a[i+1],r=a[i+2],n=a[i+3],r&&r.length>0)if(c)try{t.apply(e,r)}catch(p){c(p)}else t.apply(e,r);else if(c)try{t.call(e)}catch(p){c(p)}else t.call(e);h&&l&&l(),a.length>h?(this._queue=a.slice(h),this.flush()):this._queue.length=0},cancel:function(e){var t,r,n,i,a=this._queue,s=e.target,o=e.method,u=this.globalOptions.GUID_KEY;if(u&&this.targetQueues&&s){var l=this.targetQueues[s[u]];if(l)for(n=0,i=l.length;i>n;n++)l[n]===o&&l.splice(n,1)}for(n=0,i=a.length;i>n;n+=4)if(t=a[n],r=a[n+1],t===s&&r===o)return a.splice(n,4),!0;if(a=this._queueBeingFlushed)for(n=0,i=a.length;i>n;n+=4)if(t=a[n],r=a[n+1],t===s&&r===o)return a[n+1]=null,!0}},e["default"]=t}),e("backburner/utils",["exports"],function(e){"use strict";function t(e,t){for(var r=0;r-1){try{if(e.existsSync(s)){var o,u=e.readFileSync(s,{encoding:"utf8"}),l=u.split("/").slice(-1)[0].trim(),c=u.split(" ")[1];if(c){var h=t.join(a,c.trim());o=e.readFileSync(h)}else o=l;i.push(o.slice(0,10))}}catch(p){console.error(p.stack)}return i.join(".")}return n}}),e("container",["container/container","exports"],function(e,t){"use strict";i.MODEL_FACTORY_INJECTIONS=!1,i.ENV&&"undefined"!=typeof i.ENV.MODEL_FACTORY_INJECTIONS&&(i.MODEL_FACTORY_INJECTIONS=!!i.ENV.MODEL_FACTORY_INJECTIONS);var r=e["default"];t["default"]=r}),e("container/container",["ember-metal/core","ember-metal/keys","ember-metal/dictionary","exports"],function(e,t,r,n){"use strict";function i(e){this.parent=e,this.children=[],this.resolver=e&&e.resolver||function(){},this.registry=C(e?e.registry:null),this.cache=C(e?e.cache:null),this.factoryCache=C(e?e.factoryCache:null),this.resolveCache=C(e?e.resolveCache:null),this.typeInjections=C(e?e.typeInjections:null),this.injections=C(null),this.normalizeCache=C(null),this.factoryTypeInjections=C(e?e.factoryTypeInjections:null),this.factoryInjections=C(null),this._options=C(e?e._options:null),this._typeOptions=C(e?e._typeOptions:null)}function a(e,t){var r=e.resolveCache[t];if(r)return r;var n=e.resolver(t)||e.registry[t];return e.resolveCache[t]=n,n}function s(e,t){return e.cache[t]?!0:!!e.resolve(t)}function o(e,t,r){if(r=r||{},e.cache[t]&&r.singleton!==!1)return e.cache[t];var n=d(e,t);return void 0!==n?(l(e,t)&&r.singleton!==!1&&(e.cache[t]=n),n):void 0}function u(e){throw new Error(e+" is not currently supported on child containers")}function l(e,t){var r=h(e,t,"singleton");return r!==!1}function c(e,t){var r={};if(!t)return r;for(var n,i,a=0,s=t.length;s>a;a++){if(n=t[a],i=o(e,n.fullName),void 0===i)throw new Error("Attempting to inject an unknown injection: `"+n.fullName+"`");r[n.property]=i}return r}function h(e,t,r){var n=e._options[t];if(n&&void 0!==n[r])return n[r];var i=t.split(":")[0];return n=e._typeOptions[i],n?n[r]:void 0}function p(e,t){var r=e.factoryCache;if(r[t])return r[t];var n=e.resolve(t);if(void 0!==n){var i=t.split(":")[0];if(!n||"function"!=typeof n.extend||!w.MODEL_FACTORY_INJECTIONS&&"model"===i)return r[t]=n,n;var a=m(e,t),s=f(e,t);s._toString=e.makeToString(n,t);var o=n.extend(a);return o.reopenClass(s),r[t]=o,o}}function m(e,t){var r=t.split(":"),n=r[0],i=[];return i=i.concat(e.typeInjections[n]||[]),i=i.concat(e.injections[t]||[]),i=c(e,i),i._debugContainerKey=t,i.container=e,i}function f(e,t){var r=t.split(":"),n=r[0],i=[];return i=i.concat(e.factoryTypeInjections[n]||[]),i=i.concat(e.factoryInjections[t]||[]),i=c(e,i),i._debugContainerKey=t,i}function d(e,t){var r=p(e,t);if(h(e,t,"instantiate")===!1)return r;if(r){if("function"!=typeof r.create)throw new Error("Failed to create an instance of '"+t+"'. Most likely an improperly defined class or an invalid module export.");return"function"==typeof r.extend?r.create():r.create(m(e,t))}}function v(e,t){for(var r,n,i=e.cache,a=x(i),s=0,o=a.length;o>s;s++)r=a[s],n=i[r],h(e,r,"instantiate")!==!1&&t(n)}function b(e){v(e,function(e){e.destroy()}),e.cache.dict=C(null)}function g(e,t,r,n){var i=e[t];i||(i=[],e[t]=i),i.push({property:r,fullName:n})}function y(e){if(!O.test(e))throw new TypeError("Invalid Fullname, expected: `type:name` got: "+e);return!0}function _(e,t,r,n){var i=e[t]=e[t]||[];i.push({property:r,fullName:n})}var w=e["default"],x=t["default"],C=r["default"];i.prototype={parent:null,children:null,resolver:null,registry:null,cache:null,typeInjections:null,injections:null,_options:null,_typeOptions:null,child:function(){var e=new i(this);return this.children.push(e),e},set:function(e,t,r){e[t]=r},register:function(e,t,r){if(void 0===t)throw new TypeError("Attempting to register an unknown factory: `"+e+"`");var n=this.normalize(e);if(n in this.cache)throw new Error("Cannot re-register: `"+e+"`, as it has already been looked up.");this.registry[n]=t,this._options[n]=r||{}},unregister:function(e){var t=this.normalize(e);delete this.registry[t],delete this.cache[t],delete this.factoryCache[t],delete this.resolveCache[t],delete this._options[t]},resolve:function(e){return a(this,this.normalize(e))},describe:function(e){return e},normalizeFullName:function(e){return e},normalize:function(e){return this.normalizeCache[e]||(this.normalizeCache[e]=this.normalizeFullName(e))},makeToString:function(e){return e.toString()},lookup:function(e,t){return o(this,this.normalize(e),t)},lookupFactory:function(e){return p(this,this.normalize(e))},has:function(e){return s(this,this.normalize(e))},optionsForType:function(e,t){this.parent&&u("optionsForType"),this._typeOptions[e]=t},options:function(e,t){this.optionsForType(e,t)},typeInjection:function(e,t,r){this.parent&&u("typeInjection");var n=r.split(":")[0];if(n===e)throw new Error("Cannot inject a `"+r+"` on other "+e+"(s). Register the `"+r+"` as a different type and perform the typeInjection.");g(this.typeInjections,e,t,r)},injection:function(e,t,r){this.parent&&u("injection"),y(r);var n=this.normalize(r);if(-1===e.indexOf(":"))return this.typeInjection(e,t,n);var i=this.normalize(e);if(this.cache[i])throw new Error("Attempted to register an injection for a type that has already been looked up. ('"+i+"', '"+t+"', '"+r+"')");_(this.injections,i,t,n)},factoryTypeInjection:function(e,t,r){this.parent&&u("factoryTypeInjection"),g(this.factoryTypeInjections,e,t,this.normalize(r))},factoryInjection:function(e,t,r){this.parent&&u("injection");var n=this.normalize(e),i=this.normalize(r);if(y(r),-1===e.indexOf(":"))return this.factoryTypeInjection(n,t,i);if(this.factoryCache[n])throw new Error("Attempted to register a factoryInjection for a type that has already been looked up. ('"+n+"', '"+t+"', '"+r+"')");_(this.factoryInjections,n,t,i)},destroy:function(){for(var e=0,t=this.children.length;t>e;e++)this.children[e].destroy();this.children=[],v(this,function(e){e.destroy()}),this.parent=void 0,this.isDestroyed=!0},reset:function(){for(var e=0,t=this.children.length;t>e;e++)b(this.children[e]);b(this)}};var O=/^[^:]+.+:[^:]+$/;n["default"]=i}),e("ember-application",["ember-metal/core","ember-runtime/system/lazy_load","ember-application/system/dag","ember-application/system/resolver","ember-application/system/application","ember-application/ext/controller"],function(e,t,r,n,i){"use strict";var a=e["default"],s=t.runLoadHooks,o=r["default"],u=n.Resolver,l=n["default"],c=i["default"];a.Application=c,a.DAG=o,a.Resolver=u,a.DefaultResolver=l,s("Ember.Application",c)}),e("ember-application/ext/controller",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/error","ember-metal/utils","ember-metal/computed","ember-runtime/mixins/controller","ember-routing/system/controller_for","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(e,t,r){var n,i,a,s=[];for(i=0,a=r.length;a>i;i++)n=r[i],-1===n.indexOf(":")&&(n="controller:"+n),t.has(n)||s.push(n);if(s.length)throw new h(p(e)+" needs [ "+s.join(", ")+" ] but "+(s.length>1?"they":"it")+" could not be found")}var c=(e["default"],t.get),h=(r.set,n["default"]),p=i.inspect,m=a.computed,f=s["default"],d=(i.meta,o["default"]),v=m(function(){var e=this;return{needs:c(e,"needs"),container:c(e,"container"),unknownProperty:function(t){var r,n,i,a=this.needs;for(n=0,i=a.length;i>n;n++)if(r=a[n],r===t)return this.container.lookup("controller:"+t);var s=p(e)+"#needs does not include `"+t+"`. To access the "+t+" controller from "+p(e)+", "+p(e)+" should have a `needs` property that is an array of the controllers it has access to.";throw new ReferenceError(s)},setUnknownProperty:function(t){throw new Error("You cannot overwrite the value of `controllers."+t+"` of "+p(e))}}});f.reopen({concatenatedProperties:["needs"],needs:[],init:function(){var e=c(this,"needs"),t=c(e,"length");t>0&&(this.container&&l(this,this.container,e),c(this,"controllers")),this._super.apply(this,arguments)},controllerFor:function(e){return d(c(this,"container"),e)},controllers:v}),u["default"]=f}),e("ember-application/system/application",["ember-metal","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-application/system/dag","ember-runtime/system/namespace","ember-runtime/mixins/deferred","ember-application/system/resolver","ember-metal/platform","ember-metal/run_loop","ember-metal/utils","container/container","ember-runtime/controllers/controller","ember-metal/enumerable_utils","ember-runtime/controllers/object_controller","ember-runtime/controllers/array_controller","ember-handlebars/controls/select","ember-views/system/event_dispatcher","ember-views/system/jquery","ember-routing/system/route","ember-routing/system/router","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/location/none_location","ember-routing/system/cache","ember-metal/core","ember-handlebars-compiler","exports"],function(e,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,g,y,_,w,x,C,O,P,E,A,T,N){"use strict";function S(e){var t=[];for(var r in e)t.push(r);return t}function V(e){function t(e){return n.resolve(e)}e.get("resolver");var r=e.get("resolver")||e.get("Resolver")||z,n=r.create({namespace:e});return t.describe=function(e){return n.lookupDescription(e)},t.makeToString=function(e,t){return n.makeToString(e,t)},t.normalize=function(e){return n.normalize?n.normalize(e):e},t.__resolver__=n,t}var k,I=e["default"],j=r.get,D=n.set,R=i.runLoadHooks,M=a["default"],L=s["default"],H=o["default"],z=u["default"],q=l.create,F=c["default"],B=(h.canInvoke,p["default"]),U=m["default"],K=f["default"],W=d["default"],G=v["default"],Q=b["default"],$=g["default"],Y=y["default"],J=_["default"],Z=w["default"],X=x["default"],et=C["default"],tt=O["default"],rt=P["default"],nt=E["default"],it=A.K,at=T["default"],st=L.extend(H,{_suppressDeferredDeprecation:!0,rootElement:"body",eventDispatcher:null,customEvents:null,_readinessDeferrals:1,init:function(){if(this.$||(this.$=Y),this.__container__=this.buildContainer(),this.Router=this.defaultRouter(),this._super(),this.scheduleInitialize(),I.libraries.registerCoreLibrary("Handlebars"+(at.compile?"":"-runtime"),at.VERSION),I.libraries.registerCoreLibrary("jQuery",Y().jquery),I.LOG_VERSION){I.LOG_VERSION=!1;var e=K.map(I.libraries,function(e){return j(e,"name.length")}),t=Math.max.apply(this,e);I.libraries.each(function(e){new Array(t-e.length+1).join(" ")})}},buildContainer:function(){var e=this.__container__=st.buildContainer(this);return e},defaultRouter:function(){if(this.Router!==!1){var e=this.__container__;return this.Router&&(e.unregister("router:main"),e.register("router:main",this.Router)),e.lookupFactory("router:main")}},scheduleInitialize:function(){var e=this;!this.$||this.$.isReady?F.schedule("actions",e,"_initialize"):this.$().ready(function(){F(e,"_initialize")})},deferReadiness:function(){this._readinessDeferrals++},advanceReadiness:function(){this._readinessDeferrals--,0===this._readinessDeferrals&&F.once(this,this.didBecomeReady)},register:function(){var e=this.__container__;e.register.apply(e,arguments)},inject:function(){var e=this.__container__;e.injection.apply(e,arguments)},initialize:function(){},_initialize:function(){if(!this.isDestroyed){if(this.Router){var e=this.__container__;e.unregister("router:main"),e.register("router:main",this.Router)}return this.runInitializers(),R("application",this),this.advanceReadiness(),this}},reset:function(){function e(){var e=this.__container__.lookup("router:main");e.reset(),F(this.__container__,"destroy"),this.buildContainer(),F.schedule("actions",this,function(){this._initialize()})}this._readinessDeferrals=1,F.join(this,e)},runInitializers:function(){for(var e,t=j(this.constructor,"initializers"),r=S(t),n=this.__container__,i=new M,a=this,s=0;sa;a++)r(o[u[a]],t,n,i);t(e,i),i.pop()}}function n(){this.names=[],this.vertices=Object.create(null)}function i(e){this.name=e,this.incoming={},this.incomingNames=[],this.hasOutgoing=!1,this.value=null}var a=e["default"];n.prototype.add=function(e){if(!e)throw new Error("Can't add Vertex without name");if(void 0!==this.vertices[e])return this.vertices[e];var t=new i(e);return this.vertices[e]=t,this.names.push(e),t},n.prototype.map=function(e,t){this.add(e).value=t},n.prototype.addEdge=function(e,t){function n(e,r){if(e.name===t)throw new a("cycle detected: "+t+" <- "+r.join(" <- "))}if(e&&t&&e!==t){var i=this.add(e),s=this.add(t);s.incoming.hasOwnProperty(e)||(r(i,n),i.hasOutgoing=!0,s.incoming[e]=i,s.incomingNames.push(e))}},n.prototype.topsort=function(e){var t,n,i={},a=this.vertices,s=this.names,o=s.length;for(t=0;o>t;t++)n=a[s[t]],n.hasOutgoing||r(n,e,i)},n.prototype.addEdges=function(e,t,r,n){var i;if(this.map(e,t),r)if("string"==typeof r)this.addEdge(e,r);else for(i=0;i-1&&(i=i.replace(/\.(.)/g,function(e){return e.charAt(1).toUpperCase()})),n.indexOf("_")>-1&&(i=i.replace(/_(.)/g,function(e){return e.charAt(1).toUpperCase()})),r+":"+i}return e},resolve:function(e){var t,r=this.parseName(e),n=r.resolveMethodName;if(!r.name||!r.type)throw new TypeError("Invalid fullName: `"+e+"`, must be of the form `type:name` ");return this[n]&&(t=this[n](r)),t||(t=this.resolveOther(r)),r.root&&r.root.LOG_RESOLVER&&this._logLookup(t,r),t},parseName:function(e){return this._parseNameCache[e]||(this._parseNameCache[e]=this._parseName(e))},_parseName:function(e){var t=e.split(":"),r=t[0],n=t[1],i=n,a=c(this,"namespace"),s=a;if("template"!==r&&-1!==i.indexOf("/")){var o=i.split("/");i=o[o.length-1];var u=m(o.slice(0,-1).join("."));s=v.byName(u)}return{fullName:e,type:r,fullNameWithoutType:n,name:i,root:s,resolveMethodName:"resolve"+p(r)}},lookupDescription:function(e){var t=this.parseName(e);if("template"===t.type)return"template at "+t.fullNameWithoutType.replace(/\./g,"/");var r=t.root+"."+p(t.name);return"model"!==t.type&&(r+=p(t.type)),r},makeToString:function(e){return e.toString()},useRouterNaming:function(e){e.name=e.name.replace(/\./g,"_"),"basic"===e.name&&(e.name="")},resolveTemplate:function(e){var t=e.fullNameWithoutType.replace(/\./g,"/");return l.TEMPLATES[t]?l.TEMPLATES[t]:(t=f(t),l.TEMPLATES[t]?l.TEMPLATES[t]:void 0)},resolveView:function(e){return this.useRouterNaming(e),this.resolveOther(e)},resolveController:function(e){return this.useRouterNaming(e),this.resolveOther(e)},resolveRoute:function(e){return this.useRouterNaming(e),this.resolveOther(e)},resolveModel:function(e){var t=p(e.name),r=c(e.root,t);return r?r:void 0},resolveHelper:function(e){return this.resolveOther(e)||b.helpers[e.fullNameWithoutType]},resolveOther:function(e){var t=p(e.name)+p(e.type),r=c(e.root,t);return r?r:void 0},_logLookup:function(e,t){var r,n;r=e?"[✓]":"[ ]",n=t.fullName.length>60?".":new Array(60-t.fullName.length).join("."),h.info(r,t.fullName,n,this.lookupDescription(t.fullName))}})}),e("ember-extension-support",["ember-metal/core","ember-extension-support/data_adapter","ember-extension-support/container_debug_adapter"],function(e,t,r){"use strict";var n=e["default"],i=t["default"],a=r["default"];n.DataAdapter=i,n.ContainerDebugAdapter=a}),e("ember-extension-support/container_debug_adapter",["ember-metal/core","ember-runtime/system/native_array","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","exports"],function(e,t,r,n,i,a,s){"use strict";var o=e["default"],u=t.A,l=r.typeOf,c=n.dasherize,h=n.classify,p=i["default"],m=a["default"];s["default"]=m.extend({container:null,resolver:null,canCatalogEntriesByType:function(e){return"model"===e||"template"===e?!1:!0},catalogEntriesByType:function(e){var t=u(p.NAMESPACES),r=u(),n=new RegExp(h(e)+"$");return t.forEach(function(e){if(e!==o)for(var t in e)if(e.hasOwnProperty(t)&&n.test(t)){var i=e[t];"class"===l(i)&&r.push(c(t.replace(n,"")))}}),r}})}),e("ember-extension-support/data_adapter",["ember-metal/core","ember-metal/property_get","ember-metal/run_loop","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/native_array","ember-application/system/application","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";var l=e["default"],c=t.get,h=r["default"],p=n.dasherize,m=i["default"],f=a["default"],d=s.A,v=o["default"];u["default"]=f.extend({init:function(){this._super(),this.releaseMethods=d()},container:null,containerDebugAdapter:void 0,attributeLimit:3,releaseMethods:d(),getFilters:function(){return d()},watchModelTypes:function(e,t){var r,n=this.getModelTypes(),i=this,a=d();r=n.map(function(e){var r=e.klass,n=i.wrapModelType(r,e.name);return a.push(i.observeModelType(r,t)),n}),e(r);var s=function(){a.forEach(function(e){e()}),i.releaseMethods.removeObject(s)};return this.releaseMethods.pushObject(s),s},_nameToClass:function(e){return"string"==typeof e&&(e=this.container.lookupFactory("model:"+e)),e},watchRecords:function(e,t,r,n){var i,a=this,s=d(),o=this.getRecords(e),u=function(e){r([e])},c=o.map(function(e){return s.push(a.observeRecord(e,u)),a.wrapRecord(e)}),h=function(e,r,i,o){for(var l=r;r+o>l;l++){var c=e.objectAt(l),h=a.wrapRecord(c);s.push(a.observeRecord(c,u)),t([h])}i&&n(r,i)},p={didChange:h,willChange:l.K};return o.addArrayObserver(a,p),i=function(){s.forEach(function(e){e() +}),o.removeArrayObserver(a,p),a.releaseMethods.removeObject(i)},t(c),this.releaseMethods.pushObject(i),i},willDestroy:function(){this._super(),this.releaseMethods.forEach(function(e){e()})},detect:function(){return!1},columnsForType:function(){return d()},observeModelType:function(e,t){var r=this,n=this.getRecords(e),i=function(){t([r.wrapModelType(e)])},a={didChange:function(){h.scheduleOnce("actions",this,i)},willChange:l.K};n.addArrayObserver(this,a);var s=function(){n.removeArrayObserver(r,a)};return s},wrapModelType:function(e,t){var r,n=this.getRecords(e);return r={name:t||e.toString(),count:c(n,"length"),columns:this.columnsForType(e),object:e}},getModelTypes:function(){var e,t=this,r=this.get("containerDebugAdapter");return e=r.canCatalogEntriesByType("model")?r.catalogEntriesByType("model"):this._getObjectsOnNamespaces(),e=d(e).map(function(e){return{klass:t._nameToClass(e),name:e}}),e=d(e).filter(function(e){return t.detect(e.klass)}),d(e)},_getObjectsOnNamespaces:function(){var e=d(m.NAMESPACES),t=d(),r=this;return e.forEach(function(e){for(var n in e)if(e.hasOwnProperty(n)&&r.detect(e[n])){var i=p(n);e instanceof v||!e.toString()||(i=e+"/"+i),t.push(i)}}),t},getRecords:function(){return d()},wrapRecord:function(e){var t={object:e};return t.columnValues=this.getRecordColumnValues(e),t.searchKeywords=this.getRecordKeywords(e),t.filterValues=this.getRecordFilterValues(e),t.color=this.getRecordColor(e),t},getRecordColumnValues:function(){return{}},getRecordKeywords:function(){return d()},getRecordFilterValues:function(){return{}},getRecordColor:function(){return null},observeRecord:function(){return function(){}}})}),e("ember-extension-support/initializers",[],function(){"use strict"}),e("ember-handlebars-compiler",["ember-metal/core","exports"],function(e,n){"use strict";var i=e["default"];"undefined"==typeof i.assert&&(i.assert=function(){}),"undefined"==typeof i.FEATURES&&(i.FEATURES={isEnabled:function(){}});var a,s,o=Object.create||function(e){function t(){}return t.prototype=e,new t},u=i.imports&&i.imports.Handlebars||this&&this.Handlebars;u||"function"!=typeof r||(u=r("handlebars"));var l=i.Handlebars=o(u);l.helper=function(e,r){a||(a=t("ember-views/views/view")["default"]),s||(s=t("ember-views/views/component")["default"]),a.detect(r)?l.registerHelper(e,l.makeViewHelper(r)):l.registerBoundHelper.apply(null,arguments)},l.makeViewHelper=function(e){return function(t){return l.helpers.view.call(this,e,t)}},l.helpers=o(u.helpers),l.Compiler=function(){},u.Compiler&&(l.Compiler.prototype=o(u.Compiler.prototype)),l.Compiler.prototype.compiler=l.Compiler,l.JavaScriptCompiler=function(){},u.JavaScriptCompiler&&(l.JavaScriptCompiler.prototype=o(u.JavaScriptCompiler.prototype),l.JavaScriptCompiler.prototype.compiler=l.JavaScriptCompiler),l.JavaScriptCompiler.prototype.namespace="Ember.Handlebars",l.JavaScriptCompiler.prototype.initializeBuffer=function(){return"''"},l.JavaScriptCompiler.prototype.appendToBuffer=function(e){return"data.buffer.push("+e+");"};var c=/helpers\.(.*?)\)/,h=/helpers\['(.*?)'/,p=/(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/;l.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation=function(e){var t=e[e.length-1],r=(c.exec(t)||h.exec(t))[1],n=p.exec(t);e[e.length-1]=n[1]+"'"+r+"'"+n[3]};var m=l.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation,f=l.JavaScriptCompiler.prototype.blockValue;l.JavaScriptCompiler.prototype.blockValue=function(){f.apply(this,arguments),m(this.source)};var d=l.JavaScriptCompiler.prototype.ambiguousBlockValue;l.JavaScriptCompiler.prototype.ambiguousBlockValue=function(){d.apply(this,arguments),m(this.source)},l.Compiler.prototype.mustache=function(e){if(!e.params.length&&!e.hash){var t=new u.AST.IdNode([{part:"_triageMustache"}]);e.escaped||(e.hash=e.hash||new u.AST.HashNode([]),e.hash.pairs.push(["unescaped",new u.AST.StringNode("true")])),e=new u.AST.MustacheNode([t].concat([e.id]),e.hash,!e.escaped)}return u.Compiler.prototype.mustache.call(this,e)},l.precompile=function(e,t){var r=u.parse(e),n={knownHelpers:{action:!0,unbound:!0,"bind-attr":!0,template:!0,view:!0,_triageMustache:!0},data:!0,stringParams:!0};t=void 0===t?!0:t;var i=(new l.Compiler).compile(r,n);return(new l.JavaScriptCompiler).compile(i,n,void 0,t)},u.compile&&(l.compile=function(e){var t=u.parse(e),r={data:!0,stringParams:!0},n=(new l.Compiler).compile(t,r),i=(new l.JavaScriptCompiler).compile(n,r,void 0,!0),a=l.template(i);return a.isMethod=!1,a}),n["default"]=l}),e("ember-handlebars",["ember-handlebars-compiler","ember-metal/core","ember-runtime/system/lazy_load","ember-handlebars/loader","ember-handlebars/ext","ember-handlebars/string","ember-handlebars/helpers/shared","ember-handlebars/helpers/binding","ember-handlebars/helpers/collection","ember-handlebars/helpers/view","ember-handlebars/helpers/unbound","ember-handlebars/helpers/debug","ember-handlebars/helpers/each","ember-handlebars/helpers/template","ember-handlebars/helpers/partial","ember-handlebars/helpers/yield","ember-handlebars/helpers/loc","ember-handlebars/controls/checkbox","ember-handlebars/controls/select","ember-handlebars/controls/text_area","ember-handlebars/controls/text_field","ember-handlebars/controls/text_support","ember-handlebars/controls","ember-handlebars/component_lookup","ember-handlebars/views/handlebars_bound_view","ember-handlebars/views/metamorph_view","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,g,y,_,w,x,C,O,P,E){"use strict";var A=e["default"],T=t["default"],N=r.runLoadHooks,S=n["default"],V=i.normalizePath,k=i.template,I=i.makeBoundHelper,j=i.registerBoundHelper,D=i.resolveHash,R=i.resolveParams,M=i.getEscaped,L=i.handlebarsGet,H=i.evaluateUnboundHelper,z=i.helperMissingHelper,q=i.blockHelperMissingHelper,F=s["default"],B=o.bind,U=o._triageMustacheHelper,K=o.resolveHelper,W=o.bindHelper,G=o.boundIfHelper,Q=o.unboundIfHelper,$=o.withHelper,Y=o.ifHelper,J=o.unlessHelper,Z=o.bindAttrHelper,X=o.bindAttrHelperDeprecated,et=o.bindClasses,tt=u["default"],rt=l.ViewHelper,nt=l.viewHelper,it=c["default"],at=h.logHelper,st=h.debuggerHelper,ot=p.EachView,ut=p.GroupedEach,lt=p.eachHelper,ct=m["default"],ht=f["default"],pt=d["default"],mt=v["default"],ft=b["default"],dt=g.Select,vt=g.SelectOption,bt=g.SelectOptgroup,gt=y["default"],yt=_["default"],_t=w["default"],wt=x.inputHelper,xt=x.textareaHelper,Ct=C["default"],Ot=O._HandlebarsBoundView,Pt=O.SimpleHandlebarsView,Et=P._wrapMap,At=P._SimpleMetamorphView,Tt=P._MetamorphView,Nt=P._Metamorph;A.bootstrap=S,A.template=k,A.makeBoundHelper=I,A.registerBoundHelper=j,A.resolveHash=D,A.resolveParams=R,A.resolveHelper=K,A.get=L,A.getEscaped=M,A.evaluateUnboundHelper=H,A.bind=B,A.bindClasses=et,A.EachView=ot,A.GroupedEach=ut,A.resolvePaths=F,A.ViewHelper=rt,A.normalizePath=V,T.Handlebars=A,T.ComponentLookup=Ct,T._SimpleHandlebarsView=Pt,T._HandlebarsBoundView=Ot,T._SimpleMetamorphView=At,T._MetamorphView=Tt,T._Metamorph=Nt,T._metamorphWrapMap=Et,T.TextSupport=_t,T.Checkbox=ft,T.Select=dt,T.SelectOption=vt,T.SelectOptgroup=bt,T.TextArea=gt,T.TextField=yt,T.TextSupport=_t,A.registerHelper("helperMissing",z),A.registerHelper("blockHelperMissing",q),A.registerHelper("bind",W),A.registerHelper("boundIf",G),A.registerHelper("_triageMustache",U),A.registerHelper("unboundIf",Q),A.registerHelper("with",$),A.registerHelper("if",Y),A.registerHelper("unless",J),A.registerHelper("bind-attr",Z),A.registerHelper("bindAttr",X),A.registerHelper("collection",tt),A.registerHelper("log",at),A.registerHelper("debugger",st),A.registerHelper("each",lt),A.registerHelper("loc",mt),A.registerHelper("partial",ht),A.registerHelper("template",ct),A.registerHelper("yield",pt),A.registerHelper("view",nt),A.registerHelper("unbound",it),A.registerHelper("input",wt),A.registerHelper("textarea",xt),N("Ember.Handlebars",A),E["default"]=A}),e("ember-handlebars/component_lookup",["ember-runtime/system/object","exports"],function(e,t){"use strict";var r=e["default"],n=r.extend({lookupFactory:function(e,t){t=t||this.container;var r="component:"+e,n="template:components/"+e,a=t&&t.has(n);a&&t.injection(r,"layout",n);var s=t.lookupFactory(r);return a||s?(s||(t.register(r,i.Component),s=t.lookupFactory(r)),s):void 0}});t["default"]=n}),e("ember-handlebars/controls",["ember-handlebars/controls/checkbox","ember-handlebars/controls/text_field","ember-handlebars/controls/text_area","ember-metal/core","ember-handlebars-compiler","ember-handlebars/ext","exports"],function(e,t,r,n,i,a,s){"use strict";function o(e,t,r){return"ID"===t.hashTypes[r]?f(e,t.hash[r],t):t.hash[r]}function u(e){var t=e.hash,r=e.hashTypes,n=o(this,e,"type"),i=t.on;return"checkbox"===n?(delete t.type,delete r.type,d.view.call(this,c,e)):(delete t.on,t.onEvent=i||"enter",d.view.call(this,h,e))}function l(e){e.hash,e.hashTypes;return d.view.call(this,p,e)}var c=e["default"],h=t["default"],p=r["default"],m=(n["default"],i["default"]),f=a.handlebarsGet,d=m.helpers;s.inputHelper=u,s.textareaHelper=l}),e("ember-handlebars/controls/checkbox",["ember-metal/property_get","ember-metal/property_set","ember-views/views/view","exports"],function(e,t,r,n){"use strict";var i=e.get,a=t.set,s=r["default"];n["default"]=s.extend({instrumentDisplay:'{{input type="checkbox"}}',classNames:["ember-checkbox"],tagName:"input",attributeBindings:["type","checked","indeterminate","disabled","tabindex","name","autofocus","required","form"],type:"checkbox",checked:!1,disabled:!1,indeterminate:!1,init:function(){this._super(),this.on("change",this,this._updateElementValue)},didInsertElement:function(){this._super(),i(this,"element").indeterminate=!!i(this,"indeterminate")},_updateElementValue:function(){a(this,"checked",this.$().prop("checked"))}})}),e("ember-handlebars/controls/select",["ember-handlebars-compiler","ember-metal/enumerable_utils","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/collection_view","ember-metal/utils","ember-metal/is_none","ember-metal/computed","ember-runtime/system/native_array","ember-metal/mixin","ember-metal/properties","exports"],function(e,t,r,n,a,s,o,u,l,c,h,p,m){"use strict";var f=e["default"],d=t.forEach,v=t.indexOf,b=t.indexesOf,g=t.replace,y=r.get,_=n.set,w=a["default"],x=s["default"],C=o.isArray,O=u["default"],P=l.computed,E=c.A,A=h.observer,T=p.defineProperty,N=(f.compile,w.extend({instrumentDisplay:"Ember.SelectOption",tagName:"option",attributeBindings:["value","selected"],defaultTemplate:function(e,t){t={data:t.data,hash:{}},f.helpers.bind.call(e,"view.label",t)},init:function(){this.labelPathDidChange(),this.valuePathDidChange(),this._super()},selected:P(function(){var e=y(this,"content"),t=y(this,"parentView.selection");return y(this,"parentView.multiple")?t&&v(t,e.valueOf())>-1:e==t}).property("content","parentView.selection"),labelPathDidChange:A("parentView.optionLabelPath",function(){var e=y(this,"parentView.optionLabelPath");e&&T(this,"label",P(function(){return y(this,e)}).property(e))}),valuePathDidChange:A("parentView.optionValuePath",function(){var e=y(this,"parentView.optionValuePath");e&&T(this,"value",P(function(){return y(this,e)}).property(e))})})),S=x.extend({instrumentDisplay:"Ember.SelectOptgroup",tagName:"optgroup",attributeBindings:["label"],selectionBinding:"parentView.selection",multipleBinding:"parentView.multiple",optionLabelPathBinding:"parentView.optionLabelPath",optionValuePathBinding:"parentView.optionValuePath",itemViewClassBinding:"parentView.optionView"}),V=w.extend({instrumentDisplay:"Ember.Select",tagName:"select",classNames:["ember-select"],defaultTemplate:i.Handlebars.template(function(e,t,r,n,a){function s(e,t){var n,i="";return t.buffer.push('"),i}function o(e,t){var n;n=r.each.call(e,"view.groupedContent",{hash:{},hashTypes:{},hashContexts:{},inverse:f.noop,fn:f.program(4,u,t),contexts:[e],types:["ID"],data:t}),t.buffer.push(n||0===n?n:"")}function u(e,t){t.buffer.push(m(r.view.call(e,"view.groupView",{hash:{content:"content",label:"label"},hashTypes:{content:"ID",label:"ID"},hashContexts:{content:e,label:e},contexts:[e],types:["ID"],data:t})))}function l(e,t){var n;n=r.each.call(e,"view.content",{hash:{},hashTypes:{},hashContexts:{},inverse:f.noop,fn:f.program(7,c,t),contexts:[e],types:["ID"],data:t}),t.buffer.push(n||0===n?n:"")}function c(e,t){t.buffer.push(m(r.view.call(e,"view.optionView",{hash:{content:""},hashTypes:{content:"ID"},hashContexts:{content:e},contexts:[e],types:["ID"],data:t})))}this.compilerInfo=[4,">= 1.0.0"],r=this.merge(r,i.Handlebars.helpers),a=a||{};var h,p="",m=this.escapeExpression,f=this;return h=r["if"].call(t,"view.prompt",{hash:{},hashTypes:{},hashContexts:{},inverse:f.noop,fn:f.program(1,s,a),contexts:[t],types:["ID"],data:a}),(h||0===h)&&a.buffer.push(h),h=r["if"].call(t,"view.optionGroupPath",{hash:{},hashTypes:{},hashContexts:{},inverse:f.program(6,l,a),fn:f.program(3,o,a),contexts:[t],types:["ID"],data:a}),(h||0===h)&&a.buffer.push(h),p}),attributeBindings:["multiple","disabled","tabindex","name","required","autofocus","form","size"],multiple:!1,disabled:!1,required:!1,content:null,selection:null,value:P(function(e,t){if(2===arguments.length)return t;var r=y(this,"optionValuePath").replace(/^content\.?/,"");return r?y(this,"selection."+r):y(this,"selection")}).property("selection"),prompt:null,optionLabelPath:"content",optionValuePath:"content",optionGroupPath:null,groupView:S,groupedContent:P(function(){var e=y(this,"optionGroupPath"),t=E(),r=y(this,"content")||[];return d(r,function(r){var n=y(r,e);y(t,"lastObject.label")!==n&&t.pushObject({label:n,content:E()}),y(t,"lastObject.content").push(r)}),t}).property("optionGroupPath","content.@each"),optionView:N,_change:function(){y(this,"multiple")?this._changeMultiple():this._changeSingle()},selectionDidChange:A("selection.@each",function(){var e=y(this,"selection");if(y(this,"multiple")){if(!C(e))return void _(this,"selection",E([e]));this._selectionDidChangeMultiple()}else this._selectionDidChangeSingle()}),valueDidChange:A("value",function(){var e,t=y(this,"content"),r=y(this,"value"),n=y(this,"optionValuePath").replace(/^content\.?/,""),i=n?y(this,"selection."+n):y(this,"selection");r!==i&&(e=t?t.find(function(e){return r===(n?y(e,n):e)}):null,this.set("selection",e))}),_triggerChange:function(){var e=y(this,"selection"),t=y(this,"value");O(e)||this.selectionDidChange(),O(t)||this.valueDidChange(),this._change()},_changeSingle:function(){var e=this.$()[0].selectedIndex,t=y(this,"content"),r=y(this,"prompt");if(t&&y(t,"length")){if(r&&0===e)return void _(this,"selection",null);r&&(e-=1),_(this,"selection",t.objectAt(e))}},_changeMultiple:function(){var e=this.$("option:selected"),t=y(this,"prompt"),r=t?1:0,n=y(this,"content"),i=y(this,"selection");if(n&&e){var a=e.map(function(){return this.index-r}).toArray(),s=n.objectsAt(a);C(i)?g(i,0,y(i,"length"),s):_(this,"selection",s)}},_selectionDidChangeSingle:function(){var e=this.get("element");if(e){var t=y(this,"content"),r=y(this,"selection"),n=t?v(t,r):-1,i=y(this,"prompt");i&&(n+=1),e&&(e.selectedIndex=n)}},_selectionDidChangeMultiple:function(){var e,t=y(this,"content"),r=y(this,"selection"),n=t?b(t,r):[-1],i=y(this,"prompt"),a=i?1:0,s=this.$("option");s&&s.each(function(){e=this.index>-1?this.index-a:-1,this.selected=v(n,e)>-1})},init:function(){this._super(),this.on("didInsertElement",this,this._triggerChange),this.on("change",this,this._change)}});m["default"]=V,m.Select=V,m.SelectOption=N,m.SelectOptgroup=S}),e("ember-handlebars/controls/text_area",["ember-metal/property_get","ember-views/views/component","ember-handlebars/controls/text_support","ember-metal/mixin","exports"],function(e,t,r,n,i){"use strict";var a=e.get,s=t["default"],o=r["default"],u=n.observer;i["default"]=s.extend(o,{instrumentDisplay:"{{textarea}}",classNames:["ember-text-area"],tagName:"textarea",attributeBindings:["rows","cols","name","selectionEnd","selectionStart","wrap","lang","dir"],rows:null,cols:null,_updateElementValue:u("value",function(){var e=a(this,"value"),t=this.$();t&&e!==t.val()&&t.val(e)}),init:function(){this._super(),this.on("didInsertElement",this,this._updateElementValue)}})}),e("ember-handlebars/controls/text_field",["ember-metal/property_get","ember-metal/property_set","ember-views/views/component","ember-handlebars/controls/text_support","exports"],function(e,t,r,n,i){"use strict";var a=(e.get,t.set,r["default"]),s=n["default"];i["default"]=a.extend(s,{instrumentDisplay:'{{input type="text"}}',classNames:["ember-text-field"],tagName:"input",attributeBindings:["type","value","size","pattern","name","min","max","accept","autocomplete","autosave","formaction","formenctype","formmethod","formnovalidate","formtarget","height","inputmode","list","multiple","step","lang","dir","width"],value:"",type:"text",size:null,pattern:null,min:null,max:null})}),e("ember-handlebars/controls/text_support",["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/target_action_support","exports"],function(e,t,r,n,i){"use strict";function a(e,t,r){var n=s(t,e),i=s(t,"onEvent"),a=s(t,"value");(i===e||"keyPress"===i&&"key-press"===e)&&t.sendAction("action",a),t.sendAction(e,a),(n||i===e)&&(s(t,"bubbles")||r.stopPropagation())}var s=e.get,o=t.set,u=r.Mixin,l=n["default"],c=u.create(l,{value:"",attributeBindings:["placeholder","disabled","maxlength","tabindex","readonly","autofocus","form","selectionDirection","spellcheck","required","title","autocapitalize","autocorrect"],placeholder:null,disabled:!1,maxlength:null,init:function(){this._super(),this.on("focusOut",this,this._elementValueDidChange),this.on("change",this,this._elementValueDidChange),this.on("paste",this,this._elementValueDidChange),this.on("cut",this,this._elementValueDidChange),this.on("input",this,this._elementValueDidChange),this.on("keyUp",this,this.interpretKeyEvents)},action:null,onEvent:"enter",bubbles:!1,interpretKeyEvents:function(e){var t=c.KEY_EVENTS,r=t[e.keyCode];return this._elementValueDidChange(),r?this[r](e):void 0},_elementValueDidChange:function(){o(this,"value",this.$().val())},insertNewline:function(e){a("enter",this,e),a("insert-newline",this,e)},cancel:function(e){a("escape-press",this,e)},focusIn:function(e){a("focus-in",this,e)},focusOut:function(e){a("focus-out",this,e)},keyPress:function(e){a("key-press",this,e)}});c.KEY_EVENTS={13:"insertNewline",27:"cancel"},i["default"]=c}),e("ember-handlebars/ext",["ember-metal/core","ember-runtime/system/string","ember-handlebars-compiler","ember-metal/property_get","ember-metal/error","ember-metal/mixin","ember-views/views/view","ember-handlebars/views/metamorph_view","ember-metal/path_cache","ember-metal/is_empty","ember-metal/cache","exports"],function(e,r,n,i,a,s,o,u,l,c,h,p){"use strict";function m(e,t,r){var n,i,a=r&&r.keywords||{};return n=H.get(t),a.hasOwnProperty(n)&&(e=a[n],i=!0,t=t===n?"":t.substr(n.length+1)),{root:e,path:t,isKeyword:i}}function f(e,t,r){var n,i=r&&r.data,a=m(e,t,i);return e=a.root,t=a.path,(e||""===t)&&(n=V(e,t)),j(t)&&(void 0===n&&e!==A.lookup&&(e=A.lookup,n=V(e,t)),e===A.lookup||null===e),n}function d(e,t,r,n){var i;if("string"==typeof t){if(n){var a=m(e,t,n);e=a.root,t=a.path}i=e&&V(e,t);var s=j(t);if(i||s||(i=r.lookupFactory("view:"+t)),!i&&s){var o=V(t);o&&(i=o)}}else i=t;return"string"==typeof i&&n&&n.view&&(i=d(n.view,i,r,n)),i}function v(e,t,r){var n=f(e,t,r);return null===n||void 0===n?n="":n instanceof Handlebars.SafeString||(n=String(n)),r.hash.unescaped||(n=Handlebars.Utils.escapeExpression(n)),n}function b(e,t,r){for(var n,i,a=[],s=r.types,o=0,u=t.length;u>o;o++)n=t[o],i=s[o],a.push("ID"===i?f(e,n,r):n);return a}function g(e,t,r){var n,i={},a=r.hashTypes;for(var s in t)t.hasOwnProperty(s)&&(n=a[s],i[s]="ID"===n?f(e,t[s],r):t[s]);return i}function y(e){P||(P=t("ember-handlebars/helpers/binding").resolveHelper);var r,n="",i=arguments[arguments.length-1],a=P(i.data.view.container,e);if(a)return a.apply(this,R.call(arguments,1));throw r="%@ Handlebars error: Could not find property '%@' on object %@.",i.data&&(n=i.data.view),new k(T(r,[n,e,this]))}function _(e){P||(P=t("ember-handlebars/helpers/binding").resolveHelper);var r=arguments[arguments.length-1],n=P(r.data.view.container,e);return n?n.apply(this,R.call(arguments,1)):S.helperMissing.call(this,e)}function w(e){var t=R.call(arguments,1),r=x.apply(this,t);N.registerHelper(e,r)}function x(e){function r(){var t,r,i,a,s,o=R.call(arguments,0,-1),u=o.length,l=arguments[arguments.length-1],c=[],h=l.data,p=h.isUnbound?R.call(l.types,1):l.types,f=l.hash,d=l.hashTypes,v=h.view,b=l.contexts,g=b&&b.length?b[0]:this,y="",_=E.prototype.normalizedValue,w=f.boundOptions={};for(i in f)I.test(i)?w[i.slice(0,-7)]=f[i]:"ID"===d[i]&&(w[i]=f[i]);var x=[];for(h.properties=[],t=0;u>t;++t)if(h.properties.push(o[t]),"ID"===p[t]){var O=m(g,o[t],h);c.push(O),x.push(O)}else c.push(h.isUnbound?{path:o[t]}:null);if(h.isUnbound)return C(this,e,c,l);var P=new E(null,null,!l.hash.unescaped,l.data);P.normalizedValue=function(){var r,n=[];for(r in w)w.hasOwnProperty(r)&&(s=m(g,w[r],h),P.path=s.path,P.pathRoot=s.root,f[r]=_.call(P));for(t=0;u>t;++t)s=c[t],s?(P.path=s.path,P.pathRoot=s.root,n.push(_.call(P))):n.push(o[t]);return n.push(l),e.apply(g,n)},v.appendChild(P);for(a in w)w.hasOwnProperty(a)&&x.push(m(g,w[a],h));for(t=0,r=x.length;r>t;++t)s=x[t],v.registerObserver(s.root,s.path,P,P.rerender);if("ID"===p[0]&&0!==c.length){var A=c[0],T=A.root,N=A.path;D(N)||(y=N+".");for(var S=0,V=n.length;V>S;S++)v.registerObserver(T,y+n[S],P,P.rerender)}}E||(E=t("ember-handlebars/views/handlebars_bound_view").SimpleHandlebarsView);var n=R.call(arguments,1);return r._rawFunction=e,r}function C(e,t,r,n){var i,a,s,o,u,l=[],c=n.hash,h=c.boundOptions,p=R.call(n.types,1);for(u in h)h.hasOwnProperty(u)&&(c[u]=f(e,h[u],n));for(i=0,a=r.length;a>i;++i)s=r[i],o=p[i],l.push("ID"===o?f(s.root,s.path,n):s.path);return l.push(n),t.apply(e,l)}function O(e){var t=M(e);return t.isTop=!0,t}var P,E,A=e["default"],T=r.fmt,N=n["default"],S=N.helpers,V=i.get,k=a["default"],I=s.IS_BINDING,j=(o["default"],u._Metamorph,l.isGlobal),D=c["default"],R=[].slice,M=N.template,L=h["default"],H=new L(1e3,function(e){return e.split(".",1)[0]});p.getEscaped=v,p.resolveParams=b,p.resolveHash=g,p.helperMissingHelper=y,p.blockHelperMissingHelper=_,p.registerBoundHelper=w,p.template=O,p.normalizePath=m,p.makeBoundHelper=x,p.handlebarsGet=f,p.handlebarsGetView=d,p.evaluateUnboundHelper=C}),e("ember-handlebars/helpers/binding",["ember-metal/core","ember-handlebars-compiler","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-runtime/system/string","ember-metal/platform","ember-metal/is_none","ember-metal/enumerable_utils","ember-metal/array","ember-views/views/view","ember-metal/run_loop","ember-metal/observer","ember-metal/binding","ember-views/system/jquery","ember-handlebars/ext","ember-metal/keys","ember-metal/cache","ember-handlebars/views/handlebars_bound_view","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,g,y){"use strict";function _(e){return!z(e)}function w(e,t,r,n,i,a){var s,o,u,l=t.data,c=t.fn,h=t.inverse,p=l.view,m=this||window;if(s=et(m,e,l),"object"==typeof this){if(l.insideGroup){o=function(){for(;p._contextView;)p=p._contextView;B.once(p,"rerender")};var f,d,v=tt(m,e,t);v=i?i(v):v,d=r?m:v,n(v)?f=c:h&&(f=h),f(d,{data:t.data})}else{var b=Z,g={preserveContext:r,shouldDisplayFunc:n,valueNormalizerFunc:i,displayTemplate:c,inverseTemplate:h,path:e,pathRoot:m,previousContext:m,isEscaped:!t.hash.unescaped,templateData:t.data,templateHash:t.hash,helperName:t.helperName};t.isWithHelper&&(b=st);var y=p.createChildView(b,g);p.appendChild(y),o=function(){B.scheduleOnce("render",y,"rerenderIfNeeded")}}if(""!==s.path&&(p.registerObserver(s.root,s.path,o),a))for(u=0;ua;a++){var s=e.objectAt(a);r.data.keywords[r.hash.keyword]=s,i(s,{data:n})}}},rerenderContainingView:function(){var e=this;T.scheduleOnce("render",this,function(){e.destroyed||e.containingView.rerender()})},destroy:function(){this.removeContentObservers(),this.content&&this.removeArrayObservers(),this.destroyed=!0}},b.EachView=R,b.GroupedEach=M,b.eachHelper=g}),e("ember-handlebars/helpers/loc",["ember-runtime/system/string","exports"],function(e,t){"use strict";var r=e.loc;t["default"]=r}),e("ember-handlebars/helpers/partial",["ember-metal/core","ember-metal/is_none","ember-handlebars/ext","ember-handlebars/helpers/binding","exports"],function(e,t,r,n,i){"use strict";function a(e){return!o(e)}function s(e,t,r){var n=t.split("/"),i=n[n.length-1];n[n.length-1]="_"+i;var a=r.data.view,s=n.join("/"),o=a.templateForName(s),u=!o&&a.templateForName(t);(o=o||u)(e,{data:r.data})}var o=(e["default"],t.isNone),u=r.handlebarsGet,l=n.bind;i["default"]=function(e,t){var r=t.contexts&&t.contexts.length?t.contexts[0]:this;return t.helperName=t.helperName||"partial","ID"===t.types[0]?(t.fn=function(t,r){var n=u(t,e,r);s(t,n,r)},l.call(r,e,t,!0,a)):void s(r,e,t)}}),e("ember-handlebars/helpers/shared",["ember-handlebars/ext","exports"],function(e,t){"use strict";var r=e.handlebarsGet;t["default"]=function(e){for(var t=[],n=e.contexts,i=e.roots,a=e.data,s=0,o=n.length;o>s;s++)t.push(r(i[s],n[s],{data:a}));return t}}),e("ember-handlebars/helpers/template",["ember-metal/core","ember-handlebars-compiler","exports"],function(e,t,r){"use strict";var n=(e["default"],t["default"]),i=n.helpers;r["default"]=function(e,t){return t.helperName=t.helperName||"template",i.partial.apply(this,arguments)}}),e("ember-handlebars/helpers/unbound",["ember-handlebars-compiler","ember-handlebars/helpers/binding","ember-handlebars/ext","exports"],function(e,t,r,n){"use strict";var i=e["default"],a=i.helpers,s=t.resolveHelper,o=r.handlebarsGet,u=[].slice;n["default"]=function(e,t){var r,n,i,l,c=arguments[arguments.length-1],h=c.data.view.container;return l=this,arguments.length>2?(c.data.isUnbound=!0,r=s(h,e)||a.helperMissing,i=r.apply(l,u.call(arguments,1)),delete c.data.isUnbound,i):(n=t.contexts&&t.contexts.length?t.contexts[0]:l,o(n,e,t))}}),e("ember-handlebars/helpers/view",["ember-metal/core","ember-runtime/system/object","ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-views/system/jquery","ember-views/views/view","ember-metal/binding","ember-metal/keys","ember-handlebars/ext","ember-runtime/system/string","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h){"use strict";function p(e,t){var r=t.hash,n=t.hashTypes;for(var i in r)if("ID"===n[i]){var a=r[i];d.test(i)||(r[i+"Binding"]=a,n[i+"Binding"]="STRING",delete r[i],delete n[i])}r.hasOwnProperty("idBinding")&&(r.id=_(e,r.idBinding,t),n.id="STRING",delete r.idBinding,delete n.idBinding)}function m(e,t){return e&&e.data&&e.data.isRenderData&&(t=e,e=t.data&&t.data.view&&t.data.view.container?t.data.view.container.lookupFactory("view:toplevel"):v),t.helperName=t.helperName||"view",x.helper(this,e,t)}var f=(e["default"],t["default"]),d=(r.get,n.set,i.IS_BINDING),v=(a["default"],s["default"]),b=o.isGlobalPath,g=u["default"],y=l.normalizePath,_=l.handlebarsGet,w=l.handlebarsGetView,x=(c["default"],f.create({propertiesFromHTMLOptions:function(e){var t=e.hash,r=e.data,n=t["class"],i={helperName:e.helperName||""};t.id&&(i.elementId=t.id),t.tag&&(i.tagName=t.tag),n&&(n=n.split(" "),i.classNames=n),t.classBinding&&(i.classNameBindings=t.classBinding.split(" ")),t.classNameBindings&&(void 0===i.classNameBindings&&(i.classNameBindings=[]),i.classNameBindings=i.classNameBindings.concat(t.classNameBindings.split(" "))),t.attributeBindings&&(i.attributeBindings=null);for(var a,s=g(t),o=0,u=s.length;u>o;o++){var l=s[o],c=d.test(l);"classNameBindings"!==l&&(i[l]=t[l]),c&&"string"==typeof i[l]&&(a=this.contextualizeBindingPath(t[l],r),a&&(i[l]=a))}if(i.classNameBindings)for(var h=0,p=i.classNameBindings.length;p>h;h++){var m=i.classNameBindings[h];if("string"==typeof m){var f=v._parsePropertyPath(m);""!==f.path&&(a=this.contextualizeBindingPath(f.path,r),a&&(i.classNameBindings[h]=a+f.classNames))}}return i},contextualizeBindingPath:function(e,t){var r=y(null,e,t);return r.isKeyword?"templateData.keywords."+e:b(e)?null:"this"===e||""===e?"_parentView.context":"_parentView.context."+e},helper:function(e,t,r){var n,i=r.data,a=r.fn;p(e,r);var s=this.container||i&&i.view&&i.view.container;n=w(e,t,s,r.data);var o=this.propertiesFromHTMLOptions(r,e),u=i.view;o.templateData=i;var l=n.proto();a&&(o.template=a),l.controller||l.controllerBinding||o.controller||o.controllerBinding||(o._context=e),u.appendChild(n,o)},instanceHelper:function(e,t,r){var n=r.data,i=r.fn;p(e,r);var a=this.propertiesFromHTMLOptions(r,e),s=n.view;a.templateData=n,i&&(a.template=i),t.controller||t.controllerBinding||a.controller||a.controllerBinding||(a._context=e),s.appendChild(t,a)}}));h.ViewHelper=x,h.viewHelper=m}),e("ember-handlebars/helpers/yield",["ember-metal/core","ember-metal/property_get","exports"],function(e,t,r){"use strict";var n=(e["default"],t.get);r["default"]=function(e){for(var t=e.data.view;t&&!n(t,"layout");)t=t._contextView?t._contextView:n(t,"_parentView");t._yield(this,e)}}),e("ember-handlebars/loader",["ember-handlebars/component_lookup","ember-views/system/jquery","ember-metal/error","ember-runtime/system/lazy_load","ember-handlebars-compiler","exports"],function(e,t,r,n,a,s){"use strict";function o(e){var t='script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]';h(t,e).each(function(){var e=h(this),t="text/x-raw-handlebars"===e.attr("type")?h.proxy(Handlebars.compile,Handlebars):h.proxy(f.compile,f),r=e.attr("data-template-name")||e.attr("id")||"application",n=t(e.html());if(void 0!==i.TEMPLATES[r])throw new p('Template named "'+r+'" already exists.');i.TEMPLATES[r]=n,e.remove()})}function u(){o(h(document))}function l(e){e.register("component-lookup:main",c)}var c=e["default"],h=t["default"],p=r["default"],m=n.onLoad,f=a["default"];m("Ember.Application",function(e){e.initializer({name:"domTemplates",initialize:u}),e.initializer({name:"registerComponentLookup",after:"domTemplates",initialize:l})}),s["default"]=o}),e("ember-handlebars/string",["ember-runtime/system/string","exports"],function(e,t){"use strict";function r(e){return new Handlebars.SafeString(e)}var n=e["default"];n.htmlSafe=r,(i.EXTEND_PROTOTYPES===!0||i.EXTEND_PROTOTYPES.String)&&(String.prototype.htmlSafe=function(){return r(this)}),t["default"]=r}),e("ember-handlebars/views/handlebars_bound_view",["ember-handlebars-compiler","ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-views/views/view","ember-views/views/states","ember-handlebars/views/metamorph_view","ember-handlebars/ext","ember-metal/utils","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m){"use strict";function f(e,t,r,n){this.path=e,this.pathRoot=t,this.isEscaped=r,this.templateData=n,this[b.GUID_KEY]=N(),this._lastNormalizedValue=void 0,this.state="preRender",this.updateId=null,this._parentView=null,this.buffer=null,this._morph=null}var d=e["default"],v=d.SafeString,b=t["default"],g=b.K,y=r["default"],_=n.get,w=i.set,x=a["default"],C=s["default"],O=(o.computed,u["default"],l.cloneStates),P=l.states,E=P,A=c["default"],T=h.handlebarsGet,N=p.uuid;f.prototype={isVirtual:!0,isView:!0,destroy:function(){this.updateId&&(C.cancel(this.updateId),this.updateId=null),this._parentView&&this._parentView.removeChild(this),this.morph=null,this.state="destroyed"},propertyWillChange:g,propertyDidChange:g,normalizedValue:function(){var e,t,r=this.path,n=this.pathRoot,i=this.isEscaped;return""===r?e=n:(t=this.templateData,e=T(n,r,{data:t})),null===e||void 0===e?e="":i||e instanceof v||(e=new v(e)),e},render:function(e){var t=this.normalizedValue();this._lastNormalizedValue=t,e._element=t},rerender:function(){switch(this.state){case"preRender":case"destroyed":break;case"inBuffer":throw new y("Something you did tried to replace an {{expression}} before it was inserted into the DOM.");case"hasElement":case"inDOM":this.updateId=C.scheduleOnce("render",this,"update")}return this},update:function(){this.updateId=null;var e=this.normalizedValue();e!==this._lastNormalizedValue&&(this._lastNormalizedValue=e,this._morph.update(e))},_transitionTo:function(e){this.state=e}},P=O(E),x(P._default,{rerenderIfNeeded:g}),x(P.inDOM,{rerenderIfNeeded:function(e){e.normalizedValue()!==e._lastNormalizedValue&&e.rerender()}});var S=A.extend({instrumentName:"boundHandlebars",_states:P,shouldDisplayFunc:null,preserveContext:!1,previousContext:null,displayTemplate:null,inverseTemplate:null,path:null,pathRoot:null,normalizedValue:function(){var e,t,r=_(this,"path"),n=_(this,"pathRoot"),i=_(this,"valueNormalizerFunc");return""===r?e=n:(t=_(this,"templateData"),e=T(n,r,{data:t})),i?i(e):e},rerenderIfNeeded:function(){this.currentState.rerenderIfNeeded(this)},render:function(e){var t=_(this,"isEscaped"),r=_(this,"shouldDisplayFunc"),n=_(this,"preserveContext"),i=_(this,"previousContext"),a=_(this,"inverseTemplate"),s=_(this,"displayTemplate"),o=this.normalizedValue();if(this._lastNormalizedValue=o,r(o))if(w(this,"template",s),n)w(this,"_context",i);else{if(!s)return null===o||void 0===o?o="":o instanceof v||(o=String(o)),t&&(o=Handlebars.Utils.escapeExpression(o)),void e.push(o);w(this,"_context",o)}else a?(w(this,"template",a),n?w(this,"_context",i):w(this,"_context",o)):w(this,"template",function(){return""});return this._super(e)}});m._HandlebarsBoundView=S,m.SimpleHandlebarsView=f}),e("ember-handlebars/views/metamorph_view",["ember-metal/core","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-metal/run_loop","exports"],function(e,t,r,n,i,a){"use strict";var s=(e["default"],t["default"]),o=r["default"],u=n.Mixin,l=(i["default"],u.create({isVirtual:!0,tagName:"",instrumentName:"metamorph",init:function(){this._super()}}));a._Metamorph=l;var c=o.extend(l);a._MetamorphView=c;var h=s.extend(l);a._SimpleMetamorphView=h,a["default"]=o.extend(l)}),e("ember-metal-views",["ember-metal-views/renderer","exports"],function(e,t){"use strict";var r=e["default"];t.Renderer=r}),e("ember-metal-views/renderer",["morph","exports"],function(e,t){"use strict";function r(){this._uuid=0,this._views=new Array(2e3),this._queue=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],this._parents=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],this._elements=new Array(17),this._inserts={},this._dom=new u}function n(e,t,r){var n=this._views;n[0]=e;var i=void 0===r?-1:r,a=0,s=1,o=t?t._level+1:0,u=null==t?e:t._root,l=!!u._morph,c=this._queue;c[0]=0;for(var h,p,m,f=1,d=-1,v=this._parents,b=t||null,g=this._elements,y=null,_=null,w=0,x=e;f;){if(g[w]=y,x._morph||(x._morph=null),x._root=u,this.uuid(x),x._level=o+w,x._elementCreated&&this.remove(x,!1,!0),this.willCreateElement(x),_=x._morph&&x._morph.contextualElement,!_&&b&&b._childViewsMorph&&(_=b._childViewsMorph.contextualElement),!_&&x._didCreateElementWithoutMorph&&(_=document.body),y=this.createElement(x,_),v[w++]=d,d=a,b=x,c[f++]=a,h=this.childViews(x))for(p=h.length-1;p>=0;p--)m=h[p],a=s++,n[a]=m,c[f++]=a,x=m;for(a=c[--f],x=n[a];d===a;){if(w--,x._elementCreated=!0,this.didCreateElement(x),l&&this.willInsertElement(x),0===w){f--;break}d=v[w],b=-1===d?t:n[d],this.insertElement(x,b,y,-1),a=c[--f],x=n[a],y=g[w],g[w]=null}}for(this.insertElement(x,t,y,i),p=s-1;p>=0;p--)l&&(n[p]._elementInserted=!0,this.didInsertElement(n[p])),n[p]=null;return y}function i(e,t,r){var n=this.uuid(e);if(this._inserts[n]&&(this.cancelRender(this._inserts[n]),this._inserts[n]=void 0),e._elementCreated){var i,a,s,o,u,l,c,h=[],p=[],m=e._morph;for(h.push(e),i=0;il;l++)o.push(u[l]);for(i=0;il;l++)p.push(u[l]);for(m&&!r&&m.destroy(),i=0,a=h.length;a>i;i++)this.afterRemove(h[i],!1);for(i=0,a=p.length;a>i;i++)this.afterRemove(p[i],!0);r&&(e._morph=m)}}function a(e,t,r,n){null!==r&&void 0!==r&&(e._morph?e._morph.update(r):t&&(e._morph=-1===n?t._childViewsMorph.append(r):t._childViewsMorph.insert(n,r)))}function s(e){e._elementCreated&&this.willDestroyElement(e),e._elementInserted&&this.willRemoveElement(e)}function o(e,t){e._elementInserted=!1,e._morph=null,e._childViewsMorph=null,e._elementCreated&&(e._elementCreated=!1,this.didDestroyElement(e)),t&&this.destroyView(e)}var u=e.DOMHelper;r.prototype.uuid=function(e){return void 0===e._uuid&&(e._uuid=++this._uuid,e._renderer=this),e._uuid},r.prototype.scheduleInsert=function(e,t){if(e._morph||e._elementCreated)throw new Error("You cannot insert a View that has already been rendered");e._morph=t;var r=this.uuid(e);this._inserts[r]=this.scheduleRender(this,function(){this._inserts[r]=null,this.renderTree(e)})},r.prototype.appendTo=function(e,t){var r=this._dom.appendMorph(t);this.scheduleInsert(e,r)},r.prototype.replaceIn=function(e,t){var r=this._dom.createMorph(t,null,null);this.scheduleInsert(e,r)},r.prototype.remove=i,r.prototype.destroy=function(e){this.remove(e,!0)},r.prototype.renderTree=n,r.prototype.insertElement=a,r.prototype.beforeRemove=s,r.prototype.afterRemove=o;var l=function(){};r.prototype.willCreateElement=l,r.prototype.createElement=l,r.prototype.didCreateElement=l,r.prototype.willInsertElement=l,r.prototype.didInsertElement=l,r.prototype.willRemoveElement=l,r.prototype.willDestroyElement=l,r.prototype.didDestroyElement=l,r.prototype.destroyView=l,r.prototype.childViews=l,t["default"]=r}),e("ember-metal",["ember-metal/core","ember-metal/merge","ember-metal/instrumentation","ember-metal/utils","ember-metal/error","ember-metal/enumerable_utils","ember-metal/cache","ember-metal/platform","ember-metal/array","ember-metal/logger","ember-metal/property_get","ember-metal/events","ember-metal/observer_set","ember-metal/property_events","ember-metal/properties","ember-metal/property_set","ember-metal/map","ember-metal/get_properties","ember-metal/set_properties","ember-metal/watch_key","ember-metal/chains","ember-metal/watch_path","ember-metal/watching","ember-metal/expand_properties","ember-metal/computed","ember-metal/computed_macros","ember-metal/observer","ember-metal/mixin","ember-metal/binding","ember-metal/run_loop","ember-metal/libraries","ember-metal/is_none","ember-metal/is_empty","ember-metal/is_blank","ember-metal/is_present","ember-metal/keys","exports"],function(e,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,g,y,_,w,x,C,O,P,E,A,T,N,S,V,k,I,j,D,R,M){"use strict";var L=e["default"],H=r["default"],z=n.instrument,q=n.subscribe,F=n.unsubscribe,B=n.reset,U=i.generateGuid,K=i.GUID_KEY,W=i.guidFor,G=i.META_DESC,Q=i.EMPTY_META,$=i.meta,Y=i.getMeta,J=i.setMeta,Z=i.metaPath,X=i.inspect,et=i.typeOf,tt=i.tryCatchFinally,rt=i.isArray,nt=i.makeArray,it=i.canInvoke,at=i.tryInvoke,st=i.tryFinally,ot=i.wrap,ut=i.apply,lt=i.applyStr,ct=i.uuid,ht=a["default"],pt=s["default"],mt=o["default"],ft=u.create,dt=u.platform,vt=l.map,bt=l.forEach,gt=l.filter,yt=l.indexOf,_t=c["default"],wt=h.get,xt=h.getWithDefault,Ct=h.normalizeTuple,Ot=h._getPath,Pt=p.on,Et=p.addListener,At=p.removeListener,Tt=p.suspendListener,Nt=p.suspendListeners,St=p.sendEvent,Vt=p.hasListeners,kt=p.watchedEvents,It=p.listenersFor,jt=p.listenersDiff,Dt=p.listenersUnion,Rt=m["default"],Mt=f.propertyWillChange,Lt=f.propertyDidChange,Ht=f.overrideChains,zt=f.beginPropertyChanges,qt=f.endPropertyChanges,Ft=f.changeProperties,Bt=d.Descriptor,Ut=d.defineProperty,Kt=v.set,Wt=v.trySet,Gt=b.OrderedSet,Qt=b.Map,$t=b.MapWithDefault,Yt=g["default"],Jt=y["default"],Zt=_.watchKey,Xt=_.unwatchKey,er=w.flushPendingChains,tr=w.removeChainWatcher,rr=w.ChainNode,nr=w.finishChains,ir=x.watchPath,ar=x.unwatchPath,sr=C.watch,or=C.isWatching,ur=C.unwatch,lr=C.rewatch,cr=C.destroy,hr=O["default"],pr=P.ComputedProperty,mr=P.computed,fr=P.cacheFor,dr=A.addObserver,vr=A.observersFor,br=A.removeObserver,gr=A.addBeforeObserver,yr=A._suspendBeforeObserver,_r=A._suspendObserver,wr=A._suspendBeforeObservers,xr=A._suspendObservers,Cr=A.beforeObserversFor,Or=A.removeBeforeObserver,Pr=T.IS_BINDING,Er=T.mixin,Ar=T.Mixin,Tr=T.required,Nr=T.aliasMethod,Sr=T.observer,Vr=T.immediateObserver,kr=T.beforeObserver,Ir=N.Binding,jr=N.isGlobalPath,Dr=N.bind,Rr=N.oneWay,Mr=S["default"],Lr=V["default"],Hr=k.isNone,zr=k.none,qr=I.isEmpty,Fr=I.empty,Br=j["default"],Ur=D["default"],Kr=R["default"],Wr=L.Instrumentation={};Wr.instrument=z,Wr.subscribe=q,Wr.unsubscribe=F,Wr.reset=B,L.instrument=z,L.subscribe=q,L._Cache=mt,L.generateGuid=U,L.GUID_KEY=K,L.create=ft,L.keys=Kr,L.platform=dt;var Gr=L.ArrayPolyfills={};Gr.map=vt,Gr.forEach=bt,Gr.filter=gt,Gr.indexOf=yt,L.Error=ht,L.guidFor=W,L.META_DESC=G,L.EMPTY_META=Q,L.meta=$,L.getMeta=Y,L.setMeta=J,L.metaPath=Z,L.inspect=X,L.typeOf=et,L.tryCatchFinally=tt,L.isArray=rt,L.makeArray=nt,L.canInvoke=it,L.tryInvoke=at,L.tryFinally=st,L.wrap=ot,L.apply=ut,L.applyStr=lt,L.uuid=ct,L.Logger=_t,L.get=wt,L.getWithDefault=xt,L.normalizeTuple=Ct,L._getPath=Ot,L.EnumerableUtils=pt,L.on=Pt,L.addListener=Et,L.removeListener=At,L._suspendListener=Tt,L._suspendListeners=Nt,L.sendEvent=St,L.hasListeners=Vt,L.watchedEvents=kt,L.listenersFor=It,L.listenersDiff=jt,L.listenersUnion=Dt,L._ObserverSet=Rt,L.propertyWillChange=Mt,L.propertyDidChange=Lt,L.overrideChains=Ht,L.beginPropertyChanges=zt,L.endPropertyChanges=qt,L.changeProperties=Ft,L.Descriptor=Bt,L.defineProperty=Ut,L.set=Kt,L.trySet=Wt,L.OrderedSet=Gt,L.Map=Qt,L.MapWithDefault=$t,L.getProperties=Yt,L.setProperties=Jt,L.watchKey=Zt,L.unwatchKey=Xt,L.flushPendingChains=er,L.removeChainWatcher=tr,L._ChainNode=rr,L.finishChains=nr,L.watchPath=ir,L.unwatchPath=ar,L.watch=sr,L.isWatching=or,L.unwatch=ur,L.rewatch=lr,L.destroy=cr,L.expandProperties=hr,L.ComputedProperty=pr,L.computed=mr,L.cacheFor=fr,L.addObserver=dr,L.observersFor=vr,L.removeObserver=br,L.addBeforeObserver=gr,L._suspendBeforeObserver=yr,L._suspendBeforeObservers=wr,L._suspendObserver=_r,L._suspendObservers=xr,L.beforeObserversFor=Cr,L.removeBeforeObserver=Or,L.IS_BINDING=Pr,L.required=Tr,L.aliasMethod=Nr,L.observer=Sr,L.immediateObserver=Vr,L.beforeObserver=kr,L.mixin=Er,L.Mixin=Ar,L.oneWay=Rr,L.bind=Dr,L.Binding=Ir,L.isGlobalPath=jr,L.run=Mr,L.libraries=Lr,L.libraries.registerCoreLibrary("Ember",L.VERSION),L.isNone=Hr,L.none=zr,L.isEmpty=qr,L.empty=Fr,L.isBlank=Br,L.isPresent=Ur,L.merge=H,L.onerror=null,L.__loader.registry["ember-debug"]&&t("ember-debug"),M["default"]=L}),e("ember-metal/alias",["ember-metal/property_get","ember-metal/property_set","ember-metal/error","ember-metal/properties","ember-metal/computed","ember-metal/platform","ember-metal/utils","ember-metal/dependent_keys","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(e){return new c(e)}function c(e){this.altKey=e,this._dependentKeys=[e]}function h(e,t){throw new d('Cannot set read-only property "'+t+'" on object: '+w(e))}function p(e,t,r){return b(e,t,null),f(e,t,r)}var m=e.get,f=t.set,d=r["default"],v=n.Descriptor,b=n.defineProperty,g=i.ComputedProperty,y=a.create,_=s.meta,w=s.inspect,x=o.addDependentKeys,C=o.removeDependentKeys;u.alias=l,u.AliasedProperty=c,c.prototype=y(v.prototype),c.prototype.get=function(e){return m(e,this.altKey)},c.prototype.set=function(e,t,r){return f(e,this.altKey,r)},c.prototype.willWatch=function(e,t){x(this,e,t,_(e))},c.prototype.didUnwatch=function(e,t){C(this,e,t,_(e))},c.prototype.setup=function(e,t){var r=_(e);r.watching[t]&&x(this,e,t,r)},c.prototype.teardown=function(e,t){var r=_(e);r.watching[t]&&C(this,e,t,r)},c.prototype.readOnly=function(){return this.set=h,this},c.prototype.oneWay=function(){return this.set=p,this},c.prototype._meta=void 0,c.prototype.meta=g.prototype.meta}),e("ember-metal/array",["exports"],function(e){"use strict";var t=Array.prototype,r=function(e){return e&&Function.prototype.toString.call(e).indexOf("[native code]")>-1},n=function(e,t){return r(e)?e:t},a=n(t.map,function(e){if(void 0===this||null===this||"function"!=typeof e)throw new TypeError;for(var t=Object(this),r=t.length>>>0,n=new Array(r),i=arguments[1],a=0;r>a;a++)a in t&&(n[a]=e.call(i,t[a],a,t));return n}),s=n(t.forEach,function(e){if(void 0===this||null===this||"function"!=typeof e)throw new TypeError;for(var t=Object(this),r=t.length>>>0,n=arguments[1],i=0;r>i;i++)i in t&&e.call(n,t[i],i,t)}),o=n(t.indexOf,function(e,t){null===t||void 0===t?t=0:0>t&&(t=Math.max(0,this.length+t));for(var r=t,n=this.length;n>r;r++)if(this[r]===e)return r;return-1}),u=n(t.lastIndexOf,function(e,t){var r,n=this.length;for(t=void 0===t?n-1:0>t?Math.ceil(t):Math.floor(t),0>t&&(t+=n),r=t;r>=0;r--)if(this[r]===e)return r;return-1}),l=n(t.filter,function(e,t){var r,n,i=[],a=this.length;for(r=0;a>r;r++)this.hasOwnProperty(r)&&(n=this[r],e.call(t,n,r,this)&&i.push(n));return i});i.SHIM_ES5&&(t.map=t.map||a,t.forEach=t.forEach||s,t.filter=t.filter||l,t.indexOf=t.indexOf||o,t.lastIndexOf=t.lastIndexOf||u),e.map=a,e.forEach=s,e.filter=l,e.indexOf=o,e.lastIndexOf=u}),e("ember-metal/binding",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/map","ember-metal/observer","ember-metal/run_loop","ember-metal/path_cache","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(e,t){return d(C(t)?f.lookup:e,t)}function c(e,t){this._direction="fwd",this._from=t,this._to=e,this._directionMap=new g,this._readyToSync=void 0,this._oneWay=void 0}function h(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])}function p(e,t,r){return new c(t,r).connect(e)}function m(e,t,r){return new c(t,r).oneWay().connect(e)}var f=e["default"],d=t.get,v=(r.set,r.trySet),b=n.guidFor,g=i["default"],y=a.addObserver,_=a.removeObserver,w=a._suspendObserver,x=s["default"],C=o.isGlobal;f.LOG_BINDINGS=!1||!!f.ENV.LOG_BINDINGS,c.prototype={copy:function(){var e=new c(this._to,this._from);return this._oneWay&&(e._oneWay=!0),e},from:function(e){return this._from=e,this},to:function(e){return this._to=e,this},oneWay:function(){return this._oneWay=!0,this},toString:function(){var e=this._oneWay?"[oneWay]":"";return"Ember.Binding<"+b(this)+">("+this._from+" -> "+this._to+")"+e},connect:function(e){var t=this._from,r=this._to;return v(e,r,l(e,t)),y(e,t,this,this.fromDidChange),this._oneWay||y(e,r,this,this.toDidChange),this._readyToSync=!0,this},disconnect:function(e){var t=!this._oneWay;return _(e,this._from,this,this.fromDidChange),t&&_(e,this._to,this,this.toDidChange),this._readyToSync=!1,this},fromDidChange:function(e){this._scheduleSync(e,"fwd")},toDidChange:function(e){this._scheduleSync(e,"back")},_scheduleSync:function(e,t){var r=this._directionMap,n=r.get(e);n||(x.schedule("sync",this,this._sync,e),r.set(e,t)),"back"===n&&"fwd"===t&&r.set(e,"fwd")},_sync:function(e){var t=f.LOG_BINDINGS;if(!e.isDestroyed&&this._readyToSync){var r=this._directionMap,n=r.get(e),i=this._from,a=this._to;if(r["delete"](e),"fwd"===n){var s=l(e,this._from);t&&f.Logger.log(" ",this.toString(),"->",s,e),this._oneWay?v(e,a,s):w(e,a,this,this.toDidChange,function(){v(e,a,s)})}else if("back"===n){var o=d(e,this._to);t&&f.Logger.log(" ",this.toString(),"<-",o,e),w(e,i,this,this.fromDidChange,function(){v(C(i)?f.lookup:e,i,o)})}}}},h(c,{from:function(){var e=this,t=new e;return t.from.apply(t,arguments)},to:function(){var e=this,t=new e;return t.to.apply(t,arguments)},oneWay:function(e,t){var r=this,n=new r(null,e);return n.oneWay(t)}}),u.bind=p,u.oneWay=m,u.Binding=c,u.isGlobalPath=C}),e("ember-metal/cache",["ember-metal/dictionary","exports"],function(e,t){"use strict";function r(e,t){this.store=n(null),this.size=0,this.misses=0,this.hits=0,this.limit=e,this.func=t}var n=e["default"];t["default"]=r;var i=function(){};r.prototype={set:function(e,t){return this.limit>this.size&&(this.size++,this.store[e]=void 0===t?i:t),t},get:function(e){var t=this.store[e];return void 0===t?(this.misses++,t=this.set(e,this.func(e))):t===i?(this.hits++,t=void 0):this.hits++,t},purge:function(){this.store=n(null),this.size=0,this.hits=0,this.misses=0}}}),e("ember-metal/chains",["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/array","ember-metal/watch_key","exports"],function(e,t,r,n,i,a){"use strict";function s(e){return e.match(x)[0]}function o(){if(0!==C.length){var e=C;C=[],b.call(e,function(e){e[0].add(e[1])}),w("Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos",0===C.length)}}function u(e,t,r){if(e&&"object"==typeof e){var n=_(e),i=n.chainWatchers;n.hasOwnProperty("chainWatchers")||(i=n.chainWatchers={}),i[t]||(i[t]=[]),i[t].push(r),g(e,t,n)}}function l(e,t,r){if(e&&"object"==typeof e){var n=e.__ember_meta__;if(!n||n.hasOwnProperty("chainWatchers")){var i=n&&n.chainWatchers;if(i&&i[t]){i=i[t];for(var a=0,s=i.length;s>a;a++)if(i[a]===r){i.splice(a,1);break}}y(e,t,n)}}}function c(e,t,r){this._parent=e,this._key=t,this._watching=void 0===r,this._value=r,this._paths={},this._watching&&(this._object=e.value(),this._object&&u(this._object,this._key,this)),this._parent&&"@each"===this._parent._key&&this.value()}function h(e,t){if(!e)return void 0;var r=e.__ember_meta__;if(r&&r.proto===e)return void 0;if("@each"===t)return f(e,t);var n=r&&r.descs[t];return n&&n._cacheable?t in r.cache?r.cache[t]:void 0:f(e,t)}function p(e){var t,r,n,i=e.__ember_meta__;if(i){if(r=i.chainWatchers)for(var a in r)if(r.hasOwnProperty(a)&&(n=r[a]))for(var s=0,o=n.length;o>s;s++)n[s].didChange(null);t=i.chains,t&&t.value()!==e&&(_(e).chains=t=t.copy(e))}}var m=e["default"],f=t.get,d=t.normalizeTuple,v=r.meta,b=n.forEach,g=i.watchKey,y=i.unwatchKey,_=v,w=m.warn,x=/^([^\.]+)/,C=[];a.flushPendingChains=o;var O=c.prototype;O.value=function(){if(void 0===this._value&&this._watching){var e=this._parent.value();this._value=h(e,this._key)}return this._value},O.destroy=function(){if(this._watching){var e=this._object;e&&l(e,this._key,this),this._watching=!1}},O.copy=function(e){var t,r=new c(null,null,e),n=this._paths;for(t in n)n[t]<=0||r.add(t);return r},O.add=function(e){var t,r,n,i,a;if(a=this._paths,a[e]=(a[e]||0)+1,t=this.value(),r=d(t,e),r[0]&&r[0]===t)e=r[1],n=s(e),e=e.slice(n.length+1);else{if(!r[0])return C.push([this,e]),void(r.length=0);i=r[0],n=e.slice(0,0-(r[1].length+1)),e=r[1]}r.length=0,this.chain(n,e,i)},O.remove=function(e){var t,r,n,i,a;a=this._paths,a[e]>0&&a[e]--,t=this.value(),r=d(t,e),r[0]===t?(e=r[1],n=s(e),e=e.slice(n.length+1)):(i=r[0],n=e.slice(0,0-(r[1].length+1)),e=r[1]),r.length=0,this.unchain(n,e)},O.count=0,O.chain=function(e,t,r){var n,i=this._chains;i||(i=this._chains={}),n=i[e],n||(n=i[e]=new c(this,e,r)),n.count++,t&&(e=s(t),t=t.slice(e.length+1),n.chain(e,t))},O.unchain=function(e,t){var r=this._chains,n=r[e];t&&t.length>1&&(e=s(t),t=t.slice(e.length+1),n.unchain(e,t)),n.count--,n.count<=0&&(delete r[n._key],n.destroy())},O.willChange=function(e){var t=this._chains;if(t)for(var r in t)t.hasOwnProperty(r)&&t[r].willChange(e);this._parent&&this._parent.chainWillChange(this,this._key,1,e)},O.chainWillChange=function(e,t,r,n){this._key&&(t=this._key+"."+t),this._parent?this._parent.chainWillChange(this,t,r+1,n):(r>1&&n.push(this.value(),t),t="this."+t,this._paths[t]>0&&n.push(this.value(),t))},O.chainDidChange=function(e,t,r,n){this._key&&(t=this._key+"."+t),this._parent?this._parent.chainDidChange(this,t,r+1,n):(r>1&&n.push(this.value(),t),t="this."+t,this._paths[t]>0&&n.push(this.value(),t))},O.didChange=function(e){if(this._watching){var t=this._parent.value();t!==this._object&&(l(this._object,this._key,this),this._object=t,u(t,this._key,this)),this._value=void 0,this._parent&&"@each"===this._parent._key&&this.value()}var r=this._chains;if(r)for(var n in r)r.hasOwnProperty(n)&&r[n].didChange(e);null!==e&&this._parent&&this._parent.chainDidChange(this,this._key,1,e)},a.finishChains=p,a.removeChainWatcher=l,a.ChainNode=c}),e("ember-metal/computed",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/expand_properties","ember-metal/error","ember-metal/properties","ember-metal/property_events","ember-metal/dependent_keys","exports"],function(e,t,r,n,i,a,s,o,u,l){"use strict";function c(){}function h(e,t){e.__ember_arity__=e.length,this.func=e,this._cacheable=t&&void 0!==t.cacheable?t.cacheable:!0,this._dependentKeys=t&&t.dependentKeys,this._readOnly=t&&(void 0!==t.readOnly||!!t.readOnly)||!1}function p(e){for(var t=0,r=e.length;r>t;t++)e[t].didChange(null)}function m(e){var t;if(arguments.length>1&&(t=A.call(arguments),e=t.pop()),"function"!=typeof e)throw new y("Computed Property declared without a property function");var r=new h(e);return t&&r.property.apply(r,t),r}function f(e,t){var r=e.__ember_meta__,n=r&&r.cache,i=n&&n[t];return i===c?void 0:i}var d=(e["default"],t.get,r.set),v=n.meta,b=n.inspect,g=i["default"],y=a["default"],_=s.Descriptor,w=s.defineProperty,x=o.propertyWillChange,C=o.propertyDidChange,O=u.addDependentKeys,P=u.removeDependentKeys,E=v,A=[].slice;h.prototype=new _;var T=h.prototype;T._dependentKeys=void 0,T._suspended=void 0,T._meta=void 0,T.cacheable=function(e){return this._cacheable=e!==!1,this},T["volatile"]=function(){return this.cacheable(!1)},T.readOnly=function(e){return this._readOnly=void 0===e||!!e,this +},T.property=function(){var e,t=function(t){e.push(t)};e=[];for(var r=0,n=arguments.length;n>r;r++)g(arguments[r],t);return this._dependentKeys=e,this},T.meta=function(e){return 0===arguments.length?this._meta||{}:(this._meta=e,this)},T.didChange=function(e,t){if(this._cacheable&&this._suspended!==e){var r=E(e);void 0!==r.cache[t]&&(r.cache[t]=void 0,P(this,e,t,r))}},T.get=function(e,t){var r,n,i,a;if(this._cacheable){i=E(e),n=i.cache;var s=n[t];if(s===c)return void 0;if(void 0!==s)return s;r=this.func.call(e,t),n[t]=void 0===r?c:r,a=i.chainWatchers&&i.chainWatchers[t],a&&p(a),O(this,e,t,i)}else r=this.func.call(e,t);return r},T.set=function(e,t,r){var n=this._suspended;this._suspended=e;try{this._set(e,t,r)}finally{this._suspended=n}},T._set=function(e,t,r){var n,i,a,s=this._cacheable,o=this.func,u=E(e,s),l=u.cache,h=!1;if(this._readOnly)throw new y('Cannot set read-only property "'+t+'" on object: '+b(e));if(s&&void 0!==l[t]&&(l[t]!==c&&(i=l[t]),h=!0),n=o.wrappedFunction?o.wrappedFunction.__ember_arity__:o.__ember_arity__,3===n)a=o.call(e,t,r,i);else{if(2!==n)return w(e,t,null,i),void d(e,t,r);a=o.call(e,t,r)}if(!h||i!==a){var p=u.watching[t];return p&&x(e,t),h&&(l[t]=void 0),s&&(h||O(this,e,t,u),l[t]=void 0===a?c:a),p&&C(e,t),a}},T.teardown=function(e,t){var r=E(e);return t in r.cache&&P(this,e,t,r),this._cacheable&&delete r.cache[t],null},f.set=function(e,t,r){e[t]=void 0===r?c:r},f.get=function(e,t){var r=e[t];return r===c?void 0:r},f.remove=function(e,t){e[t]=void 0},l.ComputedProperty=h,l.computed=m,l.cacheFor=f}),e("ember-metal/computed_macros",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/is_empty","ember-metal/is_none","ember-metal/alias"],function(e,t,r,n,i,a,s){"use strict";function o(e,t){for(var r={},n=0;nt}),u("gte",function(e,t){return c(this,e)>=t}),u("lt",function(e,t){return c(this,e)1?(h(this,e,r),r):c(this,e)})}}),e("ember-metal/core",["exports"],function(e){"use strict";"undefined"==typeof i&&(i={});{var t=(i.imports=i.imports||this,i.exports=i.exports||this);i.lookup=i.lookup||this}t.Em=t.Ember=i,i.isNamespace=!0,i.toString=function(){return"Ember"},i.VERSION="1.8.0-beta.4",i.ENV||(i.ENV="undefined"!=typeof EmberENV?EmberENV:"undefined"!=typeof ENV?ENV:{}),i.config=i.config||{},"undefined"==typeof i.ENV.DISABLE_RANGE_API&&(i.ENV.DISABLE_RANGE_API=!0),"undefined"==typeof MetamorphENV&&(t.MetamorphENV={}),MetamorphENV.DISABLE_RANGE_API=i.ENV.DISABLE_RANGE_API,i.FEATURES=i.ENV.FEATURES||{},i.FEATURES.isEnabled=function(e){var t=i.FEATURES[e];return i.ENV.ENABLE_ALL_FEATURES?!0:t===!0||t===!1||void 0===t?t:i.ENV.ENABLE_OPTIONAL_FEATURES?!0:!1},i.EXTEND_PROTOTYPES=i.ENV.EXTEND_PROTOTYPES,"undefined"==typeof i.EXTEND_PROTOTYPES&&(i.EXTEND_PROTOTYPES=!0),i.LOG_STACKTRACE_ON_DEPRECATION=i.ENV.LOG_STACKTRACE_ON_DEPRECATION!==!1,i.SHIM_ES5=i.ENV.SHIM_ES5===!1?!1:i.EXTEND_PROTOTYPES,i.LOG_VERSION=i.ENV.LOG_VERSION===!1?!1:!0;var r=function(){return this},r=r;e.K=r,i.K=r,"undefined"==typeof i.assert&&(i.assert=i.K),"undefined"==typeof i.warn&&(i.warn=i.K),"undefined"==typeof i.debug&&(i.debug=i.K),"undefined"==typeof i.runInDebug&&(i.runInDebug=i.K),"undefined"==typeof i.deprecate&&(i.deprecate=i.K),"undefined"==typeof i.deprecateFunc&&(i.deprecateFunc=function(e,t){return t}),e["default"]=i}),e("ember-metal/dependent_keys",["ember-metal/platform","ember-metal/watching","exports"],function(e,t,r){"use strict";function n(e,t){var r=e[t];return r?e.hasOwnProperty(t)||(r=e[t]=c(r)):r=e[t]={},r}function i(e){return n(e,"deps")}function a(e,t,r,a){var s,o,l,c,h,p=e._dependentKeys;if(p)for(s=i(a),o=0,l=p.length;l>o;o++)c=p[o],h=n(s,c),h[r]=(h[r]||0)+1,u(t,c,a)}function s(e,t,r,a){var s,o,u,c,h,p=e._dependentKeys;if(p)for(s=i(a),o=0,u=p.length;u>o;o++)c=p[o],h=n(s,c),h[r]=(h[r]||0)-1,l(t,c,a)}var o=e.create,u=t.watch,l=t.unwatch,c=o;r.addDependentKeys=a,r.removeDependentKeys=s}),e("ember-metal/deprecate_property",["ember-metal/core","ember-metal/platform","ember-metal/properties","ember-metal/property_get","ember-metal/property_set","exports"],function(e,t,r,n,i,a){"use strict";function s(e,t,r){function n(){}o&&u(e,t,{configurable:!0,enumerable:!1,set:function(e){n(),c(this,r,e)},get:function(){return n(),l(this,r)}})}var o=(e["default"],t.hasPropertyAccessors),u=r.defineProperty,l=n.get,c=i.set;a.deprecateProperty=s}),e("ember-metal/dictionary",["exports"],function(e){"use strict";e["default"]=function(e){var t=Object.create(e);return t._dict=null,delete t._dict,t}}),e("ember-metal/enumerable_utils",["ember-metal/array","exports"],function(e,t){"use strict";function r(e,t,r){return e.map?e.map.call(e,t,r):d.call(e,t,r)}function n(e,t,r){return e.forEach?e.forEach.call(e,t,r):m.call(e,t,r)}function i(e,t,r){return e.filter?e.filter.call(e,t,r):p.call(e,t,r)}function a(e,t,r){return e.indexOf?e.indexOf.call(e,t,r):f.call(e,t,r)}function s(e,t){return void 0===t?[]:r(t,function(t){return a(e,t)})}function o(e,t){var r=a(e,t);-1===r&&e.push(t)}function u(e,t){var r=a(e,t);-1!==r&&e.splice(r,1)}function l(e,t,r,n){for(var i,a,s=[].concat(n),o=[],u=6e4,l=t,c=r;s.length;)i=c>u?u:c,0>=i&&(i=0),a=s.splice(0,u),a=[l,i].concat(a),l+=u,c-=i,o=o.concat(v.apply(e,a));return o}function c(e,t,r,n){return e.replace?e.replace(t,r,n):l(e,t,r,n)}function h(e,t){var r=[];return n(e,function(e){a(t,e)>=0&&r.push(e)}),r}var p=e.filter,m=e.forEach,f=e.indexOf,d=e.map,v=Array.prototype.splice;t.map=r,t.forEach=n,t.filter=i,t.indexOf=a,t.indexesOf=s,t.addObject=o,t.removeObject=u,t._replace=l,t.replace=c,t.intersection=h,t["default"]={_replace:l,addObject:o,filter:i,forEach:n,indexOf:a,indexesOf:s,intersection:h,map:r,removeObject:u,replace:c}}),e("ember-metal/error",["ember-metal/platform","exports"],function(e,t){"use strict";function r(){var e=Error.apply(this,arguments);Error.captureStackTrace&&Error.captureStackTrace(this,i.Error);for(var t=0;t=0;i-=3)if(t===e[i]&&r===e[i+1]){n=i;break}return n}function a(e,t){var r,n=O(e,!0);return n.listeners||(n.listeners={}),n.hasOwnProperty("listeners")||(n.listeners=x(n.listeners)),r=n.listeners[t],r&&!n.listeners.hasOwnProperty(t)?r=n.listeners[t]=n.listeners[t].slice():r||(r=n.listeners[t]=[]),r}function s(e,t,r){var n=e.__ember_meta__,a=n&&n.listeners&&n.listeners[t];if(a)for(var s=a.length-3;s>=0;s-=3){var o=a[s],u=a[s+1],l=a[s+2],c=i(r,o,u);-1===c&&r.push(o,u,l)}}function o(e,t,r){var n=e.__ember_meta__,a=n&&n.listeners&&n.listeners[t],s=[];if(a){for(var o=a.length-3;o>=0;o-=3){var u=a[o],l=a[o+1],c=a[o+2],h=i(r,u,l);-1===h&&(r.push(u,l,c),s.push(u,l,c))}return s}}function u(e,t,r,n,s){n||"function"!=typeof r||(n=r,r=null);var o=a(e,t),u=i(o,r,n),l=0;s&&(l|=P),-1===u&&(o.push(r,n,l),"function"==typeof e.didAddListener&&e.didAddListener(t,r,n))}function l(e,t,r,n){function s(r,n){var s=a(e,t),o=i(s,r,n);-1!==o&&(s.splice(o,3),"function"==typeof e.didRemoveListener&&e.didRemoveListener(t,r,n))}if(n||"function"!=typeof r||(n=r,r=null),n)s(r,n);else{var o=e.__ember_meta__,u=o&&o.listeners&&o.listeners[t];if(!u)return;for(var l=u.length-3;l>=0;l-=3)s(u[l],u[l+1])}}function c(e,t,r,n,s){function o(){return s.call(r)}function u(){-1!==c&&(l[c+2]&=~E)}n||"function"!=typeof r||(n=r,r=null);var l=a(e,t),c=i(l,r,n);return-1!==c&&(l[c+2]|=E),y(o,u)}function h(e,t,r,n,s){function o(){return s.call(r)}function u(){for(var e=0,t=m.length;t>e;e++){var r=m[e];f[e][r+2]&=~E}}n||"function"!=typeof r||(n=r,r=null);var l,c,h,p,m=[],f=[];for(h=0,p=t.length;p>h;h++){l=t[h],c=a(e,l);var d=i(c,r,n);-1!==d&&(c[d+2]|=E,m.push(d),f.push(c))}return y(o,u)}function p(e){var t=e.__ember_meta__.listeners,r=[];if(t)for(var n in t)t[n]&&r.push(n);return r}function m(e,t,r,n){if(e!==b&&"function"==typeof e.sendEvent&&e.sendEvent(t,r),!n){var i=e.__ember_meta__;n=i&&i.listeners&&i.listeners[t]}if(n){for(var a=n.length-3;a>=0;a-=3){var s=n[a],o=n[a+1],u=n[a+2];o&&(u&E||(u&P&&l(e,t,s,o),s||(s=e),"string"==typeof o?r?w(s,o,r):s[o]():r?_(s,o,r):o.call(s)))}return!0}}function f(e,t){var r=e.__ember_meta__,n=r&&r.listeners&&r.listeners[t];return!(!n||!n.length)}function d(e,t){var r=[],n=e.__ember_meta__,i=n&&n.listeners&&n.listeners[t];if(!i)return r;for(var a=0,s=i.length;s>a;a+=3){var o=i[a],u=i[a+1];r.push([o,u])}return r}function v(){var e=C.call(arguments,-1)[0],t=C.call(arguments,0,-1);return e.__ember_listens__=t,e}var b=e["default"],g=t.meta,y=t.tryFinally,_=t.apply,w=t.applyStr,x=r.create,C=[].slice,O=g,P=1,E=2;n.listenersUnion=s,n.listenersDiff=o,n.addListener=u,n.suspendListener=c,n.suspendListeners=h,n.watchedEvents=p,n.sendEvent=m,n.hasListeners=f,n.listenersFor=d,n.on=v,n.removeListener=l}),e("ember-metal/expand_properties",["ember-metal/core","ember-metal/error","ember-metal/enumerable_utils","exports"],function(e,t,r,n){"use strict";function i(e,t){if("string"===s.typeOf(e)){var r=e.split(l),n=[r];u(r,function(e,t){e.indexOf(",")>=0&&(n=a(n,e.split(","),t))}),u(n,function(e){t(e.join(""))})}else t(e)}function a(e,t,r){var n=[];return u(e,function(e){u(t,function(t){var i=e.slice(0);i[r]=t,n.push(i)})}),n}var s=e["default"],o=t["default"],u=r.forEach,l=/\{|\}/;n["default"]=function(e,t){if(e.indexOf(" ")>-1)throw new o("Brace expanded properties cannot contain spaces, e.g. `user.{firstName, lastName}` should be `user.{firstName,lastName}`");return i(e,t)}}),e("ember-metal/get_properties",["ember-metal/property_get","ember-metal/utils","exports"],function(e,t,r){"use strict";var n=e.get,i=t.typeOf;r["default"]=function(e){var t={},r=arguments,a=1;2===arguments.length&&"array"===i(arguments[1])&&(a=0,r=arguments[1]);for(var s=r.length;s>a;a++)t[r[a]]=n(e,r[a]);return t}}),e("ember-metal/instrumentation",["ember-metal/core","ember-metal/utils","exports"],function(e,t,r){"use strict";function n(e,t,r,n){if(0===c.length)return r.call(n);var a=t||{},s=i(e,function(){return a});if(s){var o=function(){return r.call(n)},u=function(e){a.exception=e};return l(o,u,s)}return r.call(n)}function i(e,t){var r=h[e];if(r||(r=p(e)),0!==r.length){var n,i=t(),a=u.STRUCTURED_PROFILE;a&&(n=e+": "+i.object,console.time(n));var s,o,l=r.length,c=new Array(l),f=m();for(s=0;l>s;s++)o=r[s],c[s]=o.before(e,f,i);return function(){var t,s,o,u=m();for(t=0,s=r.length;s>t;t++)o=r[t],o.after(e,u,i,c[t]);a&&console.timeEnd(n)}}}function a(e,t){for(var r,n=e.split("."),i=[],a=0,s=n.length;s>a;a++)r=n[a],i.push("*"===r?"[^\\.]*":r);i=i.join("\\."),i+="(\\..*)?";var o={pattern:e,regex:new RegExp("^"+i+"$"),object:t};return c.push(o),h={},o}function s(e){for(var t,r=0,n=c.length;n>r;r++)c[r]===e&&(t=r);c.splice(t,1),h={}}function o(){c.length=0,h={}}var u=e["default"],l=t.tryCatchFinally,c=[];r.subscribers=c;var h={},p=function(e){for(var t,r=[],n=0,i=c.length;i>n;n++)t=c[n],t.regex.test(e)&&r.push(t.object);return h[e]=r,r},m=function(){var e="undefined"!=typeof window?window.performance||{}:{},t=e.now||e.mozNow||e.webkitNow||e.msNow||e.oNow;return t?t.bind(e):function(){return+new Date}}();r.instrument=n,r._instrumentStart=i,r.subscribe=a,r.unsubscribe=s,r.reset=o}),e("ember-metal/is_blank",["ember-metal/core","ember-metal/is_empty","exports"],function(e,t,r){"use strict";var n=(e["default"],t["default"]);r["default"]=function(e){return n(e)||"string"==typeof e&&null===e.match(/\S/)}}),e("ember-metal/is_empty",["ember-metal/core","ember-metal/property_get","ember-metal/is_none","exports"],function(e,t,r,n){"use strict";function i(e){return o(e)||0===e.length&&"function"!=typeof e||"object"==typeof e&&0===s(e,"length")}var a=e["default"],s=t.get,o=r["default"],u=a.deprecateFunc("Ember.empty is deprecated. Please use Ember.isEmpty instead.",i);n.empty=u,n["default"]=i,n.isEmpty=i,n.empty=u}),e("ember-metal/is_none",["ember-metal/core","exports"],function(e,t){"use strict";function r(e){return null===e||void 0===e}var n=e["default"],i=n.deprecateFunc("Ember.none is deprecated. Please use Ember.isNone instead.",r);t.none=i,t["default"]=r,t.isNone=r}),e("ember-metal/is_present",["ember-metal/is_blank","exports"],function(e,t){"use strict";var r,n=e["default"];r=function(e){return!n(e)},t["default"]=r}),e("ember-metal/keys",["ember-metal/platform","exports"],function(e,t){"use strict";var r=e.canDefineNonEnumerableProperties,n=Object.keys;n&&r||(n=function(){var e=Object.prototype.hasOwnProperty,t=!{toString:null}.propertyIsEnumerable("toString"),r=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],n=r.length;return function(i){if("object"!=typeof i&&("function"!=typeof i||null===i))throw new TypeError("Object.keys called on non-object");var a,s,o=[];for(a in i)"_super"!==a&&0!==a.lastIndexOf("__",0)&&e.call(i,a)&&o.push(a);if(t)for(s=0;n>s;s++)e.call(i,r[s])&&o.push(r[s]);return o}}()),t["default"]=n}),e("ember-metal/libraries",["ember-metal/enumerable_utils","exports"],function(e,t){"use strict";var r=e.forEach,n=e.indexOf,i=function(){var e=[],t=0,i=function(t){for(var r=0;r-1&&i.splice(a,1),this.size--,!0}return!1},isEmpty:function(){return 0===this.size},has:function(e){if(0===this.size)return!1;var t=m(e),r=this.presenceSet;return!!r[t]},forEach:function(e){if("function"!=typeof e&&s(e),0!==this.size){var t,r=this.list,n=arguments.length;if(2===n)for(t=0;ts;s++)n=i[s],e[n]=t[n];return e}}),e("ember-metal/mixin",["ember-metal/core","ember-metal/merge","ember-metal/array","ember-metal/platform","ember-metal/utils","ember-metal/expand_properties","ember-metal/properties","ember-metal/computed","ember-metal/binding","ember-metal/observer","ember-metal/events","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h){"use strict";function p(){var e,t=this.__nextSuper;if(t){for(var r=new Array(arguments.length),n=0,i=r.length;i>n;n++)r[n]=arguments[n];this.__nextSuper=null,e=Z(this,t,r),this.__nextSuper=t}return e}function m(e){var t=dt(e,!0),r=t.mixins;return r?t.hasOwnProperty("mixins")||(r=t.mixins=ft(r)):r=t.mixins={},r}function f(e,t){return t&&t.length>0&&(e.mixins=ct.call(t,function(e){if(e instanceof k)return e;var t=new k;return t.properties=e,t})),e}function d(e){return"function"==typeof e&&e.isMethod!==!1&&e!==Boolean&&e!==Object&&e!==Number&&e!==Array&&e!==Date&&e!==String}function v(e,t){var r;return t instanceof k?(r=Q(t),e[r]?vt:(e[r]=t,t.properties)):t}function b(e,t,r,n){var i;return i=r[e]||n[e],t[e]&&(i=i?i.concat(t[e]):t[e]),i}function g(e,t,r,n,i){var a;return void 0===n[t]&&(a=i[t]),a=a||e.descs[t],void 0!==a&&a instanceof rt?(r=ft(r),r.func=Y(r.func,a.func),r):r}function y(e,t,r,n,i){var a;return void 0===i[t]&&(a=n[t]),a=a||e[t],void 0===a||"function"!=typeof a?r:Y(r,a)}function _(e,t,r,n){var i=n[t]||e[t];return i?"function"==typeof i.concat?i.concat(r):J(i).concat(r):J(r)}function w(e,t,r,n){var i=n[t]||e[t];if(!i)return r;var a=B({},i),s=!1;for(var o in r)if(r.hasOwnProperty(o)){var u=r[o];d(u)?(s=!0,a[o]=y(e,o,u,i,{})):a[o]=u}return s&&(a._super=p),a}function x(e,t,r,n,i,a,s,o){if(r instanceof et){if(r===q&&i[t])return vt;r.func&&(r=g(n,t,r,a,i)),i[t]=r,a[t]=void 0}else s&&ht.call(s,t)>=0||"concatenatedProperties"===t||"mergedProperties"===t?r=_(e,t,r,a):o&&ht.call(o,t)>=0?r=w(e,t,r,a):d(r)&&(r=y(e,t,r,a,i)),i[t]=void 0,a[t]=r}function C(e,t,r,n,i,a){function s(e){delete r[e],delete n[e]}for(var o,u,l,c,h,p,m=0,f=e.length;f>m;m++)if(o=e[m],u=v(t,o),u!==vt)if(u){p=dt(i),i.willMergeMixin&&i.willMergeMixin(u),c=b("concatenatedProperties",u,n,i),h=b("mergedProperties",u,n,i);for(l in u)u.hasOwnProperty(l)&&(a.push(l),x(i,l,u[l],p,r,n,c,h));u.hasOwnProperty("toString")&&(i.toString=u.toString)}else o.mixins&&(C(o.mixins,t,r,n,i,a),o._without&&pt.call(o._without,s))}function O(e,t,r,n){if(bt.test(t)){var i=n.bindings;i?n.hasOwnProperty("bindings")||(i=n.bindings=ft(n.bindings)):i=n.bindings={},i[t]=r}}function P(e,t){var r,n,i,a=t.bindings;if(a){for(r in a)n=a[r],n&&(i=r.slice(0,-7),n instanceof nt?(n=n.copy(),n.to(i)):n=new nt(i,n),n.connect(e),e[r]=n);t.bindings={}}}function E(e,t){return P(e,t||dt(e)),e}function A(e,t,r,n,i){var a,s=t.methodName;return n[s]||i[s]?(a=i[s],t=n[s]):r.descs[s]?(t=r.descs[s],a=void 0):(t=void 0,a=e[s]),{desc:t,value:a}}function T(e,t,r,n,i){var a=r[n];if(a)for(var s=0,o=a.length;o>s;s++)i(e,a[s],null,t)}function N(e,t,r){var n=e[t];"function"==typeof n&&(T(e,t,n,"__ember_observesBefore__",ot),T(e,t,n,"__ember_observes__",at),T(e,t,n,"__ember_listens__",lt)),"function"==typeof r&&(T(e,t,r,"__ember_observesBefore__",st),T(e,t,r,"__ember_observes__",it),T(e,t,r,"__ember_listens__",ut))}function S(e,t,r){var n,i,a,s={},o={},u=dt(e),l=[];e._super=p,C(t,m(e),s,o,e,l);for(var c=0,h=l.length;h>c;c++)if(n=l[c],"constructor"!==n&&o.hasOwnProperty(n)&&(a=s[n],i=o[n],a!==q)){for(;a&&a instanceof R;){var f=A(e,a,u,s,o);a=f.desc,i=f.value}(void 0!==a||void 0!==i)&&(N(e,n,i),O(e,n,i,u),tt(e,n,a,i,u))}return r||E(e,u),e}function V(e){var t=mt.call(arguments,1);return S(e,t,!1),e}function k(){return f(this,arguments)}function I(e,t,r){var n=Q(e);if(r[n])return!1;if(r[n]=!0,e===t)return!0;for(var i=e.mixins,a=i?i.length:0;--a>=0;)if(I(i[a],t,r))return!0;return!1}function j(e,t,r){if(!r[Q(t)])if(r[Q(t)]=!0,t.properties){var n=t.properties;for(var i in n)n.hasOwnProperty(i)&&(e[i]=!0)}else t.mixins&&pt.call(t.mixins,function(t){j(e,t,r)})}function D(){return q}function R(e){this.methodName=e}function M(e){return new R(e)}function L(){var e,t=mt.call(arguments,-1)[0],r=function(t){e.push(t)},n=mt.call(arguments,0,-1);"function"!=typeof t&&(t=arguments[0],n=mt.call(arguments,1)),e=[];for(var i=0;ie;e++){arguments[e]}return L.apply(this,arguments)}function z(){var e,t=mt.call(arguments,-1)[0],r=function(t){e.push(t)},n=mt.call(arguments,0,-1);"function"!=typeof t&&(t=arguments[0],n=mt.call(arguments,1)),e=[];for(var i=0;ir;r++)e=arguments[r],e instanceof k?i.push(e):(t=k.create(),t.properties=e,i.push(t));return this},gt.apply=function(e){return S(e,[this],!1)},gt.applyPartial=function(e){return S(e,[this],!0)},gt.detect=function(e){if(!e)return!1;if(e instanceof k)return I(e,this,{});var t=e.__ember_meta__,r=t&&t.mixins;return r?!!r[Q(this)]:!1},gt.without=function(){var e=new k(this);return e._without=mt.call(arguments),e},gt.keys=function(){var e={},t={},r=[];j(e,this,t);for(var n in e)e.hasOwnProperty(n)&&r.push(n);return r},k.mixins=function(e){var t=e.__ember_meta__,r=t&&t.mixins,n=[];if(!r)return n;for(var i in r){var a=r[i];a.properties||n.push(a)}return n},q=new et,q.toString=function(){return"(Required Property)"},h.required=D,R.prototype=new et,h.aliasMethod=M,h.observer=L,h.immediateObserver=H,h.beforeObserver=z,h.IS_BINDING=bt,h.Mixin=k}),e("ember-metal/observer",["ember-metal/watching","ember-metal/array","ember-metal/events","exports"],function(e,t,r,n){"use strict";function i(e){return e+O}function a(e){return e+P}function s(e,t,r,n){return _(e,i(t),r,n),v(e,t),this}function o(e,t){return y(e,i(t))}function u(e,t,r,n){return b(e,t),w(e,i(t),r,n),this}function l(e,t,r,n){return _(e,a(t),r,n),v(e,t),this}function c(e,t,r,n,i){return C(e,a(t),r,n,i)}function h(e,t,r,n,a){return C(e,i(t),r,n,a)}function p(e,t,r,n,i){var s=g.call(t,a);return x(e,s,r,n,i)}function m(e,t,r,n,a){var s=g.call(t,i);return x(e,s,r,n,a)}function f(e,t){return y(e,a(t))}function d(e,t,r,n){return b(e,t),w(e,a(t),r,n),this}var v=e.watch,b=e.unwatch,g=t.map,y=r.listenersFor,_=r.addListener,w=r.removeListener,x=r.suspendListeners,C=r.suspendListener,O=":change",P=":before";n.addObserver=s,n.observersFor=o,n.removeObserver=u,n.addBeforeObserver=l,n._suspendBeforeObserver=c,n._suspendObserver=h,n._suspendBeforeObservers=p,n._suspendObservers=m,n.beforeObserversFor=f,n.removeBeforeObserver=d}),e("ember-metal/observer_set",["ember-metal/utils","ember-metal/events","exports"],function(e,t,r){"use strict";function n(){this.clear()}var i=e.guidFor,a=t.sendEvent;r["default"]=n,n.prototype.add=function(e,t,r){var n,a=this.observerSet,s=this.observers,o=i(e),u=a[o];return u||(a[o]=u={}),n=u[t],void 0===n&&(n=s.push({sender:e,keyName:t,eventName:r,listeners:[]})-1,u[t]=n),s[n].listeners},n.prototype.flush=function(){var e,t,r,n,i=this.observers;for(this.clear(),e=0,t=i.length;t>e;++e)r=i[e],n=r.sender,n.isDestroying||n.isDestroyed||a(n,r.eventName,[n,r.keyName],r.listeners)},n.prototype.clear=function(){this.observerSet={},this.observers=[]}}),e("ember-metal/path_cache",["ember-metal/cache","exports"],function(e,t){"use strict";function r(e){return c.get(e)}function n(e){return h.get(e)}function i(e){return p.get(e)}function a(e){return m.get(e)}var s=e["default"],o=/^([A-Z$]|([0-9][A-Z$]))/,u=/^([A-Z$]|([0-9][A-Z$])).*[\.]/,l="this.",c=new s(1e3,function(e){return o.test(e)}),h=new s(1e3,function(e){return u.test(e)}),p=new s(1e3,function(e){return-1!==e.indexOf(l)}),m=new s(1e3,function(e){return-1!==e.indexOf(".")}),f={isGlobalCache:c,isGlobalPathCache:h,hasThisCache:p,isPathCache:m};t.caches=f,t.isGlobal=r,t.isGlobalPath=n,t.hasThis=i,t.isPath=a}),e("ember-metal/platform",["exports"],function(e){"use strict";var t=function(e){if(e)try{var t=5,r={};if(e(r,"a",{configurable:!0,enumerable:!0,get:function(){return t},set:function(e){t=e}}),5!==r.a)return;if(r.a=10,10!==t)return;e(r,"a",{configurable:!0,enumerable:!1,writable:!0,value:!0});for(var n in r)if("a"===n)return;if(r.a!==!0)return;return e}catch(i){return}}(Object.defineProperty),r=!!t;if(r&&"undefined"!=typeof document){var n=function(){try{return t(document.createElement("div"),"definePropertyOnDOM",{}),!0}catch(e){}return!1}();n||(t=function(e,t,r){var n;return n="object"==typeof Node?e instanceof Node:"object"==typeof e&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName,n?e[t]=r.value:Object.defineProperty(e,t,r)})}r||(t=function(e,t,r){r.get||(e[t]=r.value)}),Object.defineProperties||(Object.defineProperties=function(e,r){for(var n in r)r.hasOwnProperty(n)&&"__proto__"!==n&&t(e,n,r[n]);return e});var i;if(!Object.create||Object.create(null).hasOwnProperty){var a,s=!({__proto__:null}instanceof Object);a=s||"undefined"==typeof document?function(){return{__proto__:null}}:function(){function e(){}var t=document.createElement("iframe"),r=document.body||document.documentElement;t.style.display="none",r.appendChild(t),t.src="javascript:";var n=t.contentWindow.Object.prototype;return r.removeChild(t),t=null,delete n.constructor,delete n.hasOwnProperty,delete n.propertyIsEnumerable,delete n.isPrototypeOf,delete n.toLocaleString,delete n.toString,delete n.valueOf,e.prototype=n,a=function(){return new e},new e},i=Object.create=function(e,t){function r(){}var n;if(null===e)n=a();else{if("object"!=typeof e&&"function"!=typeof e)throw new TypeError("Object prototype may only be an Object or null");r.prototype=e,n=new r}return void 0!==t&&Object.defineProperties(n,t),n}}else i=Object.create;var o=r,u=r,l={};l.defineProperty=t,l.hasPropertyAccessors=o,e.create=i,e.defineProperty=t,e.hasPropertyAccessors=o,e.canDefineNonEnumerableProperties=u,e.platform=l}),e("ember-metal/properties",["ember-metal/core","ember-metal/utils","ember-metal/platform","ember-metal/property_events","exports"],function(e,t,r,n,i){"use strict";function a(){}function s(){}function o(e){return function(){var t=this.__ember_meta__;return t&&t.values[e]}}function u(e,t,r,n,i){var s,o,u,p;i||(i=l(e)),s=i.descs,o=i.descs[t];var m=i.watching[t];return u=void 0!==m&&m>0,o instanceof a&&o.teardown(e,t),r instanceof a?(p=r,s[t]=r,e[t]=void 0,r.setup&&r.setup(e,t)):(s[t]=void 0,null==r?(p=n,e[t]=n):(p=r,c(e,t,r))),u&&h(e,t,i),e.didDefineProperty&&e.didDefineProperty(e,t,p),this}var l=(e["default"],t.meta),c=r.defineProperty,h=(r.hasPropertyAccessors,n.overrideChains);i.Descriptor=a,i.MANDATORY_SETTER_FUNCTION=s,i.DEFAULT_GETTER_FUNCTION=o,i.defineProperty=u}),e("ember-metal/property_events",["ember-metal/utils","ember-metal/events","ember-metal/observer_set","exports"],function(e,t,r,n){"use strict";function i(e,t){var r=e.__ember_meta__,n=r&&r.watching[t]>0||"length"===t,i=r&&r.proto,a=r&&r.descs[t];n&&i!==e&&(a&&a.willChange&&a.willChange(e,t),s(e,t,r),c(e,t,r),v(e,t))}function a(e,t){var r=e.__ember_meta__,n=r&&r.watching[t]>0||"length"===t,i=r&&r.proto,a=r&&r.descs[t];i!==e&&(a&&a.didChange&&a.didChange(e,t),(n||"length"===t)&&(r&&r.deps&&r.deps[t]&&o(e,t,r),h(e,t,r,!1),b(e,t)))}function s(e,t,r){if(!e.isDestroying){var n;if(r&&r.deps&&(n=r.deps[t])){var a=g,s=!a;s&&(a=g={}),l(i,e,n,t,a,r),s&&(g=null)}}}function o(e,t,r){if(!e.isDestroying){var n;if(r&&r.deps&&(n=r.deps[t])){var i=y,s=!i;s&&(i=y={}),l(a,e,n,t,i,r),s&&(y=null)}}}function u(e){var t=[];for(var r in e)t.push(r);return t}function l(e,t,r,n,i,a){var s,o,l,c,h=_(t),p=i[h];if(p||(p=i[h]={}),!p[n]&&(p[n]=!0,r)){s=u(r);var m=a.descs;for(l=0;ln;n++)s[n].willChange(o);for(n=0,a=o.length;a>n;n+=2)i(o[n],o[n+1])}}function h(e,t,r,n){if(r&&r.hasOwnProperty("chainWatchers")&&r.chainWatchers[t]){var i,s,o=r.chainWatchers[t],u=n?null:[];for(i=0,s=o.length;s>i;i++)o[i].didChange(u);if(!n)for(i=0,s=u.length;s>i;i+=2)a(u[i],u[i+1])}}function p(e,t,r){h(e,t,r,!0)}function m(){T++}function f(){T--,0>=T&&(E.clear(),A.flush())}function d(e,t){m(),w(e,f,t)}function v(e,t){if(!e.isDestroying){var r,n,i=t+":before";T?(r=E.add(e,t,i),n=O(e,i,r),x(e,i,[e,t],n)):x(e,i,[e,t])}}function b(e,t){if(!e.isDestroying){var r,n=t+":change";T?(r=A.add(e,t,n),C(e,n,r)):x(e,n,[e,t])}}var g,y,_=e.guidFor,w=e.tryFinally,x=t.sendEvent,C=t.listenersUnion,O=t.listenersDiff,P=r["default"],E=new P,A=new P,T=0;n.propertyWillChange=i,n.propertyDidChange=a,n.overrideChains=p,n.beginPropertyChanges=m,n.endPropertyChanges=f,n.changeProperties=d}),e("ember-metal/property_get",["ember-metal/core","ember-metal/error","ember-metal/path_cache","ember-metal/platform","exports"],function(e,t,r,n,i){"use strict";function a(e,t){var r,n=p(t),i=!n&&c(t);if((!e||i)&&(e=u.lookup),n&&(t=t.slice(5)),e===u.lookup&&(r=t.match(m)[0],e=f(e,r),t=t.slice(r.length+1)),!t||0===t.length)throw new l("Path cannot be empty");return[e,t]}function s(e,t){var r,n,i,s,o;if(null===e&&!h(t))return f(u.lookup,t);for(r=p(t),(!e||r)&&(i=a(e,t),e=i[0],t=i[1],i.length=0),n=t.split("."),o=n.length,s=0;null!=e&&o>s;s++)if(e=f(e,n[s],!0),e&&e.isDestroyed)return void 0;return e}function o(e,t,r){var n=f(e,t);return void 0===n?r:n}var u=e["default"],l=t["default"],c=r.isGlobalPath,h=r.isPath,p=r.hasThis,m=(n.hasPropertyAccessors,/^([^\.]+)/),f=function(e,t){if(""===t)return e;if(t||"string"!=typeof e||(t=e,e=null),null===e){var r=s(e,t);return r}var n,i=e.__ember_meta__,a=i&&i.descs[t];return void 0===a&&h(t)?s(e,t):a?a.get(e,t):(n=e[t],void 0!==n||"object"!=typeof e||t in e||"function"!=typeof e.unknownProperty?n:e.unknownProperty(t))};u.config.overrideAccessors&&(u.get=f,u.config.overrideAccessors(),f=u.get),i.getWithDefault=o,i["default"]=f,i.get=f,i.normalizeTuple=a,i._getPath=s}),e("ember-metal/property_set",["ember-metal/core","ember-metal/property_get","ember-metal/property_events","ember-metal/properties","ember-metal/error","ember-metal/path_cache","ember-metal/platform","exports"],function(e,t,r,n,i,a,s,o){"use strict";function u(e,t,r,n){var i;if(i=t.slice(t.lastIndexOf(".")+1),t=t===i?i:t.slice(0,t.length-(i.length+1)),"this"!==t&&(e=h(e,t)),!i||0===i.length)throw new f("Property set failed: You passed an empty path");if(!e){if(n)return;throw new f('Property set failed: object in path "'+t+'" could not be found or was destroyed.')}return v(e,i,r)}function l(e,t,r){return v(e,t,r,!0)}var c=e["default"],h=t._getPath,p=r.propertyWillChange,m=r.propertyDidChange,f=(n.defineProperty,i["default"]),d=a.isPath,v=(s.hasPropertyAccessors,function(e,t,r,n){if("string"==typeof e&&(r=t,t=e,e=null),!e)return u(e,t,r,n);var i,a,s=e.__ember_meta__,o=s&&s.descs[t];if(void 0===o&&d(t))return u(e,t,r,n);if(void 0!==o)o.set(e,t,r);else{if("object"==typeof e&&null!==e&&void 0!==r&&e[t]===r)return r;i="object"==typeof e&&!(t in e),i&&"function"==typeof e.setUnknownProperty?e.setUnknownProperty(t,r):s&&s.watching[t]>0?(a=e[t],r!==a&&(p(e,t),e[t]=r,m(e,t))):e[t]=r}return r});c.config.overrideAccessors&&(c.set=v,c.config.overrideAccessors(),v=c.set),o.trySet=l,o.set=v}),e("ember-metal/run_loop",["ember-metal/core","ember-metal/utils","ember-metal/array","ember-metal/property_events","backburner","exports"],function(e,t,r,n,i,a){"use strict";function s(e){u.currentRunLoop=e}function o(e,t){u.currentRunLoop=t}function u(){return h(b,b.run,arguments)}function l(){!u.currentRunLoop}{var c=e["default"],h=t.apply,p=t.GUID_KEY,m=r.indexOf,f=n.beginPropertyChanges,d=n.endPropertyChanges,v=i["default"],b=new v(["sync","actions","destroy"],{GUID_KEY:p,sync:{before:f,after:d},defaultQueue:"actions",onBegin:s,onEnd:o,onErrorTarget:c,onErrorMethod:"onerror"}),g=[].slice;[].concat}a["default"]=u,u.join=function(){if(!u.currentRunLoop)return h(c,u,arguments);var e=g.call(arguments);e.unshift("actions"),h(u,u.schedule,e)},u.bind=function(){var e=g.call(arguments);return function(){return h(u,u.join,e.concat(g.call(arguments)))}},u.backburner=b,u.currentRunLoop=null,u.queues=b.queueNames,u.begin=function(){b.begin()},u.end=function(){b.end()},u.schedule=function(){l(),h(b,b.schedule,arguments)},u.hasScheduledTimers=function(){return b.hasTimers()},u.cancelTimers=function(){b.cancelTimers()},u.sync=function(){b.currentInstance&&b.currentInstance.queues.sync.flush()},u.later=function(){return h(b,b.later,arguments)},u.once=function(){l();var e=g.call(arguments);return e.unshift("actions"),h(b,b.scheduleOnce,e)},u.scheduleOnce=function(){return l(),h(b,b.scheduleOnce,arguments)},u.next=function(){var e=g.call(arguments);return e.push(1),h(b,b.later,e)},u.cancel=function(e){return b.cancel(e)},u.debounce=function(){return h(b,b.debounce,arguments)},u.throttle=function(){return h(b,b.throttle,arguments)},u._addQueue=function(e,t){-1===m.call(u.queues,e)&&u.queues.splice(m.call(u.queues,t)+1,0,e)}}),e("ember-metal/set_properties",["ember-metal/property_events","ember-metal/property_set","ember-metal/keys","exports"],function(e,t,r,n){"use strict";var i=e.changeProperties,a=t.set,s=r["default"];n["default"]=function(e,t){return i(function(){for(var r,n=s(t),i=0,o=n.length;o>i;i++)r=n[i],a(e,r,t[r])}),e}}),e("ember-metal/utils",["ember-metal/core","ember-metal/platform","ember-metal/array","exports"],function(e,t,r,n){"use strict";function i(){return++A}function a(e){var t={};t[e]=1;for(var r in t)if(r===e)return r;return e}function s(e,t){t||(t=T);var r=t+i();return e&&(null===e[k]?e[k]=r:(I.value=r,C(e,k,I))),r}function o(e){if(void 0===e)return"(undefined)";if(null===e)return"(null)";var t,r=typeof e;switch(r){case"number":return t=S[e],t||(t=S[e]="nu"+e),t;case"string":return t=V[e],t||(t=V[e]="st"+i()),t;case"boolean":return e?"(true)":"(false)";default:return e[k]?e[k]:e===Object?"(Object)":e===Array?"(Array)":(t=T+i(),null===e[k]?e[k]=t:(I.value=t,C(e,k,I)),t)}}function u(e){this.descs={},this.watching={},this.cache={},this.cacheMeta={},this.source=e}function l(e,t){var r=e.__ember_meta__;return t===!1?r||D:(r?r.source!==e&&(O&&C(e,"__ember_meta__",j),r=N(r),r.descs=N(r.descs),r.watching=N(r.watching),r.cache={},r.cacheMeta={},r.source=e,e.__ember_meta__=r):(O&&C(e,"__ember_meta__",j),r=new u(e),e.__ember_meta__=r,r.descs.constructor=null),r)}function c(e,t){var r=l(e,!1);return r[t]}function h(e,t,r){var n=l(e,!0);return n[t]=r,r}function p(e,t,r){for(var n,i,a=l(e,r),s=0,o=t.length;o>s;s++){if(n=t[s],i=a[n]){if(i.__ember_source__!==e){if(!r)return void 0;i=a[n]=N(i),i.__ember_source__=e}}else{if(!r)return void 0;i=a[n]={__ember_source__:e}}a=i}return i}function m(e,t){function r(){for(var r,n=this&&this.__nextSuper,i=new Array(arguments.length),a=0,s=i.length;s>a;a++)i[a]=arguments[a];return this&&(this.__nextSuper=t),r=_(this,e,i),this&&(this.__nextSuper=n),r}return r.wrappedFunction=e,r.wrappedFunction.__ember_arity__=e.length,r.__ember_observes__=e.__ember_observes__,r.__ember_observesBefore__=e.__ember_observesBefore__,r.__ember_listens__=e.__ember_listens__,r}function f(e){var t,r;return"undefined"==typeof R&&(t="ember-runtime/mixins/array",x.__loader.registry[t]&&(R=x.__loader.require(t)["default"])),!e||e.setInterval?!1:Array.isArray&&Array.isArray(e)?!0:R&&R.detect(e)?!0:(r=g(e),"array"===r?!0:void 0!==e.length&&"object"===r?!0:!1)}function d(e){return null===e||void 0===e?[]:f(e)?e:[e]}function v(e,t){return!(!e||"function"!=typeof e[t])}function b(e,t,r){return v(e,t)?r?w(e,t,r):w(e,t):void 0}function g(e){var t,r;return"undefined"==typeof F&&(r="ember-runtime/system/object",x.__loader.registry[r]&&(F=x.__loader.require(r)["default"])),t=null===e||void 0===e?String(e):z[B.call(e)]||"object","function"===t?F&&F.detect(e)&&(t="class"):"object"===t&&(e instanceof Error?t="error":F&&e instanceof F?t="instance":e instanceof Date&&(t="date")),t}function y(e){var t=g(e);if("array"===t)return"["+e+"]";if("object"!==t)return e+"";var r,n=[];for(var i in e)if(e.hasOwnProperty(i)){if(r=e[i],"toString"===r)continue;"function"===g(r)&&(r="function() { ... }"),n.push(r&&"function"!=typeof r.toString?i+": "+B.call(r):i+": "+r)}return"{"+n.join(", ")+"}"}function _(e,t,r){var n=r&&r.length;if(!r||!n)return t.call(e);switch(n){case 1:return t.call(e,r[0]);case 2:return t.call(e,r[0],r[1]);case 3:return t.call(e,r[0],r[1],r[2]);case 4:return t.call(e,r[0],r[1],r[2],r[3]);case 5:return t.call(e,r[0],r[1],r[2],r[3],r[4]);default:return t.apply(e,r)}}function w(e,t,r){var n=r&&r.length;if(!r||!n)return e[t]();switch(n){case 1:return e[t](r[0]);case 2:return e[t](r[0],r[1]);case 3:return e[t](r[0],r[1],r[2]);case 4:return e[t](r[0],r[1],r[2],r[3]);case 5:return e[t](r[0],r[1],r[2],r[3],r[4]);default:return e[t].apply(e,r)}}var x=e["default"],C=t.defineProperty,O=t.canDefineNonEnumerableProperties,P=(t.hasPropertyAccessors,t.create),E=r.forEach,A=0;n.uuid=i;var T="ember",N=P,S=[],V={},k=a("__ember"+ +new Date),I={writable:!1,configurable:!1,enumerable:!1,value:null};n.generateGuid=s,n.guidFor=o;var j={writable:!0,configurable:!1,enumerable:!1,value:null};u.prototype={descs:null,deps:null,watching:null,listeners:null,cache:null,cacheMeta:null,source:null,mixins:null,bindings:null,chains:null,chainWatchers:null,values:null,proto:null},O||(u.prototype.__preventPlainObject__=!0,u.prototype.toJSON=function(){});var D=new u(null);n.getMeta=c,n.setMeta=h,n.metaPath=p,n.wrap=m;var R;n.makeArray=d,n.tryInvoke=b;var M,L=function(){var e=0;try{try{}finally{throw e++,new Error("needsFinallyFixTest")}}catch(t){}return 1!==e}();M=L?function(e,t,r){var n,i,a;r=r||this;try{n=e.call(r)}finally{try{i=t.call(r)}catch(s){a=s}}if(a)throw a;return void 0===i?n:i}:function(e,t,r){var n,i;r=r||this;try{n=e.call(r)}finally{i=t.call(r)}return void 0===i?n:i};var H;H=L?function(e,t,r,n){var i,a,s;n=n||this;try{i=e.call(n)}catch(o){i=t.call(n,o)}finally{try{a=r.call(n)}catch(u){s=u}}if(s)throw s;return void 0===a?i:a}:function(e,t,r,n){var i,a;n=n||this;try{i=e.call(n)}catch(s){i=t.call(n,s)}finally{a=r.call(n)}return void 0===a?i:a};var z={},q="Boolean Number String Function Array Date RegExp Object".split(" ");E.call(q,function(e){z["[object "+e+"]"]=e.toLowerCase()});var F,B=Object.prototype.toString;n.inspect=y,n.apply=_,n.applyStr=w,n.GUID_KEY=k,n.META_DESC=j,n.EMPTY_META=D,n.meta=l,n.typeOf=g,n.tryCatchFinally=H,n.isArray=f,n.canInvoke=v,n.tryFinally=M}),e("ember-metal/watch_key",["ember-metal/core","ember-metal/utils","ember-metal/platform","ember-metal/properties","exports"],function(e,t,r,n,i){"use strict";function a(e,t,r){if("length"!==t||"array"!==u(e)){var n=r||l(e),i=n.watching;if(i[t])i[t]=(i[t]||0)+1;else{i[t]=1;var a=n.descs[t];a&&a.willWatch&&a.willWatch(e,t),"function"==typeof e.willWatchProperty&&e.willWatchProperty(t)}}}function s(e,t,r){var n=r||l(e),i=n.watching;if(1===i[t]){i[t]=0;var a=n.descs[t];a&&a.didUnwatch&&a.didUnwatch(e,t),"function"==typeof e.didUnwatchProperty&&e.didUnwatchProperty(t)}else i[t]>1&&i[t]--}var o=(e["default"],t.meta),u=t.typeOf,l=(r.defineProperty,r.hasPropertyAccessors,n.MANDATORY_SETTER_FUNCTION,n.DEFAULT_GETTER_FUNCTION,o);i.watchKey=a,i.unwatchKey=s}),e("ember-metal/watch_path",["ember-metal/utils","ember-metal/chains","exports"],function(e,t,r){"use strict";function n(e,t){var r=t||l(e),n=r.chains;return n?n.value()!==e&&(n=r.chains=n.copy(e)):n=r.chains=new u(null,null,e),n}function i(e,t,r){if("length"!==t||"array"!==o(e)){var i=r||l(e),a=i.watching;a[t]?a[t]=(a[t]||0)+1:(a[t]=1,n(e,i).add(t))}}function a(e,t,r){var i=r||l(e),a=i.watching;1===a[t]?(a[t]=0,n(e,i).remove(t)):a[t]>1&&a[t]--}var s=e.meta,o=e.typeOf,u=t.ChainNode,l=s;r.watchPath=i,r.unwatchPath=a}),e("ember-metal/watching",["ember-metal/utils","ember-metal/chains","ember-metal/watch_key","ember-metal/watch_path","ember-metal/path_cache","exports"],function(e,t,r,n,i,a){"use strict";function s(e,t,r){("length"!==t||"array"!==p(e))&&(_(t)?g(e,t,r):v(e,t,r))}function o(e,t){var r=e.__ember_meta__;return(r&&r.watching[t])>0}function u(e,t,r){("length"!==t||"array"!==p(e))&&(_(t)?y(e,t,r):b(e,t,r))}function l(e){var t=e.__ember_meta__,r=t&&t.chains;h in e&&!e.hasOwnProperty(h)&&m(e),r&&r.value()!==e&&(t.chains=r.copy(e))}function c(e){var t,r,n,i,a=e.__ember_meta__;if(a&&(e.__ember_meta__=null,t=a.chains))for(w.push(t);w.length>0;){if(t=w.pop(),r=t._chains)for(n in r)r.hasOwnProperty(n)&&w.push(r[n]);t._watching&&(i=t._object,i&&f(i,t._key,t))}}var h=(e.meta,e.GUID_KEY),p=e.typeOf,m=e.generateGuid,f=t.removeChainWatcher,d=t.flushPendingChains,v=r.watchKey,b=r.unwatchKey,g=n.watchPath,y=n.unwatchPath,_=i.isPath;a.watch=s,a.isWatching=o,s.flushPending=d,a.unwatch=u,a.rewatch=l;var w=[];a.destroy=c}),e("ember-routing-handlebars",["ember-metal/core","ember-handlebars","ember-routing/system/router","ember-routing-handlebars/helpers/shared","ember-routing-handlebars/helpers/link_to","ember-routing-handlebars/helpers/outlet","ember-routing-handlebars/helpers/render","ember-routing-handlebars/helpers/action","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";var l=e["default"],c=t["default"],h=r["default"],p=n.resolvePaths,m=n.resolveParams,f=i.deprecatedLinkToHelper,d=i.linkToHelper,v=i.LinkView,b=i.queryParamsHelper,g=a.outletHelper,y=a.OutletView,_=s["default"],w=o.ActionHelper,x=o.actionHelper;h.resolveParams=m,h.resolvePaths=p,l.LinkView=v,c.ActionHelper=w,c.OutletView=y,c.registerHelper("render",_),c.registerHelper("action",x),c.registerHelper("outlet",g),c.registerHelper("link-to",d),c.registerHelper("linkTo",f),c.registerHelper("query-params",b),u["default"]=l}),e("ember-routing-handlebars/helpers/action",["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/run_loop","ember-views/system/utils","ember-views/system/action_manager","ember-routing/system/router","ember-handlebars","ember-handlebars/ext","ember-handlebars/helpers/view","ember-routing-handlebars/helpers/shared","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p){"use strict";function m(e,t){var r=[];t&&r.push(t);var n=e.options.types.slice(1),i=e.options.data;return r.concat(x(e.context,e.params,{types:n,data:i}))}function f(e){var t=arguments[arguments.length-1],r=O.call(arguments,1,-1),n=t.hash,i=t.data.keywords.controller,a={eventName:n.on||"click",parameters:{context:this,options:t,params:r},view:t.data.view,bubbles:n.bubbles,preventDefault:n.preventDefault,target:{options:t},withKeyCode:n.withKeyCode,boundProperty:"ID"===t.types[0]};n.target?(a.target.root=this,a.target.target=n.target):i&&(a.target.root=i);var s=P.registerAction(e,a,n.allowedKeys);return new C('data-ember-action="'+s+'"')}var d=(e["default"],t.get,r.forEach),v=n.uuid,b=i["default"],g=a.isSimpleClick,y=s["default"],_=(o["default"],u["default"]),w=l.handlebarsGet,x=(c.viewHelper,h.resolveParams),C=(h.resolvePath,_.SafeString),O=Array.prototype.slice,P={};P.registeredActions=y.registeredActions,p.ActionHelper=P;var E=["alt","shift","meta","ctrl"],A=/^click|mouse|touch/,T=function(e,t){if("undefined"==typeof t){if(A.test(e.type))return g(e);t=""}if(t.indexOf("any")>=0)return!0;var r=!0;return d.call(E,function(n){e[n+"Key"]&&-1===t.indexOf(n)&&(r=!1)}),r};P.registerAction=function(e,t,r){var n=v();return y.registeredActions[n]={eventName:t.eventName,handler:function(n){if(!T(n,r))return!0;t.preventDefault!==!1&&n.preventDefault(),t.bubbles===!1&&n.stopPropagation();{var i,a=t.target,s=t.parameters;t.eventName}a=a.target?w(a.root,a.target,a.options):a.root,t.boundProperty&&(i=x(s.context,[e],{types:["ID"],data:s.options.data})[0],("undefined"==typeof i||"function"==typeof i)&&(i=e)),i||(i=e),b(function(){a.send?a.send.apply(a,m(s,i)):a[i].apply(a,m(s))})}},t.view.on("willClearRender",function(){delete y.registeredActions[n]}),n},p.actionHelper=f}),e("ember-routing-handlebars/helpers/link_to",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-runtime/system/lazy_load","ember-runtime/system/string","ember-runtime/system/object","ember-metal/keys","ember-views/system/utils","ember-views/views/component","ember-handlebars","ember-handlebars/helpers/view","ember-routing/system/router","ember-routing-handlebars/helpers/shared","exports"],function(e,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b){"use strict";function g(e){var t=e.options.types,r=e.options.data;return M(e.context,e.params,{types:t,data:r})}function y(){var e=H.call(arguments,-1)[0],t=H.call(arguments,0,-1),r=e.hash;if(t[t.length-1]instanceof q&&(r.queryParamsObject=t.pop()),r.disabledBinding=r.disabledWhen,!e.fn){var n=t.shift(),i=e.types.shift(),a=this;"ID"===i?(e.linkTextPath=n,e.fn=function(){return j.getEscaped(a,n,e)}):e.fn=function(){return n}}return r.parameters={context:this,options:e,params:t},e.helperName=e.helperName||"link-to",D.call(this,F,e)}function _(e){return q.create({values:e.hash,types:e.hashTypes})}function w(){return y.apply(this,arguments)}function x(e){var t=e.parameters,r=e.queryParamsObject,n={};if(!r)return n;var i=r.values;for(var a in i)if(i.hasOwnProperty(a)){var s=i[a],o=r.types[a];if("ID"===o){var u=C(s,t);s=j.get(u.root,u.path,t.options)}n[a]=s}return n}function C(e,t){return j.normalizePath(t.context,e,t.options.data)}function O(e){for(var t=0,r=e.length;r>t;++t){var n=e[t];if(null===n||"undefined"==typeof n)return!1}return!0}function P(e,t){var r;for(r in e)if(e.hasOwnProperty(r)&&e[r]!==t[r])return!1;for(r in t)if(t.hasOwnProperty(r)&&e[r]!==t[r])return!1;return!0}var E=e["default"],A=r.get,T=(n.set,i["default"]),N=a["default"],S=s.computed,V=(o.onLoad,u.fmt,l["default"]),k=(c["default"],h.isSimpleClick),I=p["default"],j=m["default"],D=f.viewHelper,R=(d["default"],v.resolveParams),M=v.resolvePaths,L=v.routeArgs,H=[].slice;t("ember-handlebars");var z=function(e,t){for(var r=0,n=0,i=t.length;i>n&&(r+=t[n].names.length,t[n].handler!==e);n++);return r},q=V.extend({values:null}),F=E.LinkView=I.extend({tagName:"a",currentWhen:null,"current-when":null,title:null,rel:null,activeClass:"active",loadingClass:"loading",disabledClass:"disabled",_isDisabled:!1,replace:!1,attributeBindings:["href","title","rel","tabindex"],classNameBindings:["active","loading","disabled"],eventName:"click",init:function(){this._super.apply(this,arguments);var e=A(this,"eventName");this.on(e,this,this._invoke)},_paramsChanged:function(){this.notifyPropertyChange("resolvedParams")},_setupPathObservers:function(){var e,t,r,n=this.parameters,i=n.options.linkTextPath,a=g(n),s=a.length;for(i&&(r=C(i,n),this.registerObserver(r.root,r.path,this,this.rerender)),t=0;s>t;t++)e=a[t],null!==e&&(r=C(e,n),this.registerObserver(r.root,r.path,this,this._paramsChanged));var o=this.queryParamsObject;if(o){var u=o.values;for(var l in u)u.hasOwnProperty(l)&&"ID"===o.types[l]&&(r=C(u[l],n),this.registerObserver(r.root,r.path,this,this._paramsChanged))}},afterRender:function(){this._super.apply(this,arguments),this._setupPathObservers()},disabled:S(function(e,t){return void 0!==t&&this.set("_isDisabled",t),t?A(this,"disabledClass"):!1}),active:S("loadedParams",function(){function e(e){var i=t.router.recognizer.handlersFor(e),s=i[i.length-1].handler,o=z(e,i);n.length>o&&(e=s);var u=L(e,n,null),l=t.isActive.apply(t,u);if(!l)return!1;var c=E.isEmpty(E.keys(r.queryParams));if(!a&&!c&&l){var h={};T(h,r.queryParams),t._prepareQueryParams(r.targetRouteName,r.models,h),l=P(h,t.router.state.queryParams)}return l}if(A(this,"loading"))return!1;var t=A(this,"router"),r=A(this,"loadedParams"),n=r.models,i=this["current-when"]||this.currentWhen,a=Boolean(i);i=i||r.targetRouteName,i=i.split(" ");for(var s=0,o=i.length;o>s;s++)if(e(i[s]))return A(this,"activeClass")}),loading:S("loadedParams",function(){return A(this,"loadedParams")?void 0:A(this,"loadingClass")}),router:S(function(){var e=A(this,"controller");return e&&e.container?e.container.lookup("router:main"):void 0}),_invoke:function(e){if(!k(e))return!0;if(this.preventDefault!==!1){var t=A(this,"target");t&&"_self"!==t||e.preventDefault()}if(this.bubbles===!1&&e.stopPropagation(),A(this,"_isDisabled"))return!1;if(A(this,"loading"))return E.Logger.warn("This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid."),!1;var r=A(this,"target");if(r&&"_self"!==r)return!1;var n=A(this,"router"),i=A(this,"loadedParams"),a=n._doTransition(i.targetRouteName,i.models,i.queryParams);A(this,"replace")&&a.method("replace");var s=L(i.targetRouteName,i.models,a.state.queryParams),o=n.router.generate.apply(n.router,s);N.scheduleOnce("routerTransitions",this,this._eagerUpdateUrl,a,o)},_eagerUpdateUrl:function(e,t){if(e.isActive&&e.urlMethod){0===t.indexOf("#")&&(t=t.slice(1));var r=A(this,"router.router");"update"===e.urlMethod?r.updateURL(t):"replace"===e.urlMethod&&r.replaceURL(t),e.method(null)}},resolvedParams:S("router.url",function(){var e,t,r=this.parameters,n=r.options,i=n.types,a=n.data,s=0===r.params.length;if(s){var o=this.container.lookup("controller:application");e=A(o,"currentRouteName"),t=[]}else t=R(r.context,r.params,{types:i,data:a}),e=t.shift();var u=x(this,e);return{targetRouteName:e,models:t,queryParams:u}}),loadedParams:S("resolvedParams",function(){var e=A(this,"router");if(e){var t=A(this,"resolvedParams"),r=t.targetRouteName;if(r&&O(t.models))return t}}),queryParamsObject:null,href:S("loadedParams",function(){if("a"===A(this,"tagName")){var e=A(this,"router"),t=A(this,"loadedParams");if(!t)return A(this,"loadingHref");var r={};T(r,t.queryParams),e._prepareQueryParams(t.targetRouteName,t.models,r);var n=L(t.targetRouteName,t.models,r),i=e.generate.apply(e,n);return i}}),loadingHref:"#"});F.toString=function(){return"LinkView"},F.reopen({attributeBindings:["target"],target:null}),b.queryParamsHelper=_,b.LinkView=F,b.deprecatedLinkToHelper=w,b.linkToHelper=y}),e("ember-routing-handlebars/helpers/outlet",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-views/views/container_view","ember-handlebars/views/metamorph_view","ember-handlebars/helpers/view","exports"],function(e,t,r,n,i,a,s,o){"use strict";function u(e,t){var r,n,i,a,s;for(e&&e.data&&e.data.isRenderData&&(t=e,e="main"),n=t.data.view.container,r=t.data.view;!r.get("template.isTop");)r=r.get("_parentView");return i=t.hash.view,i&&(s="view:"+i),a=i?n.lookupFactory(s):t.hash.viewClass||p,t.data.view.set("outletSource",r),t.hash.currentViewBinding="_view.outletSource._outlets."+e,t.helperName=t.helperName||"outlet",h.call(this,a,t)}var l=(e["default"],t.get,r.set,n.onLoad,i["default"]),c=a._Metamorph,h=s.viewHelper,p=l.extend(c);o.OutletView=p,o.outletHelper=u}),e("ember-routing-handlebars/helpers/render",["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-routing/system/generate_controller","ember-handlebars/ext","ember-handlebars/helpers/view","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";var l=(e["default"],t["default"]),c=(r.get,n.set,i.camelize),h=a.generateControllerFactory,p=a["default"],m=s.handlebarsGet,f=o.ViewHelper;u["default"]=function(e,t,r){var n,i,a,s,o,u=arguments.length;if(n=(r||t).data.keywords.controller.container,i=n.lookup("router:main"),2===u)r=t,t=void 0;else{if(3!==u)throw new l("You must pass a templateName to render");o=m(r.contexts[1],t,r)}e=e.replace(/\//g,"."),s=n.lookup("view:"+e)||n.lookup("view:default");var d=r.hash.controller||e,v="controller:"+d;r.hash.controller;var b=r.data.keywords.controller;if(u>2){var g=n.lookupFactory(v)||h(n,d,o);a=g.create({model:o,parentController:b,target:b}),s.one("willDestroyElement",function(){a.destroy()})}else a=n.lookup(v)||p(n,d),a.setProperties({target:b,parentController:b});var y=r.contexts[1];y&&s.registerObserver(y,t,function(){a.set("model",m(y,t,r))}),r.hash.viewName=c(e);var _="template:"+e;r.hash.template=n.lookup(_),r.hash.controller=a,i&&!o&&i._connectActiveView(e,s),r.helperName=r.helperName||'render "'+e+'"',f.instanceHelper(this,s,r)}}),e("ember-routing-handlebars/helpers/shared",["ember-metal/property_get","ember-metal/array","ember-runtime/mixins/controller","ember-handlebars/ext","ember-metal/utils","exports"],function(e,t,r,n,i,a){"use strict";function s(e,t,r){var n=[];return"string"===v(e)&&n.push(""+e),n.push.apply(n,t),n.push({queryParams:r}),n}function o(e){var t=e.activeTransition?e.activeTransition.state.handlerInfos:e.state.handlerInfos;return t[t.length-1].name}function u(e,t,r){return p.call(c(e,t,r),function(n,i){return null===n?t[i]:d(e,n,r)})}function l(e,t){if(!t._namesStashed){for(var r=t[t.length-1].name,n=e.router.recognizer.handlersFor(r),i=null,a=0,s=t.length;s>a;++a){var o=t[a],u=n[a].names;u.length&&(i=o),o._names=u;var l=o.handler;l._stashNames(o,i)}t._namesStashed=!0}}function c(e,t,r){function n(e,t){return"controller"===t?t:m.detect(e)?n(h(e,"model"),t?t+".model":"model"):t}var i=f(e,t,r),a=r.types;return p.call(i,function(e,r){return"ID"===a[r]?n(e,t[r]):null})}var h=e.get,p=t.map,m=r["default"],f=n.resolveParams,d=n.handlebarsGet,v=i.typeOf,h=e.get;a.routeArgs=s,a.getActiveTargetName=o,a.resolveParams=u,a.stashParamNames=l,a.resolvePaths=c}),e("ember-routing",["ember-handlebars","ember-metal/core","ember-routing/ext/run_loop","ember-routing/ext/controller","ember-routing/ext/view","ember-routing/location/api","ember-routing/location/none_location","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/system/generate_controller","ember-routing/system/controller_for","ember-routing/system/dsl","ember-routing/system/router","ember-routing/system/route","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d){"use strict";var v=(e["default"],t["default"]),b=a["default"],g=s["default"],y=o["default"],_=u["default"],w=l["default"],x=c.generateControllerFactory,C=c["default"],O=h["default"],P=p["default"],E=m["default"],A=f["default"];v.Location=b,v.AutoLocation=w,v.HashLocation=y,v.HistoryLocation=_,v.NoneLocation=g,v.controllerFor=O,v.generateControllerFactory=x,v.generateController=C,v.RouterDSL=P,v.Router=E,v.Route=A,d["default"]=v}),e("ember-routing/ext/controller",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/merge","ember-metal/enumerable_utils","ember-runtime/mixins/controller","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(e,t){var r,n=e;"string"===f(n)&&(r={},r[n]={as:null},n=r);for(var i in n){if(!n.hasOwnProperty(i))return;var a=n[i];"string"===f(a)&&(a={as:a}),r=t[i]||{as:null,scope:"model"},v(r,a),t[i]=r}}function c(e){var t=h(e,"_normalizedQueryParams");for(var r in t)t.hasOwnProperty(r)&&e.addObserver(r+".[]",e,e._qpChanged)}var h=(e["default"],t.get),p=r.set,m=n.computed,f=i.typeOf,d=i.meta,v=a["default"],b=(s.map,o["default"]);b.reopen({concatenatedProperties:["queryParams","_pCacheMeta"],init:function(){this._super.apply(this,arguments),c(this)},queryParams:null,_qpDelegate:null,_normalizedQueryParams:m(function(){var e=d(this);if(e.proto!==this)return h(e.proto,"_normalizedQueryParams");var t=h(this,"queryParams");if(t._qpMap)return t._qpMap;for(var r=t._qpMap={},n=0,i=t.length;i>n;++n)l(t[n],r);return r}),_cacheMeta:m(function(){var e=d(this);if(e.proto!==this)return h(e.proto,"_cacheMeta");var t={},r=h(this,"_normalizedQueryParams");for(var n in r)if(r.hasOwnProperty(n)){var i,a=r[n],s=a.scope;"controller"===s&&(i=[]),t[n]={parts:i,values:null,scope:s,prefix:"",def:h(this,n)}}return t}),_updateCacheParams:function(e){var t=h(this,"_cacheMeta");for(var r in t)if(t.hasOwnProperty(r)){var n=t[r];n.values=e;var i=this._calculateCacheKey(n.prefix,n.parts,n.values),a=this._bucketCache;if(a){var s=a.lookup(i,r,n.def);p(this,r,s)}}},_qpChanged:function(e,t){var r=t.substr(0,t.length-3),n=h(e,"_cacheMeta"),i=n[r],a=e._calculateCacheKey(i.prefix||"",i.parts,i.values),s=h(e,r),o=this._bucketCache;o&&e._bucketCache.stash(a,r,s);var u=e._qpDelegate;u&&u(e,r)},_calculateCacheKey:function(e,t,r){for(var n=t||[],i="",a=0,s=n.length;s>a;++a){var o=n[a],u=h(r,o);i+="::"+o+":"+u}return e+i.replace(g,"-")},transitionToRoute:function(){var e=h(this,"target"),t=e.transitionToRoute||e.transitionTo;return t.apply(e,arguments)},transitionTo:function(){return this.transitionToRoute.apply(this,arguments)},replaceRoute:function(){var e=h(this,"target"),t=e.replaceRoute||e.replaceWith;return t.apply(e,arguments)},replaceWith:function(){return this.replaceRoute.apply(this,arguments)}});var g=/\./g;u["default"]=b}),e("ember-routing/ext/run_loop",["ember-metal/run_loop"],function(e){"use strict";{var t=e["default"];t.queues}t._addQueue("routerTransitions","actions")}),e("ember-routing/ext/view",["ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-views/views/view","exports"],function(e,t,r,n,i){"use strict";var a=e.get,s=t.set,o=r["default"],u=n["default"];u.reopen({init:function(){s(this,"_outlets",{}),this._super()},connectOutlet:function(e,t){if(this._pendingDisconnections&&delete this._pendingDisconnections[e],this._hasEquivalentView(e,t))return void t.destroy();var r=a(this,"_outlets"),n=a(this,"container"),i=n&&n.lookup("router:main"),o=a(t,"renderedName");s(r,e,t),i&&o&&i._connectActiveView(o,t)},_hasEquivalentView:function(e,t){var r=a(this,"_outlets."+e);return r&&r.constructor===t.constructor&&r.get("template")===t.get("template")&&r.get("context")===t.get("context")},disconnectOutlet:function(e){this._pendingDisconnections||(this._pendingDisconnections={}),this._pendingDisconnections[e]=!0,o.once(this,"_finishDisconnections")},_finishDisconnections:function(){if(!this.isDestroyed){var e=a(this,"_outlets"),t=this._pendingDisconnections;this._pendingDisconnections=null;for(var r in t)s(e,r,null)}}}),i["default"]=u}),e("ember-routing/location/api",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","exports"],function(e,t,r,n){"use strict";e["default"],t.get,r.set;n["default"]={create:function(e){var t=e&&e.implementation,r=this.implementations[t];return r.create.apply(r,arguments)},registerImplementation:function(e,t){this.implementations[e]=t},implementations:{},_location:window.location,_getHash:function(){var e=(this._location||this.location).href,t=e.indexOf("#");return-1===t?"":e.substr(t)}}}),e("ember-routing/location/auto_location",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-routing/location/api","ember-routing/location/history_location","ember-routing/location/hash_location","ember-routing/location/none_location","exports"],function(e,t,r,n,i,a,s,o){"use strict";var u=(e["default"],t.get,r.set),l=n["default"],c=i["default"],h=a["default"],p=s["default"];o["default"]={cancelRouterSetup:!1,rootURL:"/",_window:window,_location:window.location,_history:window.history,_HistoryLocation:c,_HashLocation:h,_NoneLocation:p,_getOrigin:function(){var e=this._location,t=e.origin;return t||(t=e.protocol+"//"+e.hostname,e.port&&(t+=":"+e.port)),t},_getSupportsHistory:function(){var e=this._window.navigator.userAgent;return-1!==e.indexOf("Android 2")&&-1!==e.indexOf("Mobile Safari")&&-1===e.indexOf("Chrome")?!1:!!(this._history&&"pushState"in this._history)},_getSupportsHashChange:function(){var e=this._window,t=e.document.documentMode;return"onhashchange"in e&&(void 0===t||t>7)},_replacePath:function(e){this._location.replace(this._getOrigin()+e)},_getRootURL:function(){return this.rootURL},_getPath:function(){var e=this._location.pathname;return"/"!==e.charAt(0)&&(e="/"+e),e},_getHash:l._getHash,_getQuery:function(){return this._location.search +},_getFullPath:function(){return this._getPath()+this._getQuery()+this._getHash()},_getHistoryPath:function(){{var e,t,r=this._getRootURL(),n=this._getPath(),i=this._getHash(),a=this._getQuery();n.indexOf(r)}return"#/"===i.substr(0,2)?(t=i.substr(1).split("#"),e=t.shift(),"/"===n.slice(-1)&&(e=e.substr(1)),n+=e,n+=a,t.length&&(n+="#"+t.join("#"))):(n+=a,n+=i),n},_getHashPath:function(){var e=this._getRootURL(),t=e,r=this._getHistoryPath(),n=r.substr(e.length);return""!==n&&("/"!==n.charAt(0)&&(n="/"+n),t+="#"+n),t},create:function(e){e&&e.rootURL&&(this.rootURL=e.rootURL);var t,r,n=!1,i=this._NoneLocation,a=this._getFullPath();this._getSupportsHistory()?(t=this._getHistoryPath(),a===t?i=this._HistoryLocation:"/#"===a.substr(0,2)?(this._history.replaceState({path:t},null,t),i=this._HistoryLocation):(n=!0,this._replacePath(t))):this._getSupportsHashChange()&&(r=this._getHashPath(),a===r||"/"===a&&"/#/"===r?i=this._HashLocation:(n=!0,this._replacePath(r)));var s=i.create.apply(i,arguments);return n&&u(s,"cancelRouterSetup",!0),s}}}),e("ember-routing/location/hash_location",["ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/object","ember-routing/location/api","ember-views/system/jquery","exports"],function(e,t,r,n,i,a,s,o){"use strict";var u=e.get,l=t.set,c=r["default"],h=n.guidFor,p=i["default"],m=a["default"],f=s["default"];o["default"]=p.extend({implementation:"hash",init:function(){l(this,"location",u(this,"_location")||window.location)},getHash:m._getHash,getURL:function(){return this.getHash().substr(1)},setURL:function(e){u(this,"location").hash=e,l(this,"lastSetURL",e)},replaceURL:function(e){u(this,"location").replace("#"+e),l(this,"lastSetURL",e)},onUpdateURL:function(e){var t=this,r=h(this);f(window).on("hashchange.ember-location-"+r,function(){c(function(){var r=t.getURL();u(t,"lastSetURL")!==r&&(l(t,"lastSetURL",null),e(r))})})},formatURL:function(e){return"#"+e},willDestroy:function(){var e=h(this);f(window).off("hashchange.ember-location-"+e)}})}),e("ember-routing/location/history_location",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-runtime/system/object","ember-views/system/jquery","exports"],function(e,t,r,n,i,a,s){"use strict";var o=(e["default"],t.get),u=r.set,l=n.guidFor,c=i["default"],h=a["default"],p=!1,m=window.history&&"state"in window.history;s["default"]=c.extend({implementation:"history",init:function(){u(this,"location",o(this,"location")||window.location),u(this,"baseURL",h("base").attr("href")||"")},initState:function(){u(this,"history",o(this,"history")||window.history),this.replaceState(this.formatURL(this.getURL()))},rootURL:"/",getURL:function(){var e=o(this,"rootURL"),t=o(this,"location"),r=t.pathname,n=o(this,"baseURL");e=e.replace(/\/$/,""),n=n.replace(/\/$/,"");var i=r.replace(n,"").replace(e,""),a=t.search||"";return i+=a},setURL:function(e){var t=this.getState();e=this.formatURL(e),t&&t.path===e||this.pushState(e)},replaceURL:function(e){var t=this.getState();e=this.formatURL(e),t&&t.path===e||this.replaceState(e)},getState:function(){return m?o(this,"history").state:this._historyState},pushState:function(e){var t={path:e};o(this,"history").pushState(t,null,e),m||(this._historyState=t),this._previousURL=this.getURL()},replaceState:function(e){var t={path:e};o(this,"history").replaceState(t,null,e),m||(this._historyState=t),this._previousURL=this.getURL()},onUpdateURL:function(e){var t=l(this),r=this;h(window).on("popstate.ember-location-"+t,function(){(p||(p=!0,r.getURL()!==r._previousURL))&&e(r.getURL())})},formatURL:function(e){var t=o(this,"rootURL"),r=o(this,"baseURL");return""!==e?(t=t.replace(/\/$/,""),r=r.replace(/\/$/,"")):r.match(/^\//)&&t.match(/^\//)&&(r=r.replace(/\/$/,"")),r+t+e},willDestroy:function(){var e=l(this);h(window).off("popstate.ember-location-"+e)}})}),e("ember-routing/location/none_location",["ember-metal/property_get","ember-metal/property_set","ember-runtime/system/object","exports"],function(e,t,r,n){"use strict";var i=e.get,a=t.set,s=r["default"];n["default"]=s.extend({implementation:"none",path:"",getURL:function(){return i(this,"path")},setURL:function(e){a(this,"path",e)},onUpdateURL:function(e){this.updateCallback=e},handleURL:function(e){a(this,"path",e),this.updateCallback(e)},formatURL:function(e){return e}})}),e("ember-routing/system/cache",["ember-runtime/system/object","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=r.extend({init:function(){this.cache={}},has:function(e){return e in this.cache},stash:function(e,t,r){var n=this.cache[e];n||(n=this.cache[e]={}),n[t]=r},lookup:function(e,t,r){var n=this.cache;if(!(e in n))return r;var i=n[e];return t in i?i[t]:r},cache:null})}),e("ember-routing/system/controller_for",["exports"],function(e){"use strict";e["default"]=function(e,t,r){return e.lookup("controller:"+t,r)}}),e("ember-routing/system/dsl",["ember-metal/core","exports"],function(e,t){"use strict";function r(e){this.parent=e,this.matches=[]}function n(e){return e.parent&&"application"!==e.parent}function i(e,t,r){r=r||{},"string"!=typeof r.path&&(r.path="/"+t),n(e)&&r.resetNamespace!==!0&&(t=e.parent+"."+t),e.push(r.path,t,null)}e["default"];t["default"]=r,r.prototype={route:function(e,t,a){2===arguments.length&&"function"==typeof t&&(a=t,t={}),1===arguments.length&&(t={});t.resetNamespace===!0?"resource":"route";if("string"!=typeof t.path&&(t.path="/"+e),n(this)&&t.resetNamespace!==!0&&(e=this.parent+"."+e),a){var s=new r(e);i(s,"loading"),i(s,"error",{path:"/_unused_dummy_error_path_route_"+e+"/:error"}),a&&a.call(s),this.push(t.path,e,s.generate())}else this.push(t.path,e,null)},push:function(e,t,r){var n=t.split(".");(""===e||"/"===e||"index"===n[n.length-1])&&(this.explicitIndex=!0),this.matches.push([e,t,r])},resource:function(e,t,r){2===arguments.length&&"function"==typeof t&&(r=t,t={}),1===arguments.length&&(t={}),t.resetNamespace=!0,this.route(e,t,r)},generate:function(){var e=this.matches;return this.explicitIndex||i(this,"index",{path:"/"}),function(t){for(var r=0,n=e.length;n>r;r++){var i=e[r];t(i[0]).to(i[1],i[2])}}}},r.map=function(e){var t=new r;return e.call(t),t}}),e("ember-routing/system/generate_controller",["ember-metal/core","ember-metal/property_get","ember-metal/utils","exports"],function(e,t,r,n){"use strict";function i(e,t,r){var n,i,a,o;return o=r&&s(r)?"array":r?"object":"basic",a="controller:"+o,n=e.lookupFactory(a).extend({isGenerated:!0,toString:function(){return"(generated "+t+" controller)"}}),i="controller:"+t,e.register(i,n),n}var a=(e["default"],t.get),s=r.isArray;n.generateControllerFactory=i,n["default"]=function(e,t,r){i(e,t,r);var n="controller:"+t,s=e.lookup(n);return a(s,"namespace.LOG_ACTIVE_GENERATION"),s}}),e("ember-routing/system/route",["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/get_properties","ember-metal/enumerable_utils","ember-metal/is_none","ember-metal/computed","ember-metal/merge","ember-metal/utils","ember-metal/run_loop","ember-metal/keys","ember-runtime/copy","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/mixins/action_handler","ember-routing/system/generate_controller","ember-routing-handlebars/helpers/shared","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,g){"use strict";function y(e){var t=_(e,e.router.router.state.handlerInfos,-1);return t&&t.handler}function _(e,t,r){if(t)for(var n,i=r||0,a=0,s=t.length;s>a;a++)if(n=t[a].handler,n===e)return t[a+i]}function w(e){var t,r=y(e);if(r)return(t=r.lastRenderedTemplate)?t:w(r)}function x(e,t,r,n){n=n||{},n.into=n.into?n.into.replace(/\//g,"."):w(e),n.outlet=n.outlet||"main",n.name=t,n.template=r,n.LOG_VIEW_LOOKUPS=k(e.router,"namespace.LOG_VIEW_LOOKUPS");var i=n.controller,a=n.model;if(i=n.controller?n.controller:n.namePassed?e.container.lookup("controller:"+t)||e.controllerName||e.routeName:e.controllerName||e.container.lookup("controller:"+t),"string"==typeof i){var s=i;if(i=e.container.lookup("controller:"+s),!i)throw new V("You passed `controller: '"+s+"'` into the `render` method, but no such controller could be found.")}return a&&i.set("model",a),n.controller=i,n}function C(e,t,r){if(e)r.LOG_VIEW_LOOKUPS;else{var n=r.into?"view:default":"view:toplevel";e=t.lookup(n),r.LOG_VIEW_LOOKUPS}return k(e,"templateName")||(I(e,"template",r.template),I(e,"_debugTemplateName",r.name)),I(e,"renderedName",r.name),I(e,"controller",r.controller),e}function O(e,t,r){if(r.into){var n=e.router._lookupActiveView(r.into),i=E(n,r.outlet);e.teardownOutletViews||(e.teardownOutletViews=[]),R(e.teardownOutletViews,0,0,[i]),n.connectOutlet(r.outlet,t)}else{var a=k(e,"router.namespace.rootElement");e.teardownTopLevelView&&e.teardownTopLevelView(),e.router._connectActiveView(r.name,t),e.teardownTopLevelView=P(t),t.appendTo(a)}}function P(e){return function(){e.destroy()}}function E(e,t){return function(){e.disconnectOutlet(t)}}function A(e,t){if(t.fullQueryParams)return t.fullQueryParams;t.fullQueryParams={},L(t.fullQueryParams,t.queryParams);var r=t.handlerInfos[t.handlerInfos.length-1].name;return e._deserializeQueryParams(r,t.fullQueryParams),t.fullQueryParams}function T(e,t){t.queryParamsFor=t.queryParamsFor||{};var r=e.routeName;if(t.queryParamsFor[r])return t.queryParamsFor[r];for(var n=A(e.router,t),i=t.queryParamsFor[r]={},a=k(e,"_qp"),s=a.qps,o=0,u=s.length;u>o;++o){var l=s[o],c=l.prop in n;i[l.prop]=c?n[l.prop]:N(l.def)}return i}function N(e){return H(e)?S.A(e.slice()):e}var S=e["default"],V=t["default"],k=r.get,I=n.set,j=i["default"],D=a.forEach,R=a.replace,M=(s.isNone,o.computed),L=u["default"],H=l.isArray,z=l.typeOf,q=c["default"],F=h["default"],B=p["default"],U=(m.classify,m.fmt,f["default"]),K=d["default"],W=v["default"],G=b.stashParamNames,Q=U.extend(K,{queryParams:{},_qp:M(function(){var e=this.controllerName||this.routeName,t=this.container.lookupFactory("controller:"+e);if(!t)return $;var r=t.proto(),n=k(r,"_normalizedQueryParams"),i=k(r,"_cacheMeta"),a=[],s={},o=this;for(var u in n)if(n.hasOwnProperty(u)){var l=n[u],c=l.as||this.serializeQueryParamKey(u),h=k(r,u);H(h)&&(h=S.A(h.slice()));var p=z(h),m=this.serializeQueryParam(h,c,p),f=e+":"+u,d={def:h,sdef:m,type:p,urlKey:c,prop:u,fprop:f,ctrl:e,cProto:r,svalue:m,cacheType:l.scope,route:this,cacheMeta:i[u]};s[u]=s[c]=s[f]=d,a.push(d)}return{qps:a,map:s,states:{active:function(e,t){return o._activeQPChanged(e,s[t])},allowOverrides:function(e,t){return o._updatingQPChanged(e,s[t])},changingKeys:function(e,t){return o._updateSerializedQPValue(e,s[t])}}}}),_names:null,_stashNames:function(e,t){var r=e;if(!this._names){var n=this._names=r._names;n.length||(r=t,n=r&&r._names||[]);for(var i=k(this,"_qp.qps"),a=i.length,s=new Array(n.length),o=0,u=n.length;u>o;++o)s[o]=r.name+"."+n[o];for(var l=0;a>l;++l){var c=i[l],h=c.cacheMeta;"model"===h.scope&&(h.parts=s),h.prefix=c.ctrl}}},_updateSerializedQPValue:function(e,t){var r=k(e,t.prop);t.svalue=this.serializeQueryParam(r,t.urlKey,t.type)},_activeQPChanged:function(e,t){var r=k(e,t.prop);this.router._queuedQPChanges[t.fprop]=r,q.once(this,this._fireQueryParamTransition)},_updatingQPChanged:function(e,t){var r=this.router;r._qpUpdates||(r._qpUpdates={}),r._qpUpdates[t.urlKey]=!0},mergedProperties:["events","queryParams"],paramsFor:function(e){var t=this.container.lookup("route:"+e);if(!t)return{};var r=this.router.router.activeTransition,n=r?r.state:this.router.router.state,i={};return L(i,n.params[e]),L(i,T(t,n)),i},serializeQueryParamKey:function(e){return e},serializeQueryParam:function(e,t,r){return"array"===r?JSON.stringify(e):""+e},deserializeQueryParam:function(e,t,r){return"boolean"===r?"true"===e?!0:!1:"number"===r?Number(e).valueOf():"array"===r?S.A(JSON.parse(e)):e},_fireQueryParamTransition:function(){this.transitionTo({queryParams:this.router._queuedQPChanges}),this.router._queuedQPChanges={}},resetController:S.K,exit:function(){this.deactivate(),this.teardownViews()},_reset:function(e,t){var r=this.controller;r._qpDelegate=k(this,"_qp.states.inactive"),this.resetController(r,e,t)},enter:function(){this.activate()},viewName:null,templateName:null,controllerName:null,_actions:{queryParamsDidChange:function(e,t,r){for(var n=F(e).concat(F(r)),i=0,a=n.length;a>i;++i){var s=n[i],o=k(this.queryParams,s)||{};k(o,"refreshModel")&&this.refresh()}return!0},finalizeQueryParamChange:function(e,t,r){if("application"!==this.routeName)return!0;if(r){var n,i=r.state.handlerInfos,a=this.router,s=a._queryParamsFor(i[i.length-1].name),o=a._qpUpdates;G(a,i);for(var u=0,l=s.qps.length;l>u;++u){var c,h,p=s.qps[u],m=p.route,f=m.controller,d=p.urlKey in e&&p.urlKey;o&&p.urlKey in o?(c=k(f,p.prop),h=m.serializeQueryParam(c,p.urlKey,p.type)):d?(h=e[d],c=m.deserializeQueryParam(h,p.urlKey,p.type)):(h=p.sdef,c=N(p.def)),f._qpDelegate=k(this,"_qp.states.inactive");var v=h!==p.svalue;if(v){var b=k(m,"queryParams."+p.urlKey)||{};if(r.queryParamsOnly&&n!==!1){var g=k(b,"replace");g?n=!0:g===!1&&(n=!1)}I(f,p.prop,c)}p.svalue=h;var y=p.sdef===h;y||t.push({value:h,visible:!0,key:d||p.urlKey})}n&&r.method("replace"),D(s.qps,function(e){var t=k(e.route,"_qp"),r=e.route.controller;r._qpDelegate=k(t,"states.active")}),a._qpUpdates=null}}},events:null,deactivate:S.K,activate:S.K,transitionTo:function(){var e=this.router;return e.transitionTo.apply(e,arguments)},intermediateTransitionTo:function(){var e=this.router;e.intermediateTransitionTo.apply(e,arguments)},refresh:function(){return this.router.router.refresh(this)},replaceWith:function(){var e=this.router;return e.replaceWith.apply(e,arguments)},send:function(){return this.router.send.apply(this.router,arguments)},setup:function(e,t){var r=this.controllerName||this.routeName,n=this.controllerFor(r,!0);if(n||(n=this.generateController(r,e)),this.controller=n,this.setupControllers)this.setupControllers(n,e);else{var i=k(this,"_qp.states");if(t&&(G(this.router,t.state.handlerInfos),n._qpDelegate=i.changingKeys,n._updateCacheParams(t.params)),n._qpDelegate=i.allowOverrides,t){var a=T(this,t.state);n.setProperties(a)}this.setupController(n,e,t)}this.renderTemplates?this.renderTemplates(e):this.renderTemplate(n,e)},beforeModel:S.K,afterModel:S.K,redirect:S.K,contextDidChange:function(){this.currentModel=this.context},model:function(e,t){var r,n,i,a,s=k(this,"_qp.map");for(var o in e)"queryParams"===o||s&&o in s||((r=o.match(/^(.*)_id$/))&&(n=r[1],a=e[o]),i=!0);if(!n&&i)return B(e);if(!n){if(t.resolveIndex<1)return;var u=t.state.handlerInfos[t.resolveIndex-1].context;return u}return this.findModel(n,a)},deserialize:function(e,t){return this.model(this.paramsFor(this.routeName),t)},findModel:function(){var e=k(this,"store");return e.find.apply(e,arguments)},store:M(function(){{var e=this.container;this.routeName,k(this,"router.namespace")}return{find:function(t,r){var n=e.lookupFactory("model:"+t);if(n)return n.find(r)}}}),serialize:function(e,t){if(!(t.length<1)&&e){var r=t[0],n={};return/_id$/.test(r)&&1===t.length?n[r]=k(e,"id"):n=j(e,t),n}},setupController:function(e,t){e&&void 0!==t&&I(e,"model",t)},controllerFor:function(e){var t,r=this.container,n=r.lookup("route:"+e);return n&&n.controllerName&&(e=n.controllerName),t=r.lookup("controller:"+e)},generateController:function(e,t){var r=this.container;return t=t||this.modelFor(e),W(r,e,t)},modelFor:function(e){var t=this.container.lookup("route:"+e),r=this.router?this.router.router.activeTransition:null;if(r){var n=t&&t.routeName||e;if(r.resolvedModels.hasOwnProperty(n))return r.resolvedModels[n]}return t&&t.currentModel},renderTemplate:function(){this.render()},render:function(e,t){var r="string"==typeof e&&!!e;"object"!=typeof e||t||(t=e,e=this.routeName),t=t||{},t.namePassed=r;var n;e?(e=e.replace(/\//g,"."),n=e):(e=this.routeName,n=this.templateName||e);var i=t.view||r&&e||this.viewName||e,a=this.container,s=a.lookup("view:"+i),o=s?s.get("template"):null;return o||(o=a.lookup("template:"+n)),s||o?(t=x(this,e,o,t),s=C(s,a,t),"main"===t.outlet&&(this.lastRenderedTemplate=e),void O(this,s,t)):void k(this.router,"namespace.LOG_VIEW_LOOKUPS")},disconnectOutlet:function(e){if(!e||"string"==typeof e){var t=e;e={},e.outlet=t}e.parentView=e.parentView?e.parentView.replace(/\//g,"."):w(this),e.outlet=e.outlet||"main";var r=this.router._lookupActiveView(e.parentView);r&&r.disconnectOutlet(e.outlet)},willDestroy:function(){this.teardownViews()},teardownViews:function(){this.teardownTopLevelView&&this.teardownTopLevelView();var e=this.teardownOutletViews||[];D(e,function(e){e()}),delete this.teardownTopLevelView,delete this.teardownOutletViews,delete this.lastRenderedTemplate}}),$={qps:[],map:{},states:{}};g["default"]=Q}),e("ember-routing/system/router",["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/properties","ember-metal/computed","ember-metal/merge","ember-metal/run_loop","ember-metal/enumerable_utils","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/mixins/evented","ember-routing/system/dsl","ember-views/views/view","ember-routing/location/api","ember-handlebars/views/metamorph_view","ember-routing-handlebars/helpers/shared","exports"],function(e,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,g){"use strict";function y(e,t,r){for(var n,i,a=t.state.handlerInfos,s=!1,o=a.length-1;o>=0;--o)if(n=a[o],i=n.handler,s){if(r(i,a[o+1].handler)!==!0)return!1}else e===i&&(s=!0);return!0}function _(e,t){var r=[];t&&r.push(t),e&&(e.message&&r.push(e.message),e.stack&&r.push(e.stack),"string"==typeof e&&r.push(e)),N.Logger.error.apply(this,r)}function w(e,t,r){var n,i=e.router,a=(t.routeName.split(".").pop(),"application"===e.routeName?"":e.routeName+".");return n=a+r,x(i,n)?n:void 0}function x(e,t){var r=e.container;return e.hasRoute(t)&&(r.has("template:"+t)||r.has("route:"+t))}function C(e,t,r){var n=r.shift();if(!e){if(t)return;throw new S("Can't trigger action '"+n+"' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call `.send()` on the `Transition` object passed to the `model/beforeModel/afterModel` hooks.")}for(var i,a,s=!1,o=e.length-1;o>=0;o--)if(i=e[o],a=i.handler,a._actions&&a._actions[n]){if(a._actions[n].apply(a,r)!==!0)return;s=!0}if($[n])return void $[n].apply(null,r);if(!s&&!t)throw new S("Nothing handled the action '"+n+"'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble.")}function O(e,t,r){for(var n=e.router,i=n.applyIntent(t,r),a=i.handlerInfos,s=i.params,o=0,u=a.length;u>o;++o){var l=a[o];l.isResolved||(l=l.becomeResolved(null,l.context)),s[l.name]=l.params}return i}function P(e){var t=e.container.lookup("controller:application");if(t){var r=e.router.currentHandlerInfos,n=Q._routePath(r);"currentPath"in t||I(t,"currentPath"),k(t,"currentPath",n),"currentRouteName"in t||I(t,"currentRouteName"),k(t,"currentRouteName",r[r.length-1].name)}}function E(e){e.then(null,function(e){return e&&e.name?("UnrecognizedURLError"===e.name,e):void 0},"Ember: Process errors from Router")}function A(e){return"string"==typeof e&&(""===e||"/"===e.charAt(0))}function T(e,t,r,n){{var i=e._queryParamsFor(t);i.qps}for(var a in r)if(r.hasOwnProperty(a)){var s=r[a],o=i.map[a];o&&n(a,s,o)}}var N=e["default"],S=r["default"],V=n.get,k=i.set,I=a.defineProperty,j=s.computed,D=o["default"],R=u["default"],M=(l.forEach,c.fmt,h["default"]),L=p["default"],H=m["default"],z=f["default"],q=d["default"],F=v["default"],B=b.routeArgs,U=b.getActiveTargetName,K=b.stashParamNames,W=t("router")["default"],G=(t("router/transition").Transition,[].slice),Q=M.extend(L,{location:"hash",rootURL:"/",init:function(){this.router=this.constructor.router||this.constructor.map(N.K),this._activeViews={},this._setupLocation(),this._qpCache={},this._queuedQPChanges={},V(this,"namespace.LOG_TRANSITIONS_INTERNAL")&&(this.router.log=N.Logger.debug)},url:j(function(){return V(this,"location").getURL()}),startRouting:function(){this.router=this.router||this.constructor.map(N.K);var e=this.router,t=V(this,"location"),r=this.container,n=this,i=V(this,"initialURL");V(t,"cancelRouterSetup")||(this._setupRouter(e,t),r.register("view:default",F),r.register("view:toplevel",z.extend()),t.onUpdateURL(function(e){n.handleURL(e)}),"undefined"==typeof i&&(i=t.getURL()),this.handleURL(i))},didTransition:function(e){P(this),this._cancelLoadingEvent(),this.notifyPropertyChange("url"),R.once(this,this.trigger,"didTransition"),V(this,"namespace").LOG_TRANSITIONS&&N.Logger.log("Transitioned into '"+Q._routePath(e)+"'")},handleURL:function(e){return this._doURLTransition("handleURL",e)},_doURLTransition:function(e,t){var r=this.router[e](t||"/");return E(r),r},transitionTo:function(){var e,t=G.call(arguments);if(A(t[0]))return this._doURLTransition("transitionTo",t[0]);var r=t[t.length-1];e=r&&r.hasOwnProperty("queryParams")?t.pop().queryParams:{};var n=t.shift();return this._doTransition(n,t,e)},intermediateTransitionTo:function(){this.router.intermediateTransitionTo.apply(this.router,arguments),P(this);var e=this.router.currentHandlerInfos;V(this,"namespace").LOG_TRANSITIONS&&N.Logger.log("Intermediate-transitioned into '"+Q._routePath(e)+"'")},replaceWith:function(){return this.transitionTo.apply(this,arguments).method("replace")},generate:function(){var e=this.router.generate.apply(this.router,arguments);return this.location.formatURL(e)},isActive:function(){var e=this.router;return e.isActive.apply(e,arguments)},isActiveIntent:function(){var e=this.router;return e.isActive.apply(e,arguments)},send:function(){this.router.trigger.apply(this.router,arguments)},hasRoute:function(e){return this.router.hasRoute(e)},reset:function(){this.router.reset()},_lookupActiveView:function(e){var t=this._activeViews[e];return t&&t[0]},_connectActiveView:function(e,t){function r(){delete this._activeViews[e]}var n=this._activeViews[e];n&&n[0].off("willDestroyElement",this,n[1]),this._activeViews[e]=[t,r],t.one("willDestroyElement",this,r)},_setupLocation:function(){var e=V(this,"location"),t=V(this,"rootURL");if(t&&this.container&&!this.container.has("-location-setting:root-url")&&this.container.register("-location-setting:root-url",t,{instantiate:!1}),"string"==typeof e&&this.container){var r=this.container.lookup("location:"+e);if("undefined"!=typeof r)e=k(this,"location",r);else{var n={implementation:e};e=k(this,"location",q.create(n))}}null!==e&&"object"==typeof e&&(t&&"string"==typeof t&&(e.rootURL=t),"function"==typeof e.initState&&e.initState())},_getHandlerFunction:function(){var e={},t=this.container,r=t.lookupFactory("route:basic"),n=this;return function(i){var a="route:"+i,s=t.lookup(a);return e[i]?s:(e[i]=!0,s||(t.register(a,r.extend()),s=t.lookup(a),V(n,"namespace.LOG_ACTIVE_GENERATION")),s.routeName=i,s)}},_setupRouter:function(e,t){var r,n=this;e.getHandler=this._getHandlerFunction();var i=function(){t.setURL(r)};if(e.updateURL=function(e){r=e,R.once(i)},t.replaceURL){var a=function(){t.replaceURL(r)};e.replaceURL=function(e){r=e,R.once(a)}}e.didTransition=function(e){n.didTransition(e)}},_serializeQueryParams:function(e,t){var r={};T(this,e,t,function(e,n,i){var a=i.urlKey;r[a]||(r[a]=[]),r[a].push({qp:i,value:n}),delete t[e]});for(var n in r){var i=r[n];if(i.length>1){i[0].qp,i[1].qp}var a=i[0].qp;t[a.urlKey]=a.route.serializeQueryParam(i[0].value,a.urlKey,a.type)}},_deserializeQueryParams:function(e,t){T(this,e,t,function(e,r,n){delete t[e],t[n.prop]=n.route.deserializeQueryParam(r,n.urlKey,n.type)})},_pruneDefaultQueryParamValues:function(e,t){var r=this._queryParamsFor(e);for(var n in t){var i=r.map[n];i&&i.sdef===t[n]&&delete t[n]}},_doTransition:function(e,t,r){var n=e||U(this.router),i={};D(i,r),this._prepareQueryParams(n,t,i);var a=B(n,t,i),s=this.router.transitionTo.apply(this.router,a);return E(s),s},_prepareQueryParams:function(e,t,r){this._hydrateUnsuppliedQueryParams(e,t,r),this._serializeQueryParams(e,r),this._pruneDefaultQueryParamValues(e,r)},_queryParamsFor:function(e){if(this._qpCache[e])return this._qpCache[e];for(var t={},r=[],n=(this._qpCache[e]={map:t,qps:r},this.router),i=n.recognizer.handlersFor(e),a=0,s=i.length;s>a;++a){var o=i[a],u=n.getHandler(o.handler),l=V(u,"_qp");l&&(D(t,l.map),r.push.apply(r,l.qps))}return{qps:r,map:t}},_hydrateUnsuppliedQueryParams:function(e,t,r){var n=O(this,e,t),i=n.handlerInfos,a=this._bucketCache;K(this,i);for(var s=0,o=i.length;o>s;++s)for(var u=i[s].handler,l=V(u,"_qp"),c=0,h=l.qps.length;h>c;++c){var p=l.qps[c],m=p.prop in r&&p.prop||p.fprop in r&&p.fprop;if(m)m!==p.fprop&&(r[p.fprop]=r[m],delete r[m]);else{var f=p.cProto,d=V(f,"_cacheMeta"),v=f._calculateCacheKey(p.ctrl,d[p.prop].parts,n.params);r[p.fprop]=a.lookup(v,p.prop,p.def)}}},_scheduleLoadingEvent:function(e,t){this._cancelLoadingEvent(),this._loadingStateTimer=R.scheduleOnce("routerTransitions",this,"_fireLoadingEvent",e,t)},_fireLoadingEvent:function(e,t){this.router.activeTransition&&e.trigger(!0,"loading",e,t)},_cancelLoadingEvent:function(){this._loadingStateTimer&&R.cancel(this._loadingStateTimer),this._loadingStateTimer=null}}),$={willResolveModel:function(e,t){t.router._scheduleLoadingEvent(e,t)},error:function(e,t,r){var n=r.router,i=y(r,t,function(t,r){var i=w(t,r,"error");return i?void n.intermediateTransitionTo(i,e):!0});return i&&x(r.router,"application_error")?void n.intermediateTransitionTo("application_error",e):void _(e,"Error while processing route: "+t.targetName)},loading:function(e,t){var r=t.router,n=y(t,e,function(t,n){var i=w(t,n,"loading");return i?void r.intermediateTransitionTo(i):e.pivotHandler!==t?!0:void 0});return n&&x(t.router,"application_loading")?void r.intermediateTransitionTo("application_loading"):void 0}};Q.reopenClass({router:null,map:function(e){var t=this.router;t||(t=new W,t._triggerWillChangeContext=N.K,t._triggerWillLeave=N.K,t.callbacks=[],t.triggerEvent=C,this.reopenClass({router:t}));var r=H.map(function(){this.resource("application",{path:"/"},function(){for(var r=0;rr;++r)if(e[r]!==t[r])return!1;return!0}for(var r,n,i,a=[],s=1,o=e.length;o>s;s++){for(r=e[s].name,n=r.split("."),i=G.call(a);i.length&&!t(i,n);)i.shift();a.push.apply(a,n.slice(i.length))}return a.join(".")}}),g["default"]=Q}),e("ember-runtime",["ember-metal","ember-runtime/core","ember-runtime/compare","ember-runtime/copy","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/tracked_array","ember-runtime/system/subarray","ember-runtime/system/container","ember-runtime/system/application","ember-runtime/system/array_proxy","ember-runtime/system/object_proxy","ember-runtime/system/core_object","ember-runtime/system/each_proxy","ember-runtime/system/native_array","ember-runtime/system/set","ember-runtime/system/string","ember-runtime/system/deferred","ember-runtime/system/lazy_load","ember-runtime/mixins/array","ember-runtime/mixins/comparable","ember-runtime/mixins/copyable","ember-runtime/mixins/enumerable","ember-runtime/mixins/freezable","ember-runtime/mixins/-proxy","ember-runtime/mixins/observable","ember-runtime/mixins/action_handler","ember-runtime/mixins/deferred","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/mutable_array","ember-runtime/mixins/target_action_support","ember-runtime/mixins/evented","ember-runtime/mixins/promise_proxy","ember-runtime/mixins/sortable","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/computed/reduce_computed_macros","ember-runtime/controllers/array_controller","ember-runtime/controllers/object_controller","ember-runtime/controllers/controller","ember-runtime/mixins/controller","ember-runtime/ext/rsvp","ember-runtime/ext/string","ember-runtime/ext/function","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,g,y,_,w,x,C,O,P,E,A,T,N,S,V,k,I,j,D,R,M,L,H,z,q,F,B,U){"use strict";var K=e["default"],W=t.isEqual,G=r["default"],Q=n["default"],$=i["default"],Y=a["default"],J=s["default"],Z=o["default"],X=u["default"],et=(l["default"],c["default"]),tt=h["default"],rt=p["default"],nt=m.EachArray,it=m.EachProxy,at=f["default"],st=d["default"],ot=v["default"],ut=b["default"],lt=g.onLoad,ct=g.runLoadHooks,ht=y["default"],pt=_["default"],mt=w["default"],ft=x["default"],dt=C.Freezable,vt=C.FROZEN_ERROR,bt=O["default"],gt=P["default"],yt=E["default"],_t=A["default"],wt=T["default"],xt=N["default"],Ct=S["default"],Ot=V["default"],Pt=k["default"],Et=I["default"],At=j.arrayComputed,Tt=j.ArrayComputedProperty,Nt=D.reduceComputed,St=D.ReduceComputedProperty,Vt=R.sum,kt=R.min,It=R.max,jt=R.map,Dt=R.sort,Rt=R.setDiff,Mt=R.mapBy,Lt=R.mapProperty,Ht=R.filter,zt=R.filterBy,qt=R.filterProperty,Ft=R.uniq,Bt=R.union,Ut=R.intersect,Kt=M["default"],Wt=L["default"],Gt=H["default"],Qt=z["default"],$t=q["default"];K.compare=G,K.copy=Q,K.isEqual=W,K.Array=ht,K.Comparable=pt,K.Copyable=mt,K.SortableMixin=Et,K.Freezable=dt,K.FROZEN_ERROR=vt,K.DeferredMixin=_t,K.MutableEnumerable=wt,K.MutableArray=xt,K.TargetActionSupport=Ct,K.Evented=Ot,K.PromiseProxyMixin=Pt,K.Observable=gt,K.arrayComputed=At,K.ArrayComputedProperty=Tt,K.reduceComputed=Nt,K.ReduceComputedProperty=St;var Yt=K.computed;Yt.sum=Vt,Yt.min=kt,Yt.max=It,Yt.map=jt,Yt.sort=Dt,Yt.setDiff=Rt,Yt.mapBy=Mt,Yt.mapProperty=Lt,Yt.filter=Ht,Yt.filterBy=zt,Yt.filterProperty=qt,Yt.uniq=Ft,Yt.union=Bt,Yt.intersect=Ut,K.String=ot,K.Object=Y,K.TrackedArray=J,K.SubArray=Z,K.Container=X,K.Namespace=$,K.Enumerable=ft,K.ArrayProxy=et,K.ObjectProxy=tt,K.ActionHandler=yt,K.CoreObject=rt,K.EachArray=nt,K.EachProxy=it,K.NativeArray=at,K.Set=st,K.Deferred=ut,K.onLoad=lt,K.runLoadHooks=ct,K.ArrayController=Kt,K.ObjectController=Wt,K.Controller=Gt,K.ControllerMixin=Qt,K._ProxyMixin=bt,K.RSVP=$t,U["default"]=K}),e("ember-runtime/compare",["ember-metal/utils","ember-runtime/mixins/comparable","exports"],function(e,t,r){"use strict";function n(e,t){var r=e-t;return(r>0)-(0>r)}var i=e.typeOf,a=t["default"],s={undefined:0,"null":1,"boolean":2,number:3,string:4,array:5,object:6,instance:7,"function":8,"class":9,date:10};r["default"]=function o(e,t){if(e===t)return 0;var r=i(e),u=i(t);if(a){if("instance"===r&&a.detect(e.constructor))return e.constructor.compare(e,t);if("instance"===u&&a.detect(t.constructor))return 1-t.constructor.compare(t,e)}var l=n(s[r],s[u]);if(0!==l)return l;switch(r){case"boolean":case"number":return n(e,t);case"string":return n(e.localeCompare(t),0);case"array":for(var c=e.length,h=t.length,p=Math.min(c,h),m=0;p>m;m++){var f=o(e[m],t[m]);if(0!==f)return f}return n(c,h);case"instance":return a&&a.detect(e)?e.compare(e,t):0;case"date":return n(e.getTime(),t.getTime());default:return 0}}}),e("ember-runtime/computed/array_computed",["ember-metal/core","ember-runtime/computed/reduce_computed","ember-metal/enumerable_utils","ember-metal/platform","ember-metal/observer","ember-metal/error","exports"],function(e,t,r,n,i,a,s){"use strict";function o(){var e=this;return c.apply(this,arguments),this.func=function(t){return function(r){return e._hasInstanceMeta(this,r)||h(e._dependentKeys,function(t){m(this,t,function(){e.recomputeOnce.call(this,r)})},this),t.apply(this,arguments)}}(this.func),this}function u(e){var t;if(arguments.length>1&&(t=d.call(arguments,0,-1),e=d.call(arguments,-1)[0]),"object"!=typeof e)throw new f("Array Computed Property declared without an options hash");var r=new o(e);return t&&r.property.apply(r,t),r}var l=e["default"],c=(t.reduceComputed,t.ReduceComputedProperty),h=r.forEach,p=n.create,m=i.addObserver,f=a["default"],d=[].slice;o.prototype=p(c.prototype),o.prototype.initialValue=function(){return l.A()},o.prototype.resetValue=function(e){return e.clear(),e},o.prototype.didChange=function(){},s.arrayComputed=u,s.ArrayComputedProperty=o}),e("ember-runtime/computed/reduce_computed",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/property_events","ember-metal/expand_properties","ember-metal/observer","ember-metal/computed","ember-metal/platform","ember-metal/enumerable_utils","ember-runtime/system/tracked_array","ember-runtime/mixins/array","ember-metal/run_loop","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f){"use strict"; +function d(e,t){return"@this"===t?e:T(e,t)}function v(e,t,r){this.callbacks=e,this.cp=t,this.instanceMeta=r,this.dependentKeysByGuid={},this.trackedArraysByGuid={},this.suspended=!1,this.changedItems={},this.changedItemCount=0}function b(e,t,r){this.dependentArray=e,this.index=t,this.item=e.objectAt(t),this.trackedArray=r,this.beforeObserver=null,this.observer=null,this.destroyed=!1}function g(e,t,r){return 0>e?Math.max(0,t+e):t>e?e:Math.min(t-r,e)}function y(e,t,r){return Math.min(r,t-e)}function _(e,t,r,n,i,a,s){this.arrayChanged=e,this.index=r,this.item=t,this.propertyName=n,this.property=i,this.changedCount=a,s&&(this.previousValues=s)}function w(e,t,r,n,i){F(e,function(a,s){i.setValue(t.addedItem.call(this,i.getValue(),a,new _(e,a,s,n,r,e.length),i.sugarMeta))},this)}function x(e,t){var r=(e._callbacks(),e._hasInstanceMeta(this,t)),n=e._instanceMeta(this,t);r&&n.setValue(e.resetValue(n.getValue())),e.options.initialize&&e.options.initialize.call(this,n.getValue(),{property:e,propertyName:t},n.sugarMeta)}function C(e,t){if(Z.test(t))return!1;var r=d(e,t);return U.detect(r)}function O(e,t,r){this.context=e,this.propertyName=t,this.cache=S(e).cache,this.dependentArrays={},this.sugarMeta={},this.initialValue=r}function P(e){var t=this;this.options=e,this._dependentKeys=null,this._itemPropertyKeys={},this._previousItemPropertyKeys={},this.readOnly(),this.cacheable(),this.recomputeOnce=function(e){K.once(this,r,e)};var r=function(e){var r=(t._dependentKeys,t._instanceMeta(this,e)),n=t._callbacks();x.call(this,t,e),r.dependentArraysObserver.suspendArrayObservers(function(){F(t._dependentKeys,function(e){if(C(this,e)){var n=d(this,e),i=r.dependentArrays[e];n===i?t._previousItemPropertyKeys[e]&&(delete t._previousItemPropertyKeys[e],r.dependentArraysObserver.setupPropertyObservers(e,t._itemPropertyKeys[e])):(r.dependentArrays[e]=n,i&&r.dependentArraysObserver.teardownObservers(i,e),n&&r.dependentArraysObserver.setupObservers(n,e))}},this)},this),F(t._dependentKeys,function(i){if(C(this,i)){var a=d(this,i);a&&w.call(this,a,n,t,e,r)}},this)};this.func=function(e){return r.call(this,e),t._instanceMeta(this,e).getValue()}}function E(e){return e}function A(e){var t;if(arguments.length>1&&(t=$.call(arguments,0,-1),e=$.call(arguments,-1)[0]),"object"!=typeof e)throw new V("Reduce Computed Property declared without an options hash");if(!("initialValue"in e))throw new V("Reduce Computed Property declared without an initial value");var r=new P(e);return t&&r.property.apply(r,t),r}var T=(e["default"],t.get),N=(r.set,n.guidFor),S=n.meta,V=i["default"],k=a.propertyWillChange,I=a.propertyDidChange,j=s["default"],D=o.addObserver,R=(o.observersFor,o.removeObserver),M=o.addBeforeObserver,L=o.removeBeforeObserver,H=u.ComputedProperty,z=u.cacheFor,q=l.create,F=c.forEach,B=h["default"],U=p["default"],K=m["default"],W=(n.isArray,z.set),G=z.get,Q=z.remove,$=[].slice,Y=/^(.*)\.@each\.(.*)/,J=/(.*\.@each){2,}/,Z=/\.\[\]$/;v.prototype={setValue:function(e){this.instanceMeta.setValue(e,!0)},getValue:function(){return this.instanceMeta.getValue()},setupObservers:function(e,t){this.dependentKeysByGuid[N(e)]=t,e.addArrayObserver(this,{willChange:"dependentArrayWillChange",didChange:"dependentArrayDidChange"}),this.cp._itemPropertyKeys[t]&&this.setupPropertyObservers(t,this.cp._itemPropertyKeys[t])},teardownObservers:function(e,t){var r=this.cp._itemPropertyKeys[t]||[];delete this.dependentKeysByGuid[N(e)],this.teardownPropertyObservers(t,r),e.removeArrayObserver(this,{willChange:"dependentArrayWillChange",didChange:"dependentArrayDidChange"})},suspendArrayObservers:function(e,t){var r=this.suspended;this.suspended=!0,e.call(t),this.suspended=r},setupPropertyObservers:function(e,t){var r=d(this.instanceMeta.context,e),n=d(r,"length"),i=new Array(n);this.resetTransformations(e,i),F(r,function(n,a){var s=this.createPropertyObserverContext(r,a,this.trackedArraysByGuid[e]);i[a]=s,F(t,function(e){M(n,e,this,s.beforeObserver),D(n,e,this,s.observer)},this)},this)},teardownPropertyObservers:function(e,t){var r,n,i,a=this,s=this.trackedArraysByGuid[e];s&&s.apply(function(e,s,o){o!==B.DELETE&&F(e,function(e){e.destroyed=!0,r=e.beforeObserver,n=e.observer,i=e.item,F(t,function(e){L(i,e,a,r),R(i,e,a,n)})})})},createPropertyObserverContext:function(e,t,r){var n=new b(e,t,r);return this.createPropertyObserver(n),n},createPropertyObserver:function(e){var t=this;e.beforeObserver=function(r,n){return t.itemPropertyWillChange(r,n,e.dependentArray,e)},e.observer=function(r,n){return t.itemPropertyDidChange(r,n,e.dependentArray,e)}},resetTransformations:function(e,t){this.trackedArraysByGuid[e]=new B(t)},trackAdd:function(e,t,r){var n=this.trackedArraysByGuid[e];n&&n.addItems(t,r)},trackRemove:function(e,t,r){var n=this.trackedArraysByGuid[e];return n?n.removeItems(t,r):[]},updateIndexes:function(e,t){var r=d(t,"length");e.apply(function(e,t,n,i){n!==B.DELETE&&(0!==i||n!==B.RETAIN||e.length!==r||0!==t)&&F(e,function(e,r){e.index=r+t})})},dependentArrayWillChange:function(e,t,r){function n(e){u[o].destroyed=!0,L(a,e,this,u[o].beforeObserver),R(a,e,this,u[o].observer)}if(!this.suspended){var i,a,s,o,u,l=this.callbacks.removedItem,c=N(e),h=this.dependentKeysByGuid[c],p=this.cp._itemPropertyKeys[h]||[],m=d(e,"length"),f=g(t,m,0),v=y(f,m,r);for(u=this.trackRemove(h,f,v),o=v-1;o>=0&&(s=f+o,!(s>=m));--o)a=e.objectAt(s),F(p,n,this),i=new _(e,a,s,this.instanceMeta.propertyName,this.cp,v),this.setValue(l.call(this.instanceMeta.context,this.getValue(),a,i,this.instanceMeta.sugarMeta))}},dependentArrayDidChange:function(e,t,r,n){if(!this.suspended){var i,a,s=this.callbacks.addedItem,o=N(e),u=this.dependentKeysByGuid[o],l=new Array(n),c=this.cp._itemPropertyKeys[u],h=d(e,"length"),p=g(t,h,n),m=p+n;F(e.slice(p,m),function(t,r){c&&(a=this.createPropertyObserverContext(e,p+r,this.trackedArraysByGuid[u]),l[r]=a,F(c,function(e){M(t,e,this,a.beforeObserver),D(t,e,this,a.observer)},this)),i=new _(e,t,p+r,this.instanceMeta.propertyName,this.cp,n),this.setValue(s.call(this.instanceMeta.context,this.getValue(),t,i,this.instanceMeta.sugarMeta))},this),this.trackAdd(u,p,l)}},itemPropertyWillChange:function(e,t,r,n){var i=N(e);this.changedItems[i]||(this.changedItems[i]={array:r,observerContext:n,obj:e,previousValues:{}}),++this.changedItemCount,this.changedItems[i].previousValues[t]=d(e,t)},itemPropertyDidChange:function(){0===--this.changedItemCount&&this.flushChanges()},flushChanges:function(){var e,t,r,n=this.changedItems;for(e in n)t=n[e],t.observerContext.destroyed||(this.updateIndexes(t.observerContext.trackedArray,t.observerContext.dependentArray),r=new _(t.array,t.obj,t.observerContext.index,this.instanceMeta.propertyName,this.cp,n.length,t.previousValues),this.setValue(this.callbacks.removedItem.call(this.instanceMeta.context,this.getValue(),t.obj,r,this.instanceMeta.sugarMeta)),this.setValue(this.callbacks.addedItem.call(this.instanceMeta.context,this.getValue(),t.obj,r,this.instanceMeta.sugarMeta)));this.changedItems={}}},O.prototype={getValue:function(){var e=G(this.cache,this.propertyName);return void 0!==e?e:this.initialValue},setValue:function(e,t){e!==G(this.cache,this.propertyName)&&(t&&k(this.context,this.propertyName),void 0===e?Q(this.cache,this.propertyName):W(this.cache,this.propertyName,e),t&&I(this.context,this.propertyName))}},f.ReduceComputedProperty=P,P.prototype=q(H.prototype),P.prototype._callbacks=function(){if(!this.callbacks){var e=this.options;this.callbacks={removedItem:e.removedItem||E,addedItem:e.addedItem||E}}return this.callbacks},P.prototype._hasInstanceMeta=function(e,t){return!!S(e).cacheMeta[t]},P.prototype._instanceMeta=function(e,t){var r=S(e).cacheMeta,n=r[t];return n||(n=r[t]=new O(e,t,this.initialValue()),n.dependentArraysObserver=new v(this._callbacks(),this,n,e,t,n.sugarMeta)),n},P.prototype.initialValue=function(){return"function"==typeof this.options.initialValue?this.options.initialValue():this.options.initialValue},P.prototype.resetValue=function(){return this.initialValue()},P.prototype.itemPropertyKey=function(e,t){this._itemPropertyKeys[e]=this._itemPropertyKeys[e]||[],this._itemPropertyKeys[e].push(t)},P.prototype.clearItemPropertyKeys=function(e){this._itemPropertyKeys[e]&&(this._previousItemPropertyKeys[e]=this._itemPropertyKeys[e],this._itemPropertyKeys[e]=[])},P.prototype.property=function(){var e,t,r=this,n=$.call(arguments),i={};F(n,function(n){if(J.test(n))throw new V("Nested @each properties not supported: "+n);if(e=Y.exec(n)){t=e[1];var a=e[2],s=function(e){r.itemPropertyKey(t,e)};j(a,s),i[N(t)]=t}else i[N(n)]=n});var a=[];for(var s in i)a.push(i[s]);return H.prototype.property.apply(this,a)},f.reduceComputed=A}),e("ember-runtime/computed/reduce_computed_macros",["ember-metal/core","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/enumerable_utils","ember-metal/run_loop","ember-metal/observer","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/system/object_proxy","ember-runtime/system/subarray","ember-metal/keys","ember-runtime/compare","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d){"use strict";function v(e){return R(e,{initialValue:0,addedItem:function(e,t){return e+t},removedItem:function(e,t){return e-t}})}function b(e){return R(e,{initialValue:-1/0,addedItem:function(e,t){return Math.max(e,t)},removedItem:function(e,t){return e>t?e:void 0}})}function g(e){return R(e,{initialValue:1/0,addedItem:function(e,t){return Math.min(e,t)},removedItem:function(e,t){return t>e?e:void 0}})}function y(e,t){var r={addedItem:function(e,r,n){var i=t.call(this,r,n.index);return e.insertAt(n.index,i),e},removedItem:function(e,t,r){return e.removeAt(r.index,1),e}};return D(e,r)}function _(e,t){var r=function(e){return N(e,t)};return y(e+".@each."+t,r)}function w(e,t){var r={initialize:function(e,t,r){r.filteredArrayIndexes=new L},addedItem:function(e,r,n,i){var a=!!t.call(this,r,n.index),s=i.filteredArrayIndexes.addItem(n.index,a);return a&&e.insertAt(s,r),e},removedItem:function(e,t,r,n){var i=n.filteredArrayIndexes.removeItem(r.index);return i>-1&&e.removeAt(i),e}};return D(e,r)}function x(e,t,r){var n;return n=2===arguments.length?function(e){return N(e,t)}:function(e){return N(e,t)===r},w(e+".@each."+t,n)}function C(){var e=q.call(arguments);return e.push({initialize:function(e,t,r){r.itemCounts={}},addedItem:function(e,t,r,n){var i=S(t);return n.itemCounts[i]?++n.itemCounts[i]:(n.itemCounts[i]=1,e.pushObject(t)),e},removedItem:function(e,t,r,n){var i=S(t),a=n.itemCounts;return 0===--a[i]&&e.removeObject(t),e}}),D.apply(null,e)}function O(){var e=q.call(arguments);return e.push({initialize:function(e,t,r){r.itemCounts={}},addedItem:function(e,t,r,n){var i=S(t),a=S(r.arrayChanged),s=r.property._dependentKeys.length,o=n.itemCounts;return o[i]||(o[i]={}),void 0===o[i][a]&&(o[i][a]=0),1===++o[i][a]&&s===H(o[i]).length&&e.addObject(t),e},removedItem:function(e,t,r,n){var i,a=S(t),s=S(r.arrayChanged),o=(r.property._dependentKeys.length,n.itemCounts);return void 0===o[a][s]&&(o[a][s]=0),0===--o[a][s]&&(delete o[a][s],i=H(o[a]).length,0===i&&delete o[a],e.removeObject(t)),e}}),D.apply(null,e)}function P(e,t){if(2!==arguments.length)throw new V("setDiff requires exactly two dependent arrays.");return D(e,t,{addedItem:function(r,n,i){var a=N(this,e),s=N(this,t);return i.arrayChanged===a?s.contains(n)||r.addObject(n):r.removeObject(n),r},removedItem:function(r,n,i){var a=N(this,e),s=N(this,t);return i.arrayChanged===s?a.contains(n)&&r.addObject(n):r.removeObject(n),r}})}function E(e,t,r,n){function i(e){return S(K.detectInstance(e)?N(e,"content"):e)}var a,s,o,u,l;return arguments.length<4&&(n=N(e,"length")),arguments.length<3&&(r=0),r===n?r:(a=r+Math.floor((n-r)/2),s=e.objectAt(a),u=i(s),l=i(t),u===l?a:(o=this.order(s,t),0===o&&(o=l>u?-1:1),0>o?this.binarySearch(e,t,a+1,n):o>0?this.binarySearch(e,t,r,a):a))}function A(e,t){var r,n;return"function"==typeof t?r=function(e,r,n){n.order=t,n.binarySearch=E}:(n=t,r=function(t,r,i){function a(){var t,a,o,u=N(this,n),l=i.sortProperties=[],c=i.sortPropertyAscending={};r.property.clearItemPropertyKeys(e),k(u,function(n){-1!==(a=n.indexOf(":"))?(t=n.substring(0,a),o="desc"!==n.substring(a+1).toLowerCase()):(t=n,o=!0),l.push(t),c[t]=o,r.property.itemPropertyKey(e,t)}),u.addObserver("@each",this,s)}function s(){I.once(this,o,r.propertyName)}function o(e){a.call(this),r.property.recomputeOnce.call(this,e)}j(this,n,s),a.call(this),i.order=function(e,t){for(var r,n,i,a=t instanceof K,s=0;s=0&&r>e&&(t=this.lookupItemController(i))?this.controllerAt(e,i,t):i},arrangedContentDidChange:function(){this._super(),this._resetSubControllers()},arrayContentDidChange:function(e,t,r){var n=this._subControllers;if(n.length){var i=n.slice(e,e+t);p(i,function(e){e&&e.destroy()}),m(n,e,t,new Array(r))}this._super(e,t,r)},init:function(){this._super(),this._subControllers=[]},model:b(function(){return c.A()}),_isVirtual:!1,controllerAt:function(e,t,r){var n,i,a,s=h(this,"container"),o=this._subControllers;if(o.length>e&&(i=o[e]))return i;if(a=this._isVirtual?h(this,"parentController"):this,n="controller:"+r,!s.has(n))throw new g('Could not resolve itemController: "'+r+'"');return i=s.lookupFactory(n).create({target:a,parentController:a,model:t}),o[e]=i,i},_subControllers:null,_resetSubControllers:function(){var e,t=this._subControllers;if(t.length){for(var r=0,n=t.length;n>r;r++)e=t[r],e&&e.destroy();t.length=0}},willDestroy:function(){this._resetSubControllers(),this._super()}})}),e("ember-runtime/controllers/controller",["ember-runtime/system/object","ember-runtime/mixins/controller","exports"],function(e,t,r){"use strict";var n=e["default"],i=t["default"];r["default"]=n.extend(i)}),e("ember-runtime/controllers/object_controller",["ember-runtime/mixins/controller","ember-runtime/system/object_proxy","exports"],function(e,t,r){"use strict";var n=e["default"],i=t["default"];r["default"]=i.extend(n)}),e("ember-runtime/copy",["ember-metal/enumerable_utils","ember-metal/utils","ember-runtime/system/object","ember-runtime/mixins/copyable","exports"],function(e,t,r,n,i){"use strict";function a(e,t,r,n){var i,l,c;if("object"!=typeof e||null===e)return e;if(t&&(l=s(r,e))>=0)return n[l];if("array"===o(e)){if(i=e.slice(),t)for(l=i.length;--l>=0;)i[l]=a(i[l],t,r,n)}else if(u&&u.detect(e))i=e.copy(t,r,n);else if(e instanceof Date)i=new Date(e.getTime());else{i={};for(c in e)Object.prototype.hasOwnProperty.call(e,c)&&"__"!==c.substring(0,2)&&(i[c]=t?a(e[c],t,r,n):e[c])}return t&&(r.push(e),n.push(i)),i}var s=e.indexOf,o=t.typeOf,u=(r["default"],n["default"]);i["default"]=function(e,t){return"object"!=typeof e||null===e?e:u&&u.detect(e)?e.copy(t):a(e,t,t?[]:null,t?[]:null)}}),e("ember-runtime/core",["exports"],function(e){"use strict";var t=function(e,t){return e&&"function"==typeof e.isEqual?e.isEqual(t):e instanceof Date&&t instanceof Date?e.getTime()===t.getTime():e===t};e.isEqual=t}),e("ember-runtime/ext/function",["ember-metal/core","ember-metal/expand_properties","ember-metal/computed","ember-metal/mixin"],function(e,t,r,n){"use strict";var i=e["default"],a=t["default"],s=r.computed,o=n.observer,u=Array.prototype.slice,l=Function.prototype;(i.EXTEND_PROTOTYPES===!0||i.EXTEND_PROTOTYPES.Function)&&(l.property=function(){var e=s(this);return e.property.apply(e,arguments)},l.observes=function(){for(var e=arguments.length,t=new Array(e),r=0;e>r;r++)t[r]=arguments[r];return o.apply(this,t.concat(this))},l.observesImmediately=function(){for(var e=0,t=arguments.length;t>e;e++){arguments[e]}return this.observes.apply(this,arguments)},l.observesBefore=function(){for(var e=[],t=function(t){e.push(t)},r=0,n=arguments.length;n>r;++r)a(arguments[r],t);return this.__ember_observesBefore__=e,this},l.on=function(){var e=u.call(arguments);return this.__ember_listens__=e,this})}),e("ember-runtime/ext/rsvp",["ember-metal/core","ember-metal/logger","ember-metal/run_loop","exports"],function(e,r,n,i){"use strict";var a,s=e["default"],o=r["default"],u=n["default"],l=t("rsvp"),c="ember-testing/test",h=function(){s.Test&&s.Test.adapter&&s.Test.adapter.asyncStart()},p=function(){s.Test&&s.Test.adapter&&s.Test.adapter.asyncEnd()};l.configure("async",function(e,t){var r=!u.currentRunLoop;s.testing&&r&&h(),u.backburner.schedule("actions",function(){s.testing&&r&&p(),e(t)})}),l.Promise.prototype.fail=function(e,t){return this["catch"](e,t)},l.onerrorDefault=function(e){if(e instanceof Error)if(s.testing){if(!a&&s.__loader.registry[c]&&(a=t(c)["default"]),!a||!a.adapter)throw e;a.adapter.exception(e)}else s.onerror?s.onerror(e):o.error(e.stack)},l.on("error",l.onerrorDefault),i["default"]=l}),e("ember-runtime/ext/string",["ember-metal/core","ember-runtime/system/string"],function(e,t){"use strict";var r=e["default"],n=t.fmt,i=t.w,a=t.loc,s=t.camelize,o=t.decamelize,u=t.dasherize,l=t.underscore,c=t.capitalize,h=t.classify,p=String.prototype;(r.EXTEND_PROTOTYPES===!0||r.EXTEND_PROTOTYPES.String)&&(p.fmt=function(){return n(this,arguments)},p.w=function(){return i(this)},p.loc=function(){return a(this,arguments)},p.camelize=function(){return s(this)},p.decamelize=function(){return o(this)},p.dasherize=function(){return u(this)},p.underscore=function(){return l(this)},p.classify=function(){return h(this)},p.capitalize=function(){return c(this)})}),e("ember-runtime/mixins/-proxy",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/property_events","ember-metal/computed","ember-metal/properties","ember-metal/mixin","ember-runtime/system/string","ember-runtime/system/object","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h){"use strict";function p(e,t){var r=t.slice(8);r in this||w(this,r)}function m(e,t){var r=t.slice(8);r in this||x(this,r)}{var f=(e["default"],t.get),d=r.set,v=n.meta,b=i.addObserver,g=i.removeObserver,y=i.addBeforeObserver,_=i.removeBeforeObserver,w=a.propertyWillChange,x=a.propertyDidChange,C=s.computed,O=o.defineProperty,P=u.Mixin,E=u.observer;l.fmt,c["default"]}h["default"]=P.create({content:null,_contentDidChange:E("content",function(){}),isTruthy:C.bool("content"),_debugContainerKey:null,willWatchProperty:function(e){var t="content."+e;y(this,t,null,p),b(this,t,null,m)},didUnwatchProperty:function(e){var t="content."+e;_(this,t,null,p),g(this,t,null,m)},unknownProperty:function(e){var t=f(this,"content");return t?f(t,e):void 0},setUnknownProperty:function(e,t){var r=v(this);if(r.proto===this)return O(this,e,null,t),t;var n=f(this,"content");return d(n,e,t)}})}),e("ember-runtime/mixins/action_handler",["ember-metal/merge","ember-metal/mixin","ember-metal/property_get","ember-metal/utils","exports"],function(e,t,r,n,i){"use strict";var a=e["default"],s=t.Mixin,o=r.get,u=n.typeOf,l=s.create({mergedProperties:["_actions"],willMergeMixin:function(e){var t;e._actions||("object"===u(e.actions)?t="actions":"object"===u(e.events)&&(t="events"),t&&(e._actions=a(e._actions||{},e[t])),delete e[t])},send:function(e){var t,r=[].slice.call(arguments,1);this._actions&&this._actions[e]&&this._actions[e].apply(this,r)!==!0||(t=o(this,"target"))&&t.send.apply(t,arguments)}});i["default"]=l}),e("ember-runtime/mixins/array",["ember-metal/core","ember-metal/property_get","ember-metal/computed","ember-metal/is_none","ember-runtime/mixins/enumerable","ember-metal/enumerable_utils","ember-metal/mixin","ember-metal/property_events","ember-metal/events","ember-metal/watching","exports"],function(e,r,n,i,a,s,o,u,l,c,h){"use strict";function p(e,t,r,n,i){var a=r&&r.willChange||"arrayWillChange",s=r&&r.didChange||"arrayDidChange",o=f(e,"hasArrayObservers");return o===i&&x(e,"hasArrayObservers"),n(e,"@array:before",t,a),n(e,"@array:change",t,s),o===i&&C(e,"hasArrayObservers"),e}var m=e["default"],f=r.get,d=n.computed,v=n.cacheFor,b=i.isNone,g=(i.none,a["default"]),y=s.map,_=o.Mixin,w=o.required,x=u.propertyWillChange,C=u.propertyDidChange,O=l.addListener,P=l.removeListener,E=l.sendEvent,A=l.hasListeners,T=c.isWatching;h["default"]=_.create(g,{length:w(),objectAt:function(e){return 0>e||e>=f(this,"length")?void 0:f(this,e)},objectsAt:function(e){var t=this;return y(e,function(e){return t.objectAt(e)})},nextObject:function(e){return this.objectAt(e)},"[]":d(function(e,t){return void 0!==t&&this.replace(0,f(this,"length"),t),this}),firstObject:d(function(){return this.objectAt(0)}),lastObject:d(function(){return this.objectAt(f(this,"length")-1)}),contains:function(e){return this.indexOf(e)>=0},slice:function(e,t){var r=m.A(),n=f(this,"length");for(b(e)&&(e=0),(b(t)||t>n)&&(t=n),0>e&&(e=n+e),0>t&&(t=n+t);t>e;)r[r.length]=this.objectAt(e++);return r},indexOf:function(e,t){var r,n=f(this,"length");for(void 0===t&&(t=0),0>t&&(t+=n),r=t;n>r;r++)if(this.objectAt(r)===e)return r;return-1},lastIndexOf:function(e,t){var r,n=f(this,"length");for((void 0===t||t>=n)&&(t=n-1),0>t&&(t+=n),r=t;r>=0;r--)if(this.objectAt(r)===e)return r;return-1},addArrayObserver:function(e,t){return p(this,e,t,O,!1)},removeArrayObserver:function(e,t){return p(this,e,t,P,!0)},hasArrayObservers:d(function(){return A(this,"@array:change")||A(this,"@array:before")}),arrayContentWillChange:function(e,t,r){var n,i;if(void 0===e?(e=0,t=r=-1):(void 0===t&&(t=-1),void 0===r&&(r=-1)),T(this,"@each")&&f(this,"@each"),E(this,"@array:before",[this,e,t,r]),e>=0&&t>=0&&f(this,"hasEnumerableObservers")){n=[],i=e+t;for(var a=e;i>a;a++)n.push(this.objectAt(a))}else n=t;return this.enumerableContentWillChange(n,r),this},arrayContentDidChange:function(e,t,r){var n,i;if(void 0===e?(e=0,t=r=-1):(void 0===t&&(t=-1),void 0===r&&(r=-1)),e>=0&&r>=0&&f(this,"hasEnumerableObservers")){n=[],i=e+r;for(var a=e;i>a;a++)n.push(this.objectAt(a))}else n=r;this.enumerableContentDidChange(t,n),E(this,"@array:change",[this,e,t,r]);var s=f(this,"length"),o=v(this,"firstObject"),u=v(this,"lastObject");return this.objectAt(0)!==o&&(x(this,"firstObject"),C(this,"firstObject")),this.objectAt(s-1)!==u&&(x(this,"lastObject"),C(this,"lastObject")),this},"@each":d(function(){if(!this.__each){var e=t("ember-runtime/system/each_proxy").EachProxy;this.__each=new e(this)}return this.__each})})}),e("ember-runtime/mixins/comparable",["ember-metal/mixin","exports"],function(e,t){"use strict";var r=e.Mixin,n=e.required;t["default"]=r.create({compare:n(Function)})}),e("ember-runtime/mixins/controller",["ember-metal/core","ember-metal/property_get","ember-runtime/system/object","ember-metal/mixin","ember-metal/computed","ember-runtime/mixins/action_handler","ember-runtime/mixins/controller_content_model_alias_deprecation","exports"],function(e,t,r,n,i,a,s,o){"use strict";var u=(e["default"],t.get,r["default"],n.Mixin),l=i.computed,c=a["default"],h=s["default"];o["default"]=u.create(c,h,{isController:!0,target:null,container:null,parentController:null,store:null,model:null,content:l.alias("model")})}),e("ember-runtime/mixins/controller_content_model_alias_deprecation",["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"],function(e,t,r,n){"use strict";var i=(e["default"],t.get,r.Mixin);n["default"]=i.create({willMergeMixin:function(e){this._super.apply(this,arguments);var t=!!e.model;e.content&&!t&&(e.model=e.content,delete e.content)}})}),e("ember-runtime/mixins/copyable",["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/freezable","ember-runtime/system/string","ember-metal/error","exports"],function(e,t,r,n,i,a,s){"use strict";var o=e.get,u=(t.set,r.required),l=n.Freezable,c=r.Mixin,h=i.fmt,p=a["default"];s["default"]=c.create({copy:u(Function),frozenCopy:function(){if(l&&l.detect(this))return o(this,"isFrozen")?this:this.copy().freeze();throw new p(h("%@ does not support freezing",[this]))}})}),e("ember-runtime/mixins/deferred",["ember-metal/core","ember-metal/property_get","ember-metal/mixin","ember-metal/computed","ember-runtime/ext/rsvp","exports"],function(e,t,r,n,i,a){"use strict";var s=(e["default"],t.get),o=r.Mixin,u=n.computed,l=i["default"];a["default"]=o.create({then:function(e,t,r){function n(t){return e(t===a?o:t)}var i,a,o;return o=this,i=s(this,"_deferred"),a=i.promise,a.then(e&&n,t,r)},resolve:function(e){var t,r;t=s(this,"_deferred"),r=t.promise,t.resolve(e===this?r:e)},reject:function(e){s(this,"_deferred").reject(e)},_deferred:u(function(){return l.defer("Ember: DeferredMixin - "+this)})})}),e("ember-runtime/mixins/enumerable",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/property_events","ember-metal/events","ember-runtime/compare","exports"],function(e,t,r,n,i,a,s,o,u,l,c){"use strict";function h(){return 0===V.length?{}:V.pop()}function p(e){return V.push(e),null}function m(e,t){function r(r){var i=d(r,e);return n?t===i:!!i}var n=2===arguments.length;return r}var f=e["default"],d=t.get,v=r.set,b=n.apply,g=i.Mixin,y=i.required,_=i.aliasMethod,w=a.indexOf,x=s.computed,C=o.propertyWillChange,O=o.propertyDidChange,P=u.addListener,E=u.removeListener,A=u.sendEvent,T=u.hasListeners,N=l["default"],S=Array.prototype.slice,V=[];c["default"]=g.create({nextObject:y(Function),firstObject:x("[]",function(){if(0===d(this,"length"))return void 0;var e,t=h();return e=this.nextObject(0,null,t),p(t),e}),lastObject:x("[]",function(){var e=d(this,"length");if(0===e)return void 0;var t,r=h(),n=0,i=null;do i=t,t=this.nextObject(n++,i,r);while(void 0!==t);return p(r),i}),contains:function(e){return void 0!==this.find(function(t){return t===e})},forEach:function(e,t){if("function"!=typeof e)throw new TypeError;var r=d(this,"length"),n=null,i=h();void 0===t&&(t=null);for(var a=0;r>a;a++){var s=this.nextObject(a,n,i);e.call(t,s,a,this),n=s}return n=null,i=p(i),this},getEach:function(e){return this.mapBy(e)},setEach:function(e,t){return this.forEach(function(r){v(r,e,t)})},map:function(e,t){var r=f.A();return this.forEach(function(n,i,a){r[i]=e.call(t,n,i,a)}),r},mapBy:function(e){return this.map(function(t){return d(t,e)})},mapProperty:_("mapBy"),filter:function(e,t){var r=f.A();return this.forEach(function(n,i,a){e.call(t,n,i,a)&&r.push(n)}),r},reject:function(e,t){return this.filter(function(){return!b(t,e,arguments)})},filterBy:function(){return this.filter(b(this,m,arguments))},filterProperty:_("filterBy"),rejectBy:function(e,t){var r=function(r){return d(r,e)===t},n=function(t){return!!d(t,e)},i=2===arguments.length?r:n;return this.reject(i)},rejectProperty:_("rejectBy"),find:function(e,t){var r=d(this,"length");void 0===t&&(t=null);for(var n,i,a=null,s=!1,o=h(),u=0;r>u&&!s;u++)n=this.nextObject(u,a,o),(s=e.call(t,n,u,this))&&(i=n),a=n;return n=a=null,o=p(o),i},findBy:function(){return this.find(b(this,m,arguments))},findProperty:_("findBy"),every:function(e,t){return!this.find(function(r,n,i){return!e.call(t,r,n,i)})},everyBy:_("isEvery"),everyProperty:_("isEvery"),isEvery:function(){return this.every(b(this,m,arguments))},any:function(e,t){var r,n,i=d(this,"length"),a=h(),s=!1,o=null;for(void 0===t&&(t=null),n=0;i>n&&!s;n++)r=this.nextObject(n,o,a),s=e.call(t,r,n,this),o=r;return r=o=null,a=p(a),s},some:_("any"),isAny:function(){return this.any(b(this,m,arguments))},anyBy:_("isAny"),someProperty:_("isAny"),reduce:function(e,t,r){if("function"!=typeof e)throw new TypeError;var n=t;return this.forEach(function(t,i){n=e(n,t,i,this,r)},this),n},invoke:function(e){var t,r=f.A();return arguments.length>1&&(t=S.call(arguments,1)),this.forEach(function(n,i){var a=n&&n[e];"function"==typeof a&&(r[i]=t?b(n,a,t):n[e]())},this),r},toArray:function(){var e=f.A();return this.forEach(function(t,r){e[r]=t}),e},compact:function(){return this.filter(function(e){return null!=e})},without:function(e){if(!this.contains(e))return this;var t=f.A();return this.forEach(function(r){r!==e&&(t[t.length]=r)}),t},uniq:function(){var e=f.A();return this.forEach(function(t){w(e,t)<0&&e.push(t)}),e},"[]":x(function(){return this}),addEnumerableObserver:function(e,t){var r=t&&t.willChange||"enumerableWillChange",n=t&&t.didChange||"enumerableDidChange",i=d(this,"hasEnumerableObservers");return i||C(this,"hasEnumerableObservers"),P(this,"@enumerable:before",e,r),P(this,"@enumerable:change",e,n),i||O(this,"hasEnumerableObservers"),this},removeEnumerableObserver:function(e,t){var r=t&&t.willChange||"enumerableWillChange",n=t&&t.didChange||"enumerableDidChange",i=d(this,"hasEnumerableObservers");return i&&C(this,"hasEnumerableObservers"),E(this,"@enumerable:before",e,r),E(this,"@enumerable:change",e,n),i&&O(this,"hasEnumerableObservers"),this},hasEnumerableObservers:x(function(){return T(this,"@enumerable:change")||T(this,"@enumerable:before")}),enumerableContentWillChange:function(e,t){var r,n,i;return r="number"==typeof e?e:e?d(e,"length"):e=-1,n="number"==typeof t?t:t?d(t,"length"):t=-1,i=0>n||0>r||n-r!==0,-1===e&&(e=null),-1===t&&(t=null),C(this,"[]"),i&&C(this,"length"),A(this,"@enumerable:before",[this,e,t]),this},enumerableContentDidChange:function(e,t){var r,n,i;return r="number"==typeof e?e:e?d(e,"length"):e=-1,n="number"==typeof t?t:t?d(t,"length"):t=-1,i=0>n||0>r||n-r!==0,-1===e&&(e=null),-1===t&&(t=null),A(this,"@enumerable:change",[this,e,t]),i&&O(this,"length"),O(this,"[]"),this},sortBy:function(){var e=arguments;return this.toArray().sort(function(t,r){for(var n=0;nn;n++)r[n-1]=arguments[n];o(this,e,r)},off:function(e,t,r){return a(this,e,t,r),this},has:function(e){return s(this,e)}})}),e("ember-runtime/mixins/freezable",["ember-metal/mixin","ember-metal/property_get","ember-metal/property_set","exports"],function(e,t,r,n){"use strict";var i=e.Mixin,a=t.get,s=r.set,o=i.create({isFrozen:!1,freeze:function(){return a(this,"isFrozen")?this:(s(this,"isFrozen",!0),this)}});n.Freezable=o;var u="Frozen object cannot be modified.";n.FROZEN_ERROR=u}),e("ember-runtime/mixins/mutable_array",["ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/mixin","ember-runtime/mixins/array","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","exports"],function(e,t,r,n,i,a,s,o,u){"use strict"; +var l="Index out of range",c=[],h=e.get,p=(t.set,r.isArray),m=n["default"],f=i.Mixin,d=i.required,v=a["default"],b=s["default"],g=o["default"];u["default"]=f.create(v,b,{replace:d(),clear:function(){var e=h(this,"length");return 0===e?this:(this.replace(0,e,c),this)},insertAt:function(e,t){if(e>h(this,"length"))throw new m(l);return this.replace(e,0,[t]),this},removeAt:function(e,t){if("number"==typeof e){if(0>e||e>=h(this,"length"))throw new m(l);void 0===t&&(t=1),this.replace(e,t,c)}return this},pushObject:function(e){return this.insertAt(h(this,"length"),e),e},pushObjects:function(e){if(!g.detect(e)&&!p(e))throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects");return this.replace(h(this,"length"),0,e),this},popObject:function(){var e=h(this,"length");if(0===e)return null;var t=this.objectAt(e-1);return this.removeAt(e-1,1),t},shiftObject:function(){if(0===h(this,"length"))return null;var e=this.objectAt(0);return this.removeAt(0),e},unshiftObject:function(e){return this.insertAt(0,e),e},unshiftObjects:function(e){return this.replace(0,0,e),this},reverseObjects:function(){var e=h(this,"length");if(0===e)return this;var t=this.toArray().reverse();return this.replace(0,e,t),this},setObjects:function(e){if(0===e.length)return this.clear();var t=h(this,"length");return this.replace(0,t,e),this},removeObject:function(e){for(var t=h(this,"length")||0;--t>=0;){var r=this.objectAt(t);r===e&&this.removeAt(t)}return this},addObject:function(e){return this.contains(e)||this.pushObject(e),this}})}),e("ember-runtime/mixins/mutable_enumerable",["ember-metal/enumerable_utils","ember-runtime/mixins/enumerable","ember-metal/mixin","ember-metal/property_events","exports"],function(e,t,r,n,i){"use strict";var a=e.forEach,s=t["default"],o=r.Mixin,u=r.required,l=n.beginPropertyChanges,c=n.endPropertyChanges;i["default"]=o.create(s,{addObject:u(Function),addObjects:function(e){return l(this),a(e,function(e){this.addObject(e)},this),c(this),this},removeObject:u(Function),removeObjects:function(e){l(this);for(var t=e.length-1;t>=0;t--)this.removeObject(e[t]);return c(this),this}})}),e("ember-runtime/mixins/observable",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/get_properties","ember-metal/set_properties","ember-metal/mixin","ember-metal/events","ember-metal/property_events","ember-metal/observer","ember-metal/computed","ember-metal/is_none","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p){"use strict";var m=(e["default"],t.get),f=t.getWithDefault,d=r.set,v=n.apply,b=i["default"],g=a["default"],y=s.Mixin,_=o.hasListeners,w=u.beginPropertyChanges,x=u.propertyWillChange,C=u.propertyDidChange,O=u.endPropertyChanges,P=l.addObserver,E=l.addBeforeObserver,A=l.removeObserver,T=l.observersFor,N=c.cacheFor,S=h.isNone,V=Array.prototype.slice;p["default"]=y.create({get:function(e){return m(this,e)},getProperties:function(){return v(null,b,[this].concat(V.call(arguments)))},set:function(e,t){return d(this,e,t),this},setProperties:function(e){return g(this,e)},beginPropertyChanges:function(){return w(),this},endPropertyChanges:function(){return O(),this},propertyWillChange:function(e){return x(this,e),this},propertyDidChange:function(e){return C(this,e),this},notifyPropertyChange:function(e){return this.propertyWillChange(e),this.propertyDidChange(e),this},addBeforeObserver:function(e,t,r){E(this,e,t,r)},addObserver:function(e,t,r){P(this,e,t,r)},removeObserver:function(e,t,r){A(this,e,t,r)},hasObserverFor:function(e){return _(this,e+":change")},getWithDefault:function(e,t){return f(this,e,t)},incrementProperty:function(e,t){return S(t)&&(t=1),d(this,e,(parseFloat(m(this,e))||0)+t),m(this,e)},decrementProperty:function(e,t){return S(t)&&(t=1),d(this,e,(m(this,e)||0)-t),m(this,e)},toggleProperty:function(e){return d(this,e,!m(this,e)),m(this,e)},cacheFor:function(e){return N(this,e)},observersForKey:function(e){return T(this,e)}})}),e("ember-runtime/mixins/promise_proxy",["ember-metal/property_get","ember-metal/set_properties","ember-metal/computed","ember-metal/mixin","ember-metal/error","exports"],function(e,t,r,n,i,a){"use strict";function s(e,t){return l(e,{isFulfilled:!1,isRejected:!1}),t.then(function(t){return l(e,{content:t,isFulfilled:!0}),t},function(t){throw l(e,{reason:t,isRejected:!0}),t},"Ember: PromiseProxy")}function o(e){return function(){var t=u(this,"promise");return t[e].apply(t,arguments)}}var u=e.get,l=t["default"],c=r.computed,h=n.Mixin,p=i["default"],m=c.not,f=c.or;a["default"]=h.create({reason:null,isPending:m("isSettled").readOnly(),isSettled:f("isRejected","isFulfilled").readOnly(),isRejected:!1,isFulfilled:!1,promise:c(function(e,t){if(2===arguments.length)return s(this,t);throw new p("PromiseProxy's promise must be set")}),then:o("then"),"catch":o("catch"),"finally":o("finally")})}),e("ember-runtime/mixins/sortable",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/enumerable_utils","ember-metal/mixin","ember-runtime/mixins/mutable_enumerable","ember-runtime/compare","ember-metal/observer","ember-metal/computed","exports"],function(e,t,r,n,i,a,s,o,u,l){"use strict";var c=e["default"],h=t.get,p=(r.set,n.forEach),m=i.Mixin,f=a["default"],d=s["default"],v=o.addObserver,b=o.removeObserver,g=u.computed,y=i.beforeObserver,_=i.observer;l["default"]=m.create(f,{sortProperties:null,sortAscending:!0,sortFunction:d,orderBy:function(e,t){var r=0,n=h(this,"sortProperties"),i=h(this,"sortAscending"),a=h(this,"sortFunction");return p(n,function(n){0===r&&(r=a.call(this,h(e,n),h(t,n)),0===r||i||(r=-1*r))},this),r},destroy:function(){var e=h(this,"content"),t=h(this,"sortProperties");return e&&t&&p(e,function(e){p(t,function(t){b(e,t,this,"contentItemSortPropertyDidChange")},this)},this),this._super()},isSorted:g.notEmpty("sortProperties"),arrangedContent:g("content","sortProperties.@each",function(){var e=h(this,"content"),t=h(this,"isSorted"),r=h(this,"sortProperties"),n=this;return e&&t?(e=e.slice(),e.sort(function(e,t){return n.orderBy(e,t)}),p(e,function(e){p(r,function(t){v(e,t,this,"contentItemSortPropertyDidChange")},this)},this),c.A(e)):e}),_contentWillChange:y("content",function(){var e=h(this,"content"),t=h(this,"sortProperties");e&&t&&p(e,function(e){p(t,function(t){b(e,t,this,"contentItemSortPropertyDidChange")},this)},this),this._super()}),sortPropertiesWillChange:y("sortProperties",function(){this._lastSortAscending=void 0}),sortPropertiesDidChange:_("sortProperties",function(){this._lastSortAscending=void 0}),sortAscendingWillChange:y("sortAscending",function(){this._lastSortAscending=h(this,"sortAscending")}),sortAscendingDidChange:_("sortAscending",function(){if(void 0!==this._lastSortAscending&&h(this,"sortAscending")!==this._lastSortAscending){var e=h(this,"arrangedContent");e.reverseObjects()}}),contentArrayWillChange:function(e,t,r,n){var i=h(this,"isSorted");if(i){var a=h(this,"arrangedContent"),s=e.slice(t,t+r),o=h(this,"sortProperties");p(s,function(e){a.removeObject(e),p(o,function(t){b(e,t,this,"contentItemSortPropertyDidChange")},this)},this)}return this._super(e,t,r,n)},contentArrayDidChange:function(e,t,r,n){var i=h(this,"isSorted"),a=h(this,"sortProperties");if(i){var s=e.slice(t,t+n);p(s,function(e){this.insertItemSorted(e),p(a,function(t){v(e,t,this,"contentItemSortPropertyDidChange")},this)},this)}return this._super(e,t,r,n)},insertItemSorted:function(e){var t=h(this,"arrangedContent"),r=h(t,"length"),n=this._binarySearch(e,0,r);t.insertAt(n,e)},contentItemSortPropertyDidChange:function(e){var t=h(this,"arrangedContent"),r=t.indexOf(e),n=t.objectAt(r-1),i=t.objectAt(r+1),a=n&&this.orderBy(e,n),s=i&&this.orderBy(e,i);(0>a||s>0)&&(t.removeObject(e),this.insertItemSorted(e))},_binarySearch:function(e,t,r){var n,i,a,s;return t===r?t:(s=h(this,"arrangedContent"),n=t+Math.floor((r-t)/2),i=s.objectAt(n),a=this.orderBy(i,e),0>a?this._binarySearch(e,n+1,r):a>0?this._binarySearch(e,t,n):n)}})}),e("ember-runtime/mixins/target_action_support",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/computed","exports"],function(e,t,r,n,i,a,s){"use strict";var o=e["default"],u=t.get,l=(r.set,n.typeOf),c=i.Mixin,h=a.computed,p=c.create({target:null,action:null,actionContext:null,targetObject:h(function(){var e=u(this,"target");if("string"===l(e)){var t=u(this,e);return void 0===t&&(t=u(o.lookup,e)),t}return e}).property("target"),actionContextObject:h(function(){var e=u(this,"actionContext");if("string"===l(e)){var t=u(this,e);return void 0===t&&(t=u(o.lookup,e)),t}return e}).property("actionContext"),triggerAction:function(e){function t(e,t){var r=[];return t&&r.push(t),r.concat(e)}e=e||{};var r=e.action||u(this,"action"),n=e.target||u(this,"targetObject"),i=e.actionContext;if("undefined"==typeof i&&(i=u(this,"actionContextObject")||this),n&&r){var a;return a=n.send?n.send.apply(n,t(i,r)):n[r].apply(n,t(i)),a!==!1&&(a=!0),a}return!1}});s["default"]=p}),e("ember-runtime/system/application",["ember-runtime/system/namespace","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=r.extend()}),e("ember-runtime/system/array_proxy",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/property_events","ember-metal/error","ember-runtime/system/object","ember-runtime/mixins/mutable_array","ember-runtime/mixins/enumerable","ember-runtime/system/string","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p){"use strict";var m=e["default"],f=t.get,d=(r.set,n.isArray),v=n.apply,b=i.computed,g=a.beforeObserver,y=a.observer,_=s.beginPropertyChanges,w=s.endPropertyChanges,x=o["default"],C=u["default"],O=l["default"],P=c["default"],E=(h.fmt,"Index out of range"),A=[],T=b.alias,N=m.K,S=C.extend(O,{content:null,arrangedContent:T("content"),objectAtContent:function(e){return f(this,"arrangedContent").objectAt(e)},replaceContent:function(e,t,r){f(this,"content").replace(e,t,r)},_contentWillChange:g("content",function(){this._teardownContent()}),_teardownContent:function(){var e=f(this,"content");e&&e.removeArrayObserver(this,{willChange:"contentArrayWillChange",didChange:"contentArrayDidChange"})},contentArrayWillChange:N,contentArrayDidChange:N,_contentDidChange:y("content",function(){f(this,"content");this._setupContent()}),_setupContent:function(){var e=f(this,"content");e&&e.addArrayObserver(this,{willChange:"contentArrayWillChange",didChange:"contentArrayDidChange"})},_arrangedContentWillChange:g("arrangedContent",function(){var e=f(this,"arrangedContent"),t=e?f(e,"length"):0;this.arrangedContentArrayWillChange(this,0,t,void 0),this.arrangedContentWillChange(this),this._teardownArrangedContent(e)}),_arrangedContentDidChange:y("arrangedContent",function(){var e=f(this,"arrangedContent"),t=e?f(e,"length"):0;this._setupArrangedContent(),this.arrangedContentDidChange(this),this.arrangedContentArrayDidChange(this,0,void 0,t)}),_setupArrangedContent:function(){var e=f(this,"arrangedContent");e&&e.addArrayObserver(this,{willChange:"arrangedContentArrayWillChange",didChange:"arrangedContentArrayDidChange"})},_teardownArrangedContent:function(){var e=f(this,"arrangedContent");e&&e.removeArrayObserver(this,{willChange:"arrangedContentArrayWillChange",didChange:"arrangedContentArrayDidChange"})},arrangedContentWillChange:N,arrangedContentDidChange:N,objectAt:function(e){return f(this,"content")&&this.objectAtContent(e)},length:b(function(){var e=f(this,"arrangedContent");return e?f(e,"length"):0}),_replace:function(e,t,r){var n=f(this,"content");return n&&this.replaceContent(e,t,r),this},replace:function(){if(f(this,"arrangedContent")!==f(this,"content"))throw new x("Using replace on an arranged ArrayProxy is not allowed.");v(this,this._replace,arguments)},_insertAt:function(e,t){if(e>f(this,"content.length"))throw new x(E);return this._replace(e,0,[t]),this},insertAt:function(e,t){if(f(this,"arrangedContent")===f(this,"content"))return this._insertAt(e,t);throw new x("Using insertAt on an arranged ArrayProxy is not allowed.")},removeAt:function(e,t){if("number"==typeof e){var r,n=f(this,"content"),i=f(this,"arrangedContent"),a=[];if(0>e||e>=f(this,"length"))throw new x(E);for(void 0===t&&(t=1),r=e;e+t>r;r++)a.push(n.indexOf(i.objectAt(r)));for(a.sort(function(e,t){return t-e}),_(),r=0;rl;l++){var h=o[l];if("object"!=typeof h&&void 0!==h)throw new R("Ember.Object.create only accepts objects.");if(h)for(var p=L(h),m=0,f=p.length;f>m;m++){var d=p[m];if(h.hasOwnProperty(d)){var v=h[d];if(k.test(d)){var b=i.bindings;b?i.hasOwnProperty("bindings")||(b=i.bindings=O(i.bindings)):b=i.bindings={},b[d]=v}var g=i.descs[d];if(u&&D(u,d)>=0){var y=this[d];v=y?"function"==typeof y.concat?y.concat(v):T(y).concat(v):T(v)}g?g.set(this,d,v):"function"!=typeof this.setUnknownProperty||d in this?this[d]=v:this.setUnknownProperty(d,v)}}}}W(this,i);for(var _=arguments.length,w=new Array(_),x=0;_>x;x++)w[x]=arguments[x];C(this,this.init,w),i.proto=a,S(this),V(this,"init")};return n.toString=I.prototype.toString,n.willReopen=function(){r&&(n.PrototypeMixin=I.create(n.PrototypeMixin)),r=!1},n._initMixins=function(t){e=t},n._initProperties=function(e){t=e},n.proto=function(){var e=n.superclass;return e&&e.proto(),r||(r=!0,n.PrototypeMixin.applyPartial(n.prototype),N(n.prototype)),this.prototype},n}function y(e){return function(){return e}}var _=e["default"],w=t.get,x=(r.set,n.guidFor),C=n.apply,O=i.create,P=n.generateGuid,E=n.GUID_KEY,A=n.meta,T=n.makeArray,N=a.rewatch,S=s.finishChains,V=o.sendEvent,k=u.IS_BINDING,I=u.Mixin,j=u.required,D=l.indexOf,R=c["default"],M=i.defineProperty,L=h["default"],H=(p["default"],m.defineProperty,f.Binding),z=d.ComputedProperty,q=v["default"],F=a.destroy,B=e.K,U=(i.hasPropertyAccessors,q.schedule),K=I._apply,W=I.finishPartial,G=I.prototype.reopen,Q=!1,$={configurable:!0,writable:!0,enumerable:!1,value:void 0},Y={configurable:!0,writable:!0,enumerable:!1,value:null},J=g();J.toString=function(){return"Ember.CoreObject"},J.PrototypeMixin=I.create({reopen:function(){for(var e=arguments.length,t=new Array(e),r=0;e>r;r++)t[r]=arguments[r];return K(this,t,!0),this},init:function(){},concatenatedProperties:null,isDestroyed:!1,isDestroying:!1,destroy:function(){return this.isDestroying?void 0:(this.isDestroying=!0,U("actions",this,this.willDestroy),U("destroy",this,this._scheduledDestroy),this)},willDestroy:B,_scheduledDestroy:function(){this.isDestroyed||(F(this),this.isDestroyed=!0)},bind:function(e,t){return t instanceof H||(t=H.from(t)),t.to(e).connect(this),t},toString:function(){var e="function"==typeof this.toStringExtension,t=e?":"+this.toStringExtension():"",r="<"+this.constructor.toString()+":"+x(this)+t+">";return this.toString=y(r),r}}),J.PrototypeMixin.ownerConstructor=J,_.config.overridePrototypeMixin&&_.config.overridePrototypeMixin(J.PrototypeMixin),J.__super__=null;var Z=I.create({ClassMixin:j(),PrototypeMixin:j(),isClass:!0,isMethod:!1,extend:function(){var e,t=g();return t.ClassMixin=I.create(this.ClassMixin),t.PrototypeMixin=I.create(this.PrototypeMixin),t.ClassMixin.ownerConstructor=t,t.PrototypeMixin.ownerConstructor=t,G.apply(t.PrototypeMixin,arguments),t.superclass=this,t.__super__=this.prototype,e=t.prototype=O(this.prototype),e.constructor=t,P(e),A(e).proto=e,t.ClassMixin.apply(t),t},createWithMixins:function(){var e=this,t=arguments.length;if(t>0){for(var r=new Array(t),n=0;t>n;n++)r[n]=arguments[n];this._initMixins(r)}return new e},create:function(){var e=this,t=arguments.length;if(t>0){for(var r=new Array(t),n=0;t>n;n++)r[n]=arguments[n];this._initProperties(r)}return new e},reopen:function(){this.willReopen();var e=arguments.length,t=new Array(e);if(e>0)for(var r=0;e>r;r++)t[r]=arguments[r];return C(this.PrototypeMixin,G,t),this},reopenClass:function(){var e=arguments.length,t=new Array(e);if(e>0)for(var r=0;e>r;r++)t[r]=arguments[r];return C(this.ClassMixin,G,t),K(this,arguments,!1),this},detect:function(e){if("function"!=typeof e)return!1;for(;e;){if(e===this)return!0;e=e.superclass}return!1},detectInstance:function(e){return e instanceof this},metaForProperty:function(e){var t=this.proto().__ember_meta__,r=t&&t.descs[e];return r._meta||{}},_computedProperties:_.computed(function(){Q=!0;var e,t=this.proto(),r=A(t).descs,n=[];for(var i in r)e=r[i],e instanceof z&&n.push({name:i,meta:e._meta});return n}).readOnly(),eachComputedProperty:function(e,t){for(var r,n,i={},a=w(this,"_computedProperties"),s=0,o=a.length;o>s;s++)r=a[s],n=r.name,e.call(t||this,r.name,r.meta||i)}});Z.ownerConstructor=J,_.config.overrideClassMixin&&_.config.overrideClassMixin(Z),J.ClassMixin=Z,Z.apply(J),J.reopen({didDefineProperty:function(e,t,r){if(Q!==!1&&r instanceof _.ComputedProperty){var n=_.meta(this.constructor).cache;void 0!==n._computedProperties&&(n._computedProperties=void 0)}}}),b["default"]=J}),e("ember-runtime/system/deferred",["ember-metal/core","ember-runtime/mixins/deferred","ember-metal/property_get","ember-runtime/system/object","exports"],function(e,t,r,n,i){"use strict";var a=(e["default"],t["default"]),s=(r.get,n["default"]),o=s.extend(a,{init:function(){this._super()}});o.reopenClass({promise:function(e,t){var r=o.create();return e.call(t,r),r}}),i["default"]=o}),e("ember-runtime/system/each_proxy",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/enumerable_utils","ember-metal/array","ember-runtime/mixins/array","ember-runtime/system/object","ember-metal/computed","ember-metal/observer","ember-metal/events","ember-metal/properties","ember-metal/property_events","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m){"use strict";function f(e,t,r,n,i){var a,s=r._objects;for(s||(s=r._objects={});--i>=n;){var o=e.objectAt(i);o&&(O(o,t,r,"contentKeyWillChange"),C(o,t,r,"contentKeyDidChange"),a=b(o),s[a]||(s[a]=[]),s[a].push(i))}}function d(e,t,r,n,i){var a=r._objects;a||(a=r._objects={});for(var s,o;--i>=n;){var u=e.objectAt(i);u&&(P(u,t,r,"contentKeyWillChange"),E(u,t,r,"contentKeyDidChange"),o=b(u),s=a[o],s[y.call(s,i)]=null)}}var v=(e["default"],t.get),b=(r.set,n.guidFor),g=i.forEach,y=a.indexOf,_=s["default"],w=o["default"],x=u.computed,C=l.addObserver,O=l.addBeforeObserver,P=l.removeBeforeObserver,E=l.removeObserver,A=(n.typeOf,c.watchedEvents),T=h.defineProperty,N=p.beginPropertyChanges,S=p.propertyDidChange,V=p.propertyWillChange,k=p.endPropertyChanges,I=p.changeProperties,j=w.extend(_,{init:function(e,t,r){this._super(),this._keyName=t,this._owner=r,this._content=e},objectAt:function(e){var t=this._content.objectAt(e);return t&&v(t,this._keyName)},length:x(function(){var e=this._content;return e?v(e,"length"):0})}),D=/^.+:(before|change)$/,R=w.extend({init:function(e){this._super(),this._content=e,e.addArrayObserver(this),g(A(this),function(e){this.didAddListener(e)},this)},unknownProperty:function(e){var t;return t=new j(this._content,e,this),T(this,e,null,t),this.beginObservingContentKey(e),t},arrayWillChange:function(e,t,r){var n,i,a=this._keys;i=r>0?t+r:-1,N(this);for(n in a)a.hasOwnProperty(n)&&(i>0&&d(e,n,this,t,i),V(this,n));V(this._content,"@each"),k(this)},arrayDidChange:function(e,t,r,n){var i,a=this._keys;i=n>0?t+n:-1,I(function(){for(var r in a)a.hasOwnProperty(r)&&(i>0&&f(e,r,this,t,i),S(this,r));S(this._content,"@each")},this)},didAddListener:function(e){D.test(e)&&this.beginObservingContentKey(e.slice(0,-7))},didRemoveListener:function(e){D.test(e)&&this.stopObservingContentKey(e.slice(0,-7))},beginObservingContentKey:function(e){var t=this._keys;if(t||(t=this._keys={}),t[e])t[e]++;else{t[e]=1;var r=this._content,n=v(r,"length");f(r,e,this,0,n)}},stopObservingContentKey:function(e){var t=this._keys;if(t&&t[e]>0&&--t[e]<=0){var r=this._content,n=v(r,"length");d(r,e,this,0,n)}},contentKeyWillChange:function(e,t){V(this,t)},contentKeyDidChange:function(e,t){S(this,t)}});m.EachArray=j,m.EachProxy=R}),e("ember-runtime/system/lazy_load",["ember-metal/core","ember-metal/array","ember-runtime/system/native_array","exports"],function(e,t,r,n){"use strict";function i(e,t){var r;u[e]=u[e]||s.A(),u[e].pushObject(t),(r=l[e])&&t(r)}function a(e,t){if(l[e]=t,"object"==typeof window&&"function"==typeof window.dispatchEvent&&"function"==typeof CustomEvent){var r=new CustomEvent(e,{detail:t,name:e});window.dispatchEvent(r)}u[e]&&o.call(u[e],function(e){e(t)})}var s=e["default"],o=t.forEach,u=s.ENV.EMBER_LOAD_HOOKS||{},l={};n.onLoad=i,n.runLoadHooks=a}),e("ember-runtime/system/namespace",["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/mixin","ember-runtime/system/object","exports"],function(e,t,r,n,i,a,s){"use strict";function o(e,t,r){var n=e.length;x[e.join(".")]=t;for(var i in t)if(C.call(t,i)){var a=t[i];if(e[n]=i,a&&a.toString===h)a.toString=m(e.join(".")),a[P]=e.join(".");else if(a&&a.isNamespace){if(r[g(a)])continue;r[g(a)]=!0,o(e,a,r)}}e.length=n}function u(e,t){try{var r=e[t];return r&&r.isNamespace&&r}catch(n){}}function l(){var e,t=f.lookup;if(!w.PROCESSED)for(var r in t)O.test(r)&&(!t.hasOwnProperty||t.hasOwnProperty(r))&&(e=u(t,r),e&&(e[P]=r))}function c(e){var t=e.superclass;return t?t[P]?t[P]:c(t):void 0}function h(){f.BOOTED||this[P]||p();var e;if(this[P])e=this[P];else if(this._toString)e=this._toString;else{var t=c(this);e=t?"(subclass of "+t+")":"(unknown mixin)",this.toString=m(e)}return e}function p(){var e=!w.PROCESSED,t=f.anyUnprocessedMixins;if(e&&(l(),w.PROCESSED=!0),e||t){for(var r,n=w.NAMESPACES,i=0,a=n.length;a>i;i++)r=n[i],o([r.toString()],r,{});f.anyUnprocessedMixins=!1}}function m(e){return function(){return e}}var f=e["default"],d=t.get,v=r.indexOf,b=n.GUID_KEY,g=n.guidFor,y=i.Mixin,_=a["default"],w=_.extend({isNamespace:!0,init:function(){w.NAMESPACES.push(this),w.PROCESSED=!1},toString:function(){var e=d(this,"name");return e?e:(l(),this[P])},nameClasses:function(){o([this.toString()],this,{})},destroy:function(){var e=w.NAMESPACES,t=this.toString();t&&(f.lookup[t]=void 0,delete w.NAMESPACES_BY_ID[t]),e.splice(v.call(e,this),1),this._super()}});w.reopenClass({NAMESPACES:[f],NAMESPACES_BY_ID:{},PROCESSED:!1,processAll:p,byName:function(e){return f.BOOTED||p(),x[e]}});var x=w.NAMESPACES_BY_ID,C={}.hasOwnProperty,O=/^[A-Z]/,P=f.NAME_KEY=b+"_name";y.prototype.toString=h,s["default"]=w}),e("ember-runtime/system/native_array",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/enumerable_utils","ember-metal/mixin","ember-metal/array","ember-runtime/mixins/array","ember-runtime/mixins/mutable_array","ember-runtime/mixins/observable","ember-runtime/mixins/copyable","ember-runtime/mixins/freezable","ember-runtime/copy","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p){"use strict";var m=e["default"],f=t.get,d=(r.set,n._replace),v=n.forEach,b=i.Mixin,g=a.indexOf,y=a.lastIndexOf,_=s["default"],w=o["default"],x=u["default"],C=l["default"],O=c.FROZEN_ERROR,P=h["default"],E=b.create(w,x,C,{get:function(e){return"length"===e?this.length:"number"==typeof e?this[e]:this._super(e)},objectAt:function(e){return this[e]},replace:function(e,t,r){if(this.isFrozen)throw O;var n=r?f(r,"length"):0;return this.arrayContentWillChange(e,t,n),0===n?this.splice(e,t):d(this,e,t,r),this.arrayContentDidChange(e,t,n),this},unknownProperty:function(e,t){var r;return void 0!==t&&void 0===r&&(r=this[e]=t),r},indexOf:g,lastIndexOf:y,copy:function(e){return e?this.map(function(e){return P(e,!0)}):this.slice()}}),A=["length"];v(E.keys(),function(e){Array.prototype[e]&&A.push(e)}),A.length>0&&(E=E.without.apply(E,A));var T=function(e){return void 0===e&&(e=[]),_.detect(e)?e:E.apply(e)};E.activate=function(){E.apply(Array.prototype),T=function(e){return e||[]}},(m.EXTEND_PROTOTYPES===!0||m.EXTEND_PROTOTYPES.Array)&&E.activate(),m.A=T,p.A=T,p.NativeArray=E,p["default"]=E}),e("ember-runtime/system/object",["ember-runtime/system/core_object","ember-runtime/mixins/observable","exports"],function(e,t,r){"use strict";var n=e["default"],i=t["default"],a=n.extend(i);a.toString=function(){return"Ember.Object"},r["default"]=a}),e("ember-runtime/system/object_proxy",["ember-runtime/system/object","ember-runtime/mixins/-proxy","exports"],function(e,t,r){"use strict";var n=e["default"],i=t["default"];r["default"]=n.extend(i)}),e("ember-runtime/system/set",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/is_none","ember-runtime/system/string","ember-runtime/system/core_object","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","ember-runtime/mixins/copyable","ember-runtime/mixins/freezable","ember-metal/error","ember-metal/property_events","ember-metal/mixin","ember-metal/computed","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d){"use strict";var v=(e["default"],t.get),b=r.set,g=n.guidFor,y=i.isNone,_=a.fmt,w=s["default"],x=o["default"],C=u["default"],O=l["default"],P=c.Freezable,E=c.FROZEN_ERROR,A=h["default"],T=p.propertyWillChange,N=p.propertyDidChange,S=m.aliasMethod,V=f.computed;d["default"]=w.extend(x,O,P,{length:0,clear:function(){if(this.isFrozen)throw new A(E);var e=v(this,"length");if(0===e)return this;var t;this.enumerableContentWillChange(e,0),T(this,"firstObject"),T(this,"lastObject");for(var r=0;e>r;r++)t=g(this[r]),delete this[t],delete this[r];return b(this,"length",0),N(this,"firstObject"),N(this,"lastObject"),this.enumerableContentDidChange(e,0),this},isEqual:function(e){if(!C.detect(e))return!1;var t=v(this,"length");if(v(e,"length")!==t)return!1;for(;--t>=0;)if(!e.contains(this[t]))return!1;return!0},add:S("addObject"),remove:S("removeObject"),pop:function(){if(v(this,"isFrozen"))throw new A(E);var e=this.length>0?this[this.length-1]:null;return this.remove(e),e},push:S("addObject"),shift:S("pop"),unshift:S("push"),addEach:S("addObjects"),removeEach:S("removeObjects"),init:function(e){this._super(),e&&this.addObjects(e)},nextObject:function(e){return this[e]},firstObject:V(function(){return this.length>0?this[0]:void 0}),lastObject:V(function(){return this.length>0?this[this.length-1]:void 0}),addObject:function(e){if(v(this,"isFrozen"))throw new A(E);if(y(e))return this;var t,r=g(e),n=this[r],i=v(this,"length");return n>=0&&i>n&&this[n]===e?this:(t=[e],this.enumerableContentWillChange(null,t),T(this,"lastObject"),i=v(this,"length"),this[r]=i,this[i]=e,b(this,"length",i+1),N(this,"lastObject"),this.enumerableContentDidChange(null,t),this)},removeObject:function(e){if(v(this,"isFrozen"))throw new A(E);if(y(e))return this;var t,r,n=g(e),i=this[n],a=v(this,"length"),s=0===i,o=i===a-1;return i>=0&&a>i&&this[i]===e&&(r=[e],this.enumerableContentWillChange(r,null),s&&T(this,"firstObject"),o&&T(this,"lastObject"),a-1>i&&(t=this[a-1],this[i]=t,this[g(t)]=i),delete this[n],delete this[a-1],b(this,"length",a-1),s&&N(this,"firstObject"),o&&N(this,"lastObject"),this.enumerableContentDidChange(r,null)),this},contains:function(e){return this[g(e)]>=0},copy:function(){var e=this.constructor,t=new e,r=v(this,"length");for(b(t,"length",r);--r>=0;)t[r]=this[r],t[g(this[r])]=r;return t},toString:function(){var e,t=this.length,r=[];for(e=0;t>e;e++)r[e]=this[e];return _("Ember.Set<%@>",[r.join(",")])}})}),e("ember-runtime/system/string",["ember-metal/core","ember-metal/utils","ember-metal/cache","exports"],function(e,t,r,n){"use strict";function i(e,t){var r=t;if(!f(r)||arguments.length>2){r=new Array(arguments.length-1);for(var n=1,i=arguments.length;i>n;n++)r[n-1]=arguments[n]}var a=0;return e.replace(/%@([0-9]+)?/g,function(e,t){return t=t?parseInt(t,10)-1:a++,e=r[t],null===e?"(null)":void 0===e?"":d(e)})}function a(e,t){return(!f(t)||arguments.length>2)&&(t=Array.prototype.slice.call(arguments,1)),e=m.STRINGS[e]||e,i(e,t)}function s(e){return e.split(/\s+/)}function o(e){return C.get(e)}function u(e){return g.get(e)}function l(e){return y.get(e)}function c(e){return _.get(e)}function h(e){return w.get(e)}function p(e){return x.get(e)}var m=e["default"],f=t.isArray,d=t.inspect,v=r["default"],b=/[ _]/g,g=new v(1e3,function(e){return o(e).replace(b,"-")}),y=new v(1e3,function(e){return e.replace(P,function(e,t,r){return r?r.toUpperCase():""}).replace(/^([A-Z])/,function(e){return e.toLowerCase()})}),_=new v(1e3,function(e){for(var t=e.split("."),r=[],n=0,i=t.length;i>n;n++){var a=l(t[n]);r.push(a.charAt(0).toUpperCase()+a.substr(1))}return r.join(".")}),w=new v(1e3,function(e){return e.replace(E,"$1_$2").replace(A,"_").toLowerCase()}),x=new v(1e3,function(e){return e.charAt(0).toUpperCase()+e.substr(1)}),C=new v(1e3,function(e){return e.replace(O,"$1_$2").toLowerCase()}),O=/([a-z\d])([A-Z])/g,P=/(\-|_|\.|\s)+(.)?/g,E=/([a-z\d])([A-Z]+)/g,A=/\-|\s+/g;m.STRINGS={},n["default"]={fmt:i,loc:a,w:s,decamelize:o,dasherize:u,camelize:l,classify:c,underscore:h,capitalize:p},n.fmt=i,n.loc=a,n.w=s,n.decamelize=o,n.dasherize=u,n.camelize=l,n.classify=c,n.underscore=h,n.capitalize=p}),e("ember-runtime/system/subarray",["ember-metal/property_get","ember-metal/error","ember-metal/enumerable_utils","exports"],function(e,t,r,n){"use strict";function i(e,t){this.type=e,this.count=t}function a(e){arguments.length<1&&(e=0),this._operations=e>0?[new i(u,e)]:[]}var s=(e.get,t["default"]),o=r["default"],u="r",l="f";n["default"]=a,a.prototype={addItem:function(e,t){var r=-1,n=t?u:l,a=this;return this._findOperation(e,function(s,o,l,c,h){var p,m;n===s.type?++s.count:e===l?a._operations.splice(o,0,new i(n,1)):(p=new i(n,1),m=new i(s.type,c-e+1),s.count=e-l,a._operations.splice(o+1,0,p,m)),t&&(r=s.type===u?h+(e-l):h),a._composeAt(o)},function(e){a._operations.push(new i(n,1)),t&&(r=e),a._composeAt(a._operations.length-1)}),r},removeItem:function(e){var t=-1,r=this;return this._findOperation(e,function(n,i,a,s,o){n.type===u&&(t=o+(e-a)),n.count>1?--n.count:(r._operations.splice(i,1),r._composeAt(i))},function(){throw new s("Can't remove an item that has never been added.")}),t},_findOperation:function(e,t,r){var n,i,a,s,o,l=0;for(n=s=0,i=this._operations.length;i>n;s=o+1,++n){if(a=this._operations[n],o=s+a.count-1,e>=s&&o>=e)return void t(a,n,s,o,l);a.type===u&&(l+=a.count) +}r(l)},_composeAt:function(e){var t,r=this._operations[e];r&&(e>0&&(t=this._operations[e-1],t.type===r.type&&(r.count+=t.count,this._operations.splice(e-1,1),--e)),er)){var n,a,o=this._findArrayOperation(e),u=o.operation,c=o.index,h=o.rangeStart;a=new i(l,r,t),u?o.split?(this._split(c,e-h,a),n=c+1):(this._operations.splice(c,0,a),n=c):(this._operations.push(a),n=c),this._composeInsert(n)}},removeItems:function(e,t){if(!(1>t)){var r,n,a=this._findArrayOperation(e),s=(a.operation,a.index),o=a.rangeStart;return r=new i(c,t),a.split?(this._split(s,e-o,r),n=s+1):(this._operations.splice(s,0,r),n=s),this._composeDelete(n)}},apply:function(e){var t=[],r=0;o(this._operations,function(n,i){e(n.items,r,n.type,i),n.type!==c&&(r+=n.count,t=t.concat(n.items))}),this._operations=[new i(u,t.length,t)]},_findArrayOperation:function(e){var t,r,n,i,s,o=!1;for(t=n=0,s=this._operations.length;s>t;++t)if(r=this._operations[t],r.type!==c){if(i=n+r.count-1,e===n)break;if(e>n&&i>=e){o=!0;break}n=i+1}return new a(r,t,o,n)},_split:function(e,t,r){var n=this._operations[e],a=n.items.slice(t),s=new i(n.type,a.length,a);n.count=t,n.items=n.items.slice(0,t),this._operations.splice(e+1,0,r,s)},_composeInsert:function(e){var t=this._operations[e],r=this._operations[e-1],n=this._operations[e+1],i=r&&r.type,a=n&&n.type;i===l?(r.count+=t.count,r.items=r.items.concat(t.items),a===l?(r.count+=n.count,r.items=r.items.concat(n.items),this._operations.splice(e,2)):this._operations.splice(e,1)):a===l&&(t.count+=n.count,t.items=t.items.concat(n.items),this._operations.splice(e+1,1))},_composeDelete:function(e){var t,r,n,i=this._operations[e],a=i.count,s=this._operations[e-1],o=s&&s.type,u=!1,h=[];o===c&&(i=s,e-=1);for(var p=e+1;a>0;++p)t=this._operations[p],r=t.type,n=t.count,r!==c?(n>a?(h=h.concat(t.items.splice(0,a)),t.count-=a,p-=1,n=a,a=0):(n===a&&(u=!0),h=h.concat(t.items),a-=n),r===l&&(i.count-=n)):i.count+=n;return i.count>0?this._operations.splice(e+1,p-1-e):this._operations.splice(e,u?2:1),h},toString:function(){var e="";return o(this._operations,function(t){e+=" "+t.type+":"+t.count}),e.substring(1)}}}),e("ember-testing",["ember-metal/core","ember-testing/initializers","ember-testing/support","ember-testing/setup_for_testing","ember-testing/test","ember-testing/adapters/adapter","ember-testing/adapters/qunit","ember-testing/helpers"],function(e,t,r,n,i,a,s){"use strict";var o=e["default"],u=n["default"],l=i["default"],c=a["default"],h=s["default"];o.Test=l,o.Test.Adapter=c,o.Test.QUnitAdapter=h,o.setupForTesting=u}),e("ember-testing/adapters/adapter",["ember-metal/core","ember-metal/utils","ember-runtime/system/object","exports"],function(e,t,r,n){"use strict";var i=e["default"],a=(t.inspect,r["default"]),s=a.extend({asyncStart:i.K,asyncEnd:i.K,exception:function(e){throw e}});n["default"]=s}),e("ember-testing/adapters/qunit",["ember-testing/adapters/adapter","ember-metal/utils","exports"],function(e,t,r){"use strict";var n=e["default"],i=t.inspect;r["default"]=n.extend({asyncStart:function(){QUnit.stop()},asyncEnd:function(){QUnit.start()},exception:function(e){ok(!1,i(e))}})}),e("ember-testing/helpers",["ember-metal/property_get","ember-metal/error","ember-metal/run_loop","ember-views/system/jquery","ember-testing/test"],function(e,t,r,n,i){"use strict";function a(e){var t=e.__container__.lookup("controller:application");return b(t,"currentRouteName")}function s(e){var t=e.__container__.lookup("controller:application");return b(t,"currentPath")}function o(e){var t=e.__container__.lookup("router:main");return b(t,"location").getURL()}function u(e,t){var r=e.__container__.lookup("router:main");return r.location.setURL(t),e._readinessDeferrals>0?(r.initialURL=t,y(e,"advanceReadiness"),delete r.initialURL):y(e,e.handleURL,t),e.testHelpers.wait()}function l(e,t,r){var n=e.testHelpers.findWithAssert(t,r);if(y(n,"mousedown"),n.is(":input")){var i=n.prop("type");"checkbox"!==i&&"radio"!==i&&"hidden"!==i&&y(n,function(){!document.hasFocus||document.hasFocus()?this.focus():this.trigger("focusin")})}return y(n,"mouseup"),y(n,"click"),e.testHelpers.wait()}function c(e,t,r,n,i){var a,s,o,u=arguments.length;3===u?(a=null,s=r,o={}):4===u?"object"==typeof n?(a=null,s=r,o=n):(a=r,s=n,o={}):(a=r,s=n,o=i);var l=e.testHelpers.findWithAssert(t,a),c=_.Event(s,o);return y(l,"trigger",c),e.testHelpers.wait()}function h(e,t,r,n,i){var a,s;return"undefined"==typeof i?(a=null,i=n,s=r):(a=r,s=n),e.testHelpers.triggerEvent(t,a,s,{keyCode:i,which:i})}function p(e,t,r,n){var i,a;return"undefined"==typeof n?n=r:a=r,i=e.testHelpers.findWithAssert(t,a),y(function(){i.val(n).change()}),e.testHelpers.wait()}function m(e,t,r){var n=e.testHelpers.find(t,r);if(0===n.length)throw new g("Element "+t+" not found.");return n}function f(e,t,r){var n;return r=r||b(e,"rootElement"),n=e.$(t,r)}function d(e,t){return e.testHelpers.wait(t(e))}function v(e,t){return w.promise(function(r){1===++O&&w.adapter.asyncStart();var n=setInterval(function(){var i=!!e.__container__.lookup("router:main").router.activeTransition;i||w.pendingAjaxRequests||y.hasScheduledTimers()||y.currentRunLoop||w.waiters&&w.waiters.any(function(e){var t=e[0],r=e[1];return!r.call(t)})||(clearInterval(n),0===--O&&w.adapter.asyncEnd(),y(null,r,t))},10)})}var b=e.get,g=t["default"],y=r["default"],_=n["default"],w=i["default"],x=w.registerHelper,C=w.registerAsyncHelper,O=0;C("visit",u),C("click",l),C("keyEvent",h),C("fillIn",p),x("find",f),x("findWithAssert",m),C("wait",v),C("andThen",d),x("currentRouteName",a),x("currentPath",s),x("currentURL",o),C("triggerEvent",c)}),e("ember-testing/initializers",["ember-runtime/system/lazy_load"],function(e){"use strict";var t=e.onLoad,r="deferReadiness in `testing` mode";t("Ember.Application",function(e){e.initializers[r]||e.initializer({name:r,initialize:function(e,t){t.testing&&t.deferReadiness()}})})}),e("ember-testing/setup_for_testing",["ember-metal/core","ember-testing/adapters/qunit","ember-views/system/jquery","exports"],function(e,r,n,i){"use strict";function a(e,t){u.push(t),o.pendingAjaxRequests=u.length}function s(e,t){for(var r=0;r').css({position:"absolute",left:"-1000px",top:"-1000px"}).appendTo("body").on("click",e).trigger("click").remove()}var n=(e["default"],t["default"]),i=n;i(function(){r(function(){this.checked||i.event.special.click||(i.event.special.click={trigger:function(){return i.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0}})}),r(function(){})})}),e("ember-testing/test",["ember-metal/core","ember-metal/run_loop","ember-metal/platform","ember-runtime/compare","ember-runtime/ext/rsvp","ember-testing/setup_for_testing","ember-application/system/application","exports"],function(e,t,r,n,i,a,s,o){"use strict";function u(e,t){var r=_[t].method,n=_[t].meta;return function(){var t=y.call(arguments),i=x.lastPromise;return t.unshift(e),n.wait?(i?l(function(){i=x.resolve(i).then(function(){return r.apply(e,t)})}):i=r.apply(e,t),i):r.apply(e,t)}}function l(e){m.currentRunLoop?e():m(e)}function c(e,t,r,n){e[t]=function(){var e=arguments;return n?r.apply(this,e):this.then(function(){return r.apply(this,e)})}}function h(e,t){var r,n;return x.lastPromise=null,r=e(t),n=x.lastPromise,r&&r instanceof x.Promise||!n?r:(l(function(){n=x.resolve(n).then(function(){return r})}),n)}var p=e["default"],m=t["default"],f=r.create,d=n["default"],v=i["default"],b=a["default"],g=s["default"],y=[].slice,_={},w=[],x={_helpers:_,registerHelper:function(e,t){_[e]={method:t,meta:{wait:!1}}},registerAsyncHelper:function(e,t){_[e]={method:t,meta:{wait:!0}}},unregisterHelper:function(e){delete _[e],delete x.Promise.prototype[e]},onInjectHelpers:function(e){w.push(e)},promise:function(e){return new x.Promise(e)},adapter:null,resolve:function(e){return x.promise(function(t){return t(e)})},registerWaiter:function(e,t){1===arguments.length&&(t=e,e=null),this.waiters||(this.waiters=p.A()),this.waiters.push([e,t])},unregisterWaiter:function(e,t){var r;this.waiters&&(1===arguments.length&&(t=e,e=null),r=[e,t],this.waiters=p.A(this.waiters.filter(function(e){return 0!==d(e,r)})))}};g.reopen({testHelpers:{},originalMethods:{},testing:!1,setupForTesting:function(){b(),this.testing=!0,this.Router.reopen({location:"none"})},helperContainer:window,injectTestHelpers:function(e){e&&(this.helperContainer=e),this.testHelpers={};for(var t in _)this.originalMethods[t]=this.helperContainer[t],this.testHelpers[t]=this.helperContainer[t]=u(this,t),c(x.Promise.prototype,t,u(this,t),_[t].meta.wait);for(var r=0,n=w.length;n>r;r++)w[r](this)},removeTestHelpers:function(){for(var e in _)this.helperContainer[e]=this.originalMethods[e],delete this.testHelpers[e],delete this.originalMethods[e]}}),x.Promise=function(){v.Promise.apply(this,arguments),x.lastPromise=this},x.Promise.prototype=f(v.Promise.prototype),x.Promise.prototype.constructor=x.Promise;var C=v.Promise.prototype.then;x.Promise.prototype.then=function(e,t){return C.call(this,function(t){return h(e,t)},t)},o["default"]=x}),e("ember-views",["ember-runtime","ember-views/system/jquery","ember-views/system/utils","ember-views/system/render_buffer","ember-views/system/ext","ember-views/views/states","ember-views/views/core_view","ember-views/views/view","ember-views/views/container_view","ember-views/views/collection_view","ember-views/views/component","ember-views/system/event_dispatcher","ember-views/mixins/view_target_action_support","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m){"use strict";var f=e["default"],d=t["default"],v=r.isSimpleClick,b=n["default"],g=a.cloneStates,y=a.states,_=s["default"],w=o["default"],x=u["default"],C=l["default"],O=c["default"],P=h["default"],E=p["default"];f.$=d,f.ViewTargetActionSupport=E,f.RenderBuffer=b;var A=f.ViewUtils={};A.isSimpleClick=v,f.CoreView=_,f.View=w,f.View.states=y,f.View.cloneStates=g,f.ContainerView=x,f.CollectionView=C,f.Component=O,f.EventDispatcher=P,m["default"]=f}),e("ember-views/mixins/component_template_deprecation",["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"],function(e,t,r,n){"use strict";var i=(e["default"],t.get),a=r.Mixin;n["default"]=a.create({willMergeMixin:function(e){this._super.apply(this,arguments);var t,r,n=e.layoutName||e.layout||i(this,"layoutName");e.templateName&&!n&&(t="templateName",r="layoutName",e.layoutName=e.templateName,delete e.templateName),e.template&&!n&&(t="template",r="layout",e.layout=e.template,delete e.template)}})}),e("ember-views/mixins/view_target_action_support",["ember-metal/mixin","ember-runtime/mixins/target_action_support","ember-metal/computed","exports"],function(e,t,r,n){"use strict";var i=e.Mixin,a=t["default"],s=r.computed,o=s.alias;n["default"]=i.create(a,{target:o("controller"),actionContext:o("context")})}),e("ember-views/system/action_manager",["exports"],function(e){"use strict";function t(){}t.registeredActions={},e["default"]=t}),e("ember-views/system/event_dispatcher",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/object","ember-views/system/jquery","ember-views/system/action_manager","ember-views/views/view","ember-metal/merge","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p){"use strict";var m=(e["default"],t.get),f=r.set,d=n.isNone,v=i["default"],b=a.typeOf,g=(s.fmt,o["default"]),y=u["default"],_=l["default"],w=c["default"],x=h["default"];p["default"]=g.extend({events:{touchstart:"touchStart",touchmove:"touchMove",touchend:"touchEnd",touchcancel:"touchCancel",keydown:"keyDown",keyup:"keyUp",keypress:"keyPress",mousedown:"mouseDown",mouseup:"mouseUp",contextmenu:"contextMenu",click:"click",dblclick:"doubleClick",mousemove:"mouseMove",focusin:"focusIn",focusout:"focusOut",mouseenter:"mouseEnter",mouseleave:"mouseLeave",submit:"submit",input:"input",change:"change",dragstart:"dragStart",drag:"drag",dragenter:"dragEnter",dragleave:"dragLeave",dragover:"dragOver",drop:"drop",dragend:"dragEnd"},rootElement:"body",canDispatchToEventManager:!0,setup:function(e,t){var r,n=m(this,"events");x(n,e||{}),d(t)||f(this,"rootElement",t),t=y(m(this,"rootElement")),t.addClass("ember-application");for(r in n)n.hasOwnProperty(r)&&this.setupHandler(t,r,n[r])},setupHandler:function(e,t,r){var n=this;e.on(t+".ember",".ember-view",function(e,t){var i=w.views[this.id],a=!0,s=n.canDispatchToEventManager?n._findNearestEventManager(i,r):null;return s&&s!==t?a=n._dispatchEvent(s,e,r,i):i&&(a=n._bubbleEvent(i,e,r)),a}),e.on(t+".ember","[data-ember-action]",function(e){var t=y(e.currentTarget).attr("data-ember-action"),n=_.registeredActions[t];return n&&n.eventName===r?n.handler(e):void 0})},_findNearestEventManager:function(e,t){for(var r=null;e&&(r=m(e,"eventManager"),!r||!r[t]);)e=m(e,"parentView");return r},_dispatchEvent:function(e,t,r,n){var i=!0,a=e[r];return"function"===b(a)?(i=v(e,a,t,n),t.stopPropagation()):i=this._bubbleEvent(n,t,r),i},_bubbleEvent:function(e,t,r){return v(e,e.handleEvent,r,t)},destroy:function(){var e=m(this,"rootElement");return y(e).off(".ember","**").removeClass("ember-application"),this._super()},toString:function(){return"(EventDispatcher)"}})}),e("ember-views/system/ext",["ember-metal/run_loop"],function(e){"use strict";{var t=e["default"];t.queues}t._addQueue("render","actions"),t._addQueue("afterRender","render")}),e("ember-views/system/jquery",["ember-metal/core","ember-runtime/system/string","ember-metal/enumerable_utils","exports"],function(e,t,n,i){"use strict";var a=e["default"],s=t.w,o=n.forEach,u=a.imports&&a.imports.jQuery||this&&this.jQuery;if(u||"function"!=typeof r||(u=r("jquery")),u){var l=s("dragstart drag dragenter dragleave dragover drop dragend");o(l,function(e){u.event.fixHooks[e]={props:["dataTransfer"]}})}i["default"]=u}),e("ember-views/system/render_buffer",["ember-views/system/jquery","morph","ember-metal/core","exports"],function(e,t,r,n){"use strict";function i(e,t){if("TABLE"===t.tagName){var r=p.exec(e);if(r)return h[r[1].toLowerCase()]}}function a(){this.seen={},this.list=[]}function s(e){return e&&m.test(e)?e.replace(f,""):e}function o(e){var t={"<":"<",">":">",'"':""","'":"'","`":"`"},r=function(e){return t[e]||"&"},n=e.toString();return v.test(n)?n.replace(d,r):n}function u(e,t){this.tagName=e,this._contextualElement=t,this.buffer=null,this.childViews=[],this.dom=new c}var l=e["default"],c=t.DOMHelper,h=(r["default"],{tr:document.createElement("tbody"),col:document.createElement("colgroup")}),p=/(?:"'`]/g,v=/[&<>"'`]/,b=function(){var e=document.createElement("div"),t=document.createElement("input");return t.setAttribute("name","foo"),e.appendChild(t),!!e.innerHTML.match("foo")}();n["default"]=function(e,t){return new u(e,t)},u.prototype={reset:function(e,t){this.tagName=e,this.buffer=null,this._element=null,this._contextualElement=t,this.elementClasses=null,this.elementId=null,this.elementAttributes=null,this.elementProperties=null,this.elementTag=null,this.elementStyle=null,this.childViews.length=0},_element:null,_contextualElement:null,elementClasses:null,classes:null,elementId:null,elementAttributes:null,elementProperties:null,elementTag:null,elementStyle:null,pushChildView:function(e){var t=this.childViews.length;this.childViews[t]=e,this.push("")},hydrateMorphs:function(e){for(var t=this.childViews,r=this._element,n=0,i=t.length;i>n;n++){var a=t[n],s=r.querySelector("#morph-"+n),o=s.parentNode;a._morph=this.dom.insertMorphBefore(o,s,1===o.nodeType?o:e),o.removeChild(s)}},push:function(e){return null===this.buffer&&(this.buffer=""),this.buffer+=e,this},addClass:function(e){return this.elementClasses=this.elementClasses||new a,this.elementClasses.add(e),this.classes=this.elementClasses.list,this},setClasses:function(e){this.elementClasses=null;var t,r=e.length;for(t=0;r>t;t++)this.addClass(e[t])},id:function(e){return this.elementId=e,this},attr:function(e,t){var r=this.elementAttributes=this.elementAttributes||{};return 1===arguments.length?r[e]:(r[e]=t,this)},removeAttr:function(e){var t=this.elementAttributes;return t&&delete t[e],this},prop:function(e,t){var r=this.elementProperties=this.elementProperties||{};return 1===arguments.length?r[e]:(r[e]=t,this)},removeProp:function(e){var t=this.elementProperties;return t&&delete t[e],this},style:function(e,t){return this.elementStyle=this.elementStyle||{},this.elementStyle[e]=t,this},generateElement:function(){var e,t,r,n=this.tagName,i=this.elementId,a=this.classes,u=this.elementAttributes,c=this.elementProperties,h=this.elementStyle,p="";r=u&&u.name&&!b?"<"+s(n)+' name="'+o(u.name)+'">':n;var m=this.dom.createElement(r,this._contextualElement),f=l(m);if(i&&(this.dom.setAttribute(m,"id",i),this.elementId=null),a&&(this.dom.setAttribute(m,"class",a.join(" ")),this.classes=null,this.elementClasses=null),h){for(t in h)h.hasOwnProperty(t)&&(p+=t+":"+h[t]+";");this.dom.setAttribute(m,"style",p),this.elementStyle=null}if(u){for(e in u)u.hasOwnProperty(e)&&this.dom.setAttribute(m,e,u[e]);this.elementAttributes=null}if(c){for(t in c)c.hasOwnProperty(t)&&f.prop(t,c[t]);this.elementProperties=null}this._element=m},element:function(){this._contextualElement||(this._contextualElement=document.body);var e,t=this.innerString();if(this._element){if(t){for(this.dom.detectNamespace(this._element),e=this.dom.parseHTML(t,this._element);e[0];)this._element.appendChild(e[0]);this.hydrateMorphs(this._element)}}else if(t){var r=i(t,this._contextualElement),n=r||this._contextualElement;this.dom.detectNamespace(n),e=this.dom.parseHTML(t,n);for(var a=this._element=document.createDocumentFragment();e[0];)a.appendChild(e[0]);this.hydrateMorphs(n)}else""===t&&(this._element=t);return this._element},string:function(){if(this._element){var e=this.element(),t=e.outerHTML;return"undefined"==typeof t?l("
    ").append(e).html():t}return this.innerString()},innerString:function(){return this.buffer}}}),e("ember-views/system/renderer",["ember-metal-views/renderer","ember-metal/platform","ember-views/system/render_buffer","ember-metal/run_loop","ember-metal/property_set","ember-metal/instrumentation","exports"],function(e,t,r,n,i,a,s){"use strict";function o(){this.buffer=c(),u.call(this)}var u=e["default"],l=t.create,c=r["default"],h=n["default"],p=i.set,m=a._instrumentStart,f=a.subscribers;o.prototype=l(u.prototype),o.prototype.constructor=o;o.prototype.scheduleRender=function(e,t){return h.scheduleOnce("render",e,t)},o.prototype.cancelRender=function(e){h.cancel(e)},o.prototype.createChildViewsMorph=function(e,t){if(e.createChildViewsMorph)return e.createChildViewsMorph(t);var r=t;return""===e.tagName?e._morph?e._childViewsMorph=e._morph:(r=document.createDocumentFragment(),e._childViewsMorph=this._dom.appendMorph(r)):e._childViewsMorph=this._dom.createMorph(r,r.lastChild,null),r},o.prototype.createElement=function(e,t){var r=e.tagName;(null===r||void 0===r)&&(r="div");var n=e.buffer=this.buffer;n.reset(r,t),e.beforeRender&&e.beforeRender(n),""!==e.tagName&&(e.applyAttributesToBuffer&&e.applyAttributesToBuffer(n),n.generateElement()),e.render&&e.render(n),e.afterRender&&e.afterRender(n);var i=n.element();return e.isContainer&&this.createChildViewsMorph(e,i),e.buffer=null,i&&1===i.nodeType&&p(e,"element",i),i},o.prototype.destroyView=function(e){e.removedFromDOM=!0,e.destroy()},o.prototype.childViews=function(e){return e._childViews},u.prototype.willCreateElement=function(e){f.length&&e.instrumentDetails&&(e._instrumentEnd=m("render."+e.instrumentName,function(){var t={};return e.instrumentDetails(t),t})),e._transitionTo&&e._transitionTo("inBuffer")},u.prototype.didCreateElement=function(e){e._transitionTo&&e._transitionTo("hasElement"),e._instrumentEnd&&e._instrumentEnd()},u.prototype.willInsertElement=function(e){e.trigger&&e.trigger("willInsertElement")},u.prototype.didInsertElement=function(e){e._transitionTo&&e._transitionTo("inDOM"),e.trigger&&e.trigger("didInsertElement")},u.prototype.willRemoveElement=function(){},u.prototype.willDestroyElement=function(e){e.trigger&&e.trigger("willDestroyElement"),e.trigger&&e.trigger("willClearRender")},u.prototype.didDestroyElement=function(e){p(e,"element",null),e._transitionTo&&e._transitionTo("preRender")},s["default"]=o}),e("ember-views/system/utils",["exports"],function(e){"use strict";function t(e){var t=e.shiftKey||e.metaKey||e.altKey||e.ctrlKey,r=e.which>1;return!t&&!r}e.isSimpleClick=t}),e("ember-views/views/collection_view",["ember-metal/core","ember-metal/platform","ember-metal/binding","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-views/views/container_view","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-handlebars/ext","ember-runtime/mixins/array","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m){"use strict";var f=(e["default"],t.create,r.isGlobalPath),d=(n["default"],i.get),v=a.set,b=(s.fmt,o["default"]),g=u["default"],y=l["default"],_=c.observer,w=c.beforeObserver,x=h.handlebarsGetView,C=(p["default"],b.extend({content:null,emptyViewClass:y,emptyView:null,itemViewClass:y,init:function(){var e=this._super();return this._contentDidChange(),e},_contentWillChange:w("content",function(){var e=this.get("content");e&&e.removeArrayObserver(this);var t=e?d(e,"length"):0;this.arrayWillChange(e,0,t)}),_contentDidChange:_("content",function(){var e=d(this,"content");e&&(this._assertArrayLike(e),e.addArrayObserver(this));var t=e?d(e,"length"):0;this.arrayDidChange(e,0,null,t)}),_assertArrayLike:function(){},destroy:function(){if(this._super()){var e=d(this,"content");return e&&e.removeArrayObserver(this),this._createdEmptyView&&this._createdEmptyView.destroy(),this}},arrayWillChange:function(e,t,r){var n=d(this,"emptyView");n&&n instanceof y&&n.removeFromParent();var i,a,s=this._childViews;for(a=t+r-1;a>=t;a--)i=s[a],i.destroy()},arrayDidChange:function(e,t,r,n){var i,a,s,o,u,l,c=[];if(o=e?d(e,"length"):0)for(u=d(this,"itemViewClass"),u=x(e,u,this.container),s=t;t+n>s;s++)a=e.objectAt(s),i=this.createChildView(u,{content:a,contentIndex:s}),c.push(i);else{if(l=d(this,"emptyView"),!l)return;"string"==typeof l&&f(l)&&(l=d(l)||l),l=this.createChildView(l),c.push(l),v(this,"emptyView",l),g.detect(l)&&(this._createdEmptyView=l)}this.replace(t,0,c)},createChildView:function(e,t){e=this._super(e,t);var r=d(e,"tagName");return(null===r||void 0===r)&&(r=C.CONTAINER_MAP[d(this,"tagName")],v(e,"tagName",r)),e}}));C.CONTAINER_MAP={ul:"li",ol:"li",table:"tr",thead:"tr",tbody:"tr",tfoot:"tr",tr:"td",select:"option"},m["default"]=C}),e("ember-views/views/component",["ember-metal/core","ember-views/mixins/component_template_deprecation","ember-runtime/mixins/target_action_support","ember-views/views/view","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/computed","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";var l=e["default"],c=t["default"],h=r["default"],p=n["default"],m=i.get,f=a.set,d=(s.isNone,o.computed),v=Array.prototype.slice,b=p.extend(h,c,{instrumentName:"component",instrumentDisplay:d(function(){return this._debugContainerKey?"{{"+this._debugContainerKey.split(":")[1]+"}}":void 0}),init:function(){this._super(),f(this,"origContext",m(this,"context")),f(this,"context",this),f(this,"controller",this)},defaultLayout:function(e,t){l.Handlebars.helpers["yield"].call(e,t)},template:d(function(e,t){if(void 0!==t)return t;var r=m(this,"templateName"),n=this.templateForName(r,"template");return n||m(this,"defaultTemplate")}).property("templateName"),templateName:null,cloneKeywords:function(){return{view:this,controller:this}},_yield:function(e,t){var r=t.data.view,n=this._parentView,i=m(this,"template");i&&r.appendChild(p,{isVirtual:!0,tagName:"",_contextView:n,template:i,context:t.data.insideGroup?m(this,"origContext"):m(n,"context"),controller:m(n,"controller"),templateData:{keywords:n.cloneKeywords(),insideGroup:t.data.insideGroup}})},targetObject:d(function(){var e=m(this,"_parentView");return e?m(e,"controller"):null}).property("_parentView"),sendAction:function(e){var t,r=v.call(arguments,1);t=void 0===e?m(this,"action"):m(this,e),void 0!==t&&this.triggerAction({action:t,actionContext:r})}});u["default"]=b}),e("ember-views/views/container_view",["ember-metal/core","ember-metal/merge","ember-runtime/mixins/mutable_array","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/states","ember-metal/error","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/run_loop","ember-metal/properties","ember-views/system/render_buffer","ember-metal/mixin","ember-runtime/system/native_array","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d){"use strict";var v=e["default"],b=t["default"],g=r["default"],y=n.get,_=i.set,w=a["default"],x=s.cloneStates,C=s.states,O=o["default"],P=u.forEach,E=l.computed,A=c["default"],T=h.defineProperty,N=(p["default"],m.observer),S=m.beforeObserver,V=(f.A,x(C)),k=w.extend(g,{isContainer:!0,_states:V,willWatchProperty:function(){},init:function(){this._super();var e=y(this,"childViews");T(this,"childViews",w.childViewsProperty);var t=this._childViews;P(e,function(e,r){var n;"string"==typeof e?(n=y(this,e),n=this.createChildView(n),_(this,e,n)):n=this.createChildView(e),t[r]=n},this);var r=y(this,"currentView");r&&(t.length||(t=this._childViews=this._childViews.slice()),t.push(this.createChildView(r)))},replace:function(e,t,r){var n=r?y(r,"length"):0;if(this.arrayContentWillChange(e,t,n),this.childViewsWillChange(this._childViews,e,t),0===n)this._childViews.splice(e,t);else{var i=[e,t].concat(r);r.length&&!this._childViews.length&&(this._childViews=this._childViews.slice()),this._childViews.splice.apply(this._childViews,i)}return this.arrayContentDidChange(e,t,n),this.childViewsDidChange(this._childViews,e,t,n),this},objectAt:function(e){return this._childViews[e]},length:E(function(){return this._childViews.length})["volatile"](),render:function(){},instrumentName:"container",childViewsWillChange:function(e,t,r){if(this.propertyWillChange("childViews"),r>0){var n=e.slice(t,t+r);this.currentState.childViewsWillChange(this,e,t,r),this.initializeViews(n,null,null)}},removeChild:function(e){return this.removeObject(e),this},childViewsDidChange:function(e,t,r,n){if(n>0){var i=e.slice(t,t+n);this.initializeViews(i,this,y(this,"templateData")),this.currentState.childViewsDidChange(this,e,t,n)}this.propertyDidChange("childViews")},initializeViews:function(e,t,r){P(e,function(e){_(e,"_parentView",t),!e.container&&t&&_(e,"container",t.container),y(e,"templateData")||_(e,"templateData",r)})},currentView:null,_currentViewWillChange:S("currentView",function(){var e=y(this,"currentView");e&&e.destroy()}),_currentViewDidChange:N("currentView",function(){var e=y(this,"currentView");e&&this.pushObject(e)}),_ensureChildrenAreInDOM:function(){this.currentState.ensureChildrenAreInDOM(this)}});b(V._default,{childViewsWillChange:v.K,childViewsDidChange:v.K,ensureChildrenAreInDOM:v.K}),b(V.inBuffer,{childViewsDidChange:function(){throw new O("You cannot modify child views while in the inBuffer state")}}),b(V.hasElement,{childViewsWillChange:function(e,t,r,n){for(var i=r;r+n>i;i++)t[i].remove()},childViewsDidChange:function(e){A.scheduleOnce("render",e,"_ensureChildrenAreInDOM")},ensureChildrenAreInDOM:function(e){var t,r,n,i=e._childViews,a=e._renderer;for(t=0,r=i.length;r>t;t++)n=i[t],n._elementCreated||a.renderTree(n,e,t)}}),d["default"]=k}),e("ember-views/views/core_view",["ember-views/system/renderer","ember-views/views/states","ember-runtime/system/object","ember-runtime/mixins/evented","ember-runtime/mixins/action_handler","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/instrumentation","exports"],function(e,t,r,n,a,s,o,u,l,c,h){"use strict";var p=e["default"],m=t.cloneStates,f=t.states,d=r["default"],v=n["default"],b=a["default"],g=s.get,y=(o.set,u.computed),_=l.typeOf,w=(c.instrument,d.extend(v,b,{isView:!0,isVirtual:!1,isContainer:!1,_states:m(f),init:function(){this._super(),this._transitionTo("preRender"),this._isVisible=g(this,"isVisible")},parentView:y("_parentView",function(){var e=this._parentView;return e&&e.isVirtual?g(e,"parentView"):e}),_state:null,_parentView:null,concreteView:y("parentView",function(){return this.isVirtual?g(this,"parentView.concreteView"):this}),instrumentName:"core_view",instrumentDetails:function(e){e.object=this.toString(),e.containerKey=this._debugContainerKey,e.view=this},trigger:function(){this._super.apply(this,arguments);var e=arguments[0],t=this[e];if(t){for(var r=arguments.length,n=new Array(r-1),i=1;r>i;i++)n[i-1]=arguments[i];return t.apply(this,n)}},has:function(e){return"function"===_(this[e])||this._super(e)},destroy:function(){var e=this._parentView;if(this._super())return!this.removedFromDOM&&this._renderer&&this._renderer.remove(this,!0),e&&e.removeChild(this),this._transitionTo("destroying",!1),this},clearRenderedChildren:i.K,_transitionTo:i.K,destroyElement:i.K}));w.reopenClass({renderer:new p}),h["default"]=w}),e("ember-views/views/states",["ember-metal/platform","ember-metal/merge","ember-views/views/states/default","ember-views/views/states/pre_render","ember-views/views/states/in_buffer","ember-views/views/states/has_element","ember-views/views/states/in_dom","ember-views/views/states/destroying","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(e){var t={};t._default={},t.preRender=c(t._default),t.destroying=c(t._default),t.inBuffer=c(t._default),t.hasElement=c(t._default),t.inDOM=c(t.hasElement);for(var r in e)e.hasOwnProperty(r)&&h(t[r],e[r]);return t}var c=e.create,h=t["default"],p=r["default"],m=n["default"],f=i["default"],d=a["default"],v=s["default"],b=o["default"];u.cloneStates=l;var g={_default:p,preRender:m,inDOM:v,inBuffer:f,hasElement:d,destroying:b};u.states=g}),e("ember-views/views/states/default",["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/error","exports"],function(e,t,r,n,i,a){"use strict";var s=e["default"],o=(t.get,r.set,n["default"],i["default"]);a["default"]={appendChild:function(){throw new o("You can't use appendChild outside of the rendering process")},$:function(){return void 0},getElement:function(){return null},handleEvent:function(){return!0},destroyElement:function(e){return e._renderer&&e._renderer.remove(e,!1),e},rerender:s.K,invokeObserver:s.K} +}),e("ember-views/views/states/destroying",["ember-metal/merge","ember-metal/platform","ember-runtime/system/string","ember-views/views/states/default","ember-metal/error","exports"],function(e,t,r,n,i,a){"use strict";var s=e["default"],o=t.create,u=r.fmt,l=n["default"],c=i["default"],h="You can't call %@ on a view being destroyed",p=o(l);s(p,{appendChild:function(){throw new c(u(h,["appendChild"]))},rerender:function(){throw new c(u(h,["rerender"]))},destroyElement:function(){throw new c(u(h,["destroyElement"]))}}),a["default"]=p}),e("ember-views/views/states/has_element",["ember-views/views/states/default","ember-metal/run_loop","ember-metal/merge","ember-metal/platform","ember-views/system/jquery","ember-metal/error","ember-metal/property_get","ember-metal/property_set","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";var l=e["default"],c=t["default"],h=r["default"],p=n.create,m=i["default"],f=a["default"],d=s.get,v=(o.set,p(l));h(v,{$:function(e,t){var r=e.get("concreteView").element;return t?m(t,r):m(r)},getElement:function(e){var t=d(e,"parentView");return t&&(t=d(t,"element")),t?e.findElementInParentElement(t):m("#"+d(e,"elementId"))[0]},rerender:function(e){if(e._root._morph&&!e._elementInserted)throw new f("Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.");c.scheduleOnce("render",function(){e.isDestroying||e._renderer.renderTree(e,e._parentView)})},destroyElement:function(e){return e._renderer.remove(e,!1),e},handleEvent:function(e,t,r){return e.has(t)?e.trigger(t,r):!0},invokeObserver:function(e,t){t.call(e)}}),u["default"]=v}),e("ember-views/views/states/in_buffer",["ember-views/views/states/default","ember-metal/error","ember-metal/core","ember-metal/platform","ember-metal/merge","exports"],function(e,t,r,n,i,a){"use strict";var s=e["default"],o=t["default"],u=r["default"],l=n.create,c=i["default"],h=l(s);c(h,{$:function(e){return e.rerender(),u.$()},rerender:function(){throw new o("Something you did caused a view to re-render after it rendered but before it was inserted into the DOM.")},appendChild:function(e,t,r){var n=e.buffer,i=e._childViews;return t=e.createChildView(t,r),i.length||(i=e._childViews=i.slice()),i.push(t),t._morph||n.pushChildView(t),e.propertyDidChange("childViews"),t},invokeObserver:function(e,t){t.call(e)}}),a["default"]=h}),e("ember-views/views/states/in_dom",["ember-metal/core","ember-metal/platform","ember-metal/merge","ember-metal/error","ember-views/views/states/has_element","exports"],function(e,r,n,i,a,s){"use strict";var o,u=(e["default"],r.create),l=n["default"],c=i["default"],h=a["default"],p=u(h);l(p,{enter:function(e){o||(o=t("ember-views/views/view")["default"]),e.isVirtual||(o.views[e.elementId]=e),e.addBeforeObserver("elementId",function(){throw new c("Changing a view's elementId after creation is not allowed")})},exit:function(e){o||(o=t("ember-views/views/view")["default"]),this.isVirtual||delete o.views[e.elementId]}}),s["default"]=p}),e("ember-views/views/states/pre_render",["ember-views/views/states/default","ember-metal/platform","ember-metal/merge","ember-views/system/jquery","exports"],function(e,t,r,n,i){"use strict";var a=e["default"],s=t.create,o=(r["default"],n["default"],s(a));i["default"]=o}),e("ember-views/views/view",["ember-metal/core","ember-runtime/mixins/evented","ember-runtime/system/object","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/set_properties","ember-metal/run_loop","ember-metal/observer","ember-metal/properties","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/is_none","ember-metal/deprecate_property","ember-runtime/system/native_array","ember-runtime/system/string","ember-metal/enumerable_utils","ember-runtime/copy","ember-metal/binding","ember-metal/property_events","ember-views/system/jquery","ember-views/system/ext","ember-views/views/core_view","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v,b,g,y,_,w,x,C,O){"use strict";var P=e["default"],E=t["default"],A=r["default"],T=n["default"],N=i.get,S=a.set,V=s["default"],k=o["default"],I=u.addObserver,j=u.removeObserver,D=l.defineProperty,R=l.deprecateProperty,M=c.guidFor,L=(c.meta,h.computed),H=p.observer,z=c.typeOf,q=c.isArray,F=m.isNone,B=p.Mixin,R=f.deprecateProperty,U=d.A,K=v.dasherize,W=b.forEach,G=b.addObject,Q=b.removeObject,$=p.beforeObserver,Y=g["default"],J=y.isGlobalPath,Z=_.propertyWillChange,X=_.propertyDidChange,et=w["default"],tt=C["default"],rt=L(function(){var e=this._childViews,t=U();return W(e,function(e){var r;e.isVirtual?(r=N(e,"childViews"))&&t.pushObjects(r):t.push(e)}),t.replace=function(){throw new T("childViews is immutable")},t});P.TEMPLATES={};var nt=[],it=tt.extend({concatenatedProperties:["classNames","classNameBindings","attributeBindings"],isView:!0,templateName:null,layoutName:null,instrumentDisplay:L(function(){return this.helperName?"{{"+this.helperName+"}}":void 0}),template:L("templateName",function(e,t){if(void 0!==t)return t;var r=N(this,"templateName"),n=this.templateForName(r,"template");return n||N(this,"defaultTemplate")}),controller:L("_parentView",function(){var e=N(this,"_parentView");return e?N(e,"controller"):null}),layout:L(function(){var e=N(this,"layoutName"),t=this.templateForName(e,"layout");return t||N(this,"defaultLayout")}).property("layoutName"),_yield:function(e,t){var r=N(this,"template");r&&r(e,t)},templateForName:function(e){if(e){if(!this.container)throw new T("Container was not found when looking up a views template. This is most likely due to manually instantiating an Ember.View. See: http://git.io/EKPpnA");return this.container.lookup("template:"+e)}},context:L(function(e,t){return 2===arguments.length?(S(this,"_context",t),t):N(this,"_context")})["volatile"](),_context:L(function(){var e,t;return(t=N(this,"controller"))?t:(e=this._parentView,e?N(e,"_context"):null)}),_contextDidChange:H("context",function(){this.rerender()}),isVisible:!0,childViews:rt,_childViews:nt,_childViewsWillChange:$("childViews",function(){if(this.isVirtual){var e=N(this,"parentView");e&&Z(e,"childViews")}}),_childViewsDidChange:H("childViews",function(){if(this.isVirtual){var e=N(this,"parentView");e&&X(e,"childViews")}}),nearestInstanceOf:function(e){for(var t=N(this,"parentView");t;){if(t instanceof e)return t;t=N(t,"parentView")}},nearestOfType:function(e){for(var t=N(this,"parentView"),r=e instanceof B?function(t){return e.detect(t)}:function(t){return e.detect(t.constructor)};t;){if(r(t))return t;t=N(t,"parentView")}},nearestWithProperty:function(e){for(var t=N(this,"parentView");t;){if(e in t)return t;t=N(t,"parentView")}},nearestChildOf:function(e){for(var t=N(this,"parentView");t;){if(N(t,"parentView")instanceof e)return t;t=N(t,"parentView")}},_parentViewDidChange:H("_parentView",function(){this.isDestroying||(this.trigger("parentViewDidChange"),N(this,"parentView.controller")&&!N(this,"controller")&&this.notifyPropertyChange("controller"))}),_controllerDidChange:H("controller",function(){this.isDestroying||(this.rerender(),this.forEachChildView(function(e){e.propertyDidChange("controller")}))}),cloneKeywords:function(){var e=N(this,"templateData"),t=e?Y(e.keywords):{};return S(t,"view",this.isVirtual?t.view:this),S(t,"_view",this),S(t,"controller",N(this,"controller")),t},render:function(e){var t=N(this,"layout")||N(this,"template");if(t){var r,n=N(this,"context"),i=this.cloneKeywords(),a={view:this,buffer:e,isRenderData:!0,keywords:i,insideGroup:N(this,"templateData.insideGroup")};r=t(n,{data:a}),void 0!==r&&e.push(r)}},rerender:function(){return this.currentState.rerender(this)},_applyClassNameBindings:function(e){var t,r,n,i=this.classNames;W(e,function(e){var a,s=it._parsePropertyPath(e),o=function(){r=this._classStringForProperty(e),t=this.$(),a&&(t.removeClass(a),i.removeObject(a)),r?(t.addClass(r),a=r):a=null};n=this._classStringForProperty(e),n&&(G(i,n),a=n),this.registerObserver(this,s.path,o),this.one("willClearRender",function(){a&&(i.removeObject(a),a=null)})},this)},_unspecifiedAttributeBindings:null,_applyAttributeBindings:function(e,t){var r,n=this._unspecifiedAttributeBindings=this._unspecifiedAttributeBindings||{};W(t,function(t){var i=t.split(":"),a=i[0],s=i[1]||a;a in this?(this._setupAttributeBindingObservation(a,s),r=N(this,a),it.applyAttributeBindings(e,s,r)):n[a]=s},this),this.setUnknownProperty=this._setUnknownProperty},_setupAttributeBindingObservation:function(e,t){var r,n,i=function(){n=this.$(),r=N(this,e),it.applyAttributeBindings(n,t,r)};this.registerObserver(this,e,i)},setUnknownProperty:null,_setUnknownProperty:function(e,t){var r=this._unspecifiedAttributeBindings&&this._unspecifiedAttributeBindings[e];return r&&this._setupAttributeBindingObservation(e,r),D(this,e),S(this,e,t)},_classStringForProperty:function(e){var t=it._parsePropertyPath(e),r=t.path,n=N(this,r);return void 0===n&&J(r)&&(n=N(P.lookup,r)),it._classStringForValue(r,n,t.className,t.falsyClassName)},element:null,$:function(e){return this.currentState.$(this,e)},mutateChildViews:function(e){for(var t,r=this._childViews,n=r.length;--n>=0;)t=r[n],e(this,t,n);return this},forEachChildView:function(e){var t=this._childViews;if(!t)return this;var r,n,i=t.length;for(n=0;i>n;n++)r=t[n],e(r);return this},appendTo:function(e){var t=et(e);return this.constructor.renderer.appendTo(this,t[0]),this},replaceIn:function(e){var t=et(e);return this.constructor.renderer.replaceIn(this,t[0]),this},append:function(){return this.appendTo(document.body)},remove:function(){this.removedFromDOM||this.destroyElement()},elementId:null,findElementInParentElement:function(e){var t="#"+this.elementId;return et(t)[0]||et(t,e)[0]},createElement:function(){return this.element?this:(this._didCreateElementWithoutMorph=!0,this.constructor.renderer.renderTree(this),this)},willInsertElement:P.K,didInsertElement:P.K,willClearRender:P.K,destroyElement:function(){return this.currentState.destroyElement(this)},willDestroyElement:P.K,parentViewDidChange:P.K,instrumentName:"view",instrumentDetails:function(e){e.template=N(this,"templateName"),this._super(e)},beforeRender:function(){},afterRender:function(){},applyAttributesToBuffer:function(e){var t=N(this,"classNameBindings");t.length&&this._applyClassNameBindings(t);var r=N(this,"attributeBindings");r.length&&this._applyAttributeBindings(e,r),e.setClasses(this.classNames),e.id(this.elementId);var n=N(this,"ariaRole");n&&e.attr("role",n),N(this,"isVisible")===!1&&e.style("display","none")},tagName:null,ariaRole:null,classNames:["ember-view"],classNameBindings:nt,attributeBindings:nt,init:function(){this.isVirtual||this.elementId||(this.elementId=M(this)),this._super(),this._childViews=this._childViews.slice(),this.classNameBindings=U(this.classNameBindings.slice()),this.classNames=U(this.classNames.slice())},appendChild:function(e,t){return this.currentState.appendChild(this,e,t)},removeChild:function(e){if(!this.isDestroying){S(e,"_parentView",null);var t=this._childViews;return Q(t,e),this.propertyDidChange("childViews"),this}},removeAllChildren:function(){return this.mutateChildViews(function(e,t){e.removeChild(t)})},destroyAllChildren:function(){return this.mutateChildViews(function(e,t){t.destroy()})},removeFromParent:function(){var e=this._parentView;return this.remove(),e&&e.removeChild(this),this},destroy:function(){var e=(this._childViews,N(this,"parentView")),t=this.viewName;return this._super()?(t&&e&&e.set(t,null),this):void 0},createChildView:function(e,t){if(!e)throw new TypeError("createChildViews first argument must exist");if(e.isView&&e._parentView===this&&e.container===this.container)return e;if(t=t||{},t._parentView=this,tt.detect(e))t.templateData=t.templateData||N(this,"templateData"),t.container=this.container,e=e.create(t),e.viewName&&S(N(this,"concreteView"),e.viewName,e);else if("string"==typeof e){var r="view:"+e,n=this.container.lookupFactory(r);t.templateData=N(this,"templateData"),e=n.create(t)}else t.container=this.container,N(e,"templateData")||(t.templateData=N(this,"templateData")),V(e,t);return e},becameVisible:P.K,becameHidden:P.K,_isVisibleDidChange:H("isVisible",function(){this._isVisible!==N(this,"isVisible")&&k.scheduleOnce("render",this,this._toggleVisibility)}),_toggleVisibility:function(){var e=this.$(),t=N(this,"isVisible");this._isVisible!==t&&(this._isVisible=t,e&&(e.toggle(t),this._isAncestorHidden()||(t?this._notifyBecameVisible():this._notifyBecameHidden())))},_notifyBecameVisible:function(){this.trigger("becameVisible"),this.forEachChildView(function(e){var t=N(e,"isVisible");(t||null===t)&&e._notifyBecameVisible()})},_notifyBecameHidden:function(){this.trigger("becameHidden"),this.forEachChildView(function(e){var t=N(e,"isVisible");(t||null===t)&&e._notifyBecameHidden()})},_isAncestorHidden:function(){for(var e=N(this,"parentView");e;){if(N(e,"isVisible")===!1)return!0;e=N(e,"parentView")}return!1},transitionTo:function(e,t){this._transitionTo(e,t)},_transitionTo:function(e){var t=this.currentState,r=this.currentState=this._states[e];this._state=e,t&&t.exit&&t.exit(this),r.enter&&r.enter(this)},handleEvent:function(e,t){return this.currentState.handleEvent(this,e,t)},registerObserver:function(e,t,r,n){if(n||"function"!=typeof r||(n=r,r=null),e&&"object"==typeof e){var i=this,a=function(){i.currentState.invokeObserver(this,n)},s=function(){k.scheduleOnce("render",this,a)};I(e,t,r,s),this.one("willClearRender",function(){j(e,t,r,s)})}}});R(it.prototype,"state","_state"),R(it.prototype,"states","_states"),it.reopenClass({_parsePropertyPath:function(e){var t,r,n=e.split(":"),i=n[0],a="";return n.length>1&&(t=n[1],3===n.length&&(r=n[2]),a=":"+t,r&&(a+=":"+r)),{path:i,classNames:a,className:""===t?void 0:t,falsyClassName:r}},_classStringForValue:function(e,t,r,n){if(q(t)&&(t=0!==N(t,"length")),r||n)return r&&t?r:n&&!t?n:null;if(t===!0){var i=e.split(".");return K(i[i.length-1])}return t!==!1&&null!=t?t:null}});var at=A.extend(E).create();it.addMutationListener=function(e){at.on("change",e)},it.removeMutationListener=function(e){at.off("change",e)},it.notifyMutationListeners=function(){at.trigger("change")},it.views={},it.childViewsProperty=rt,it.applyAttributeBindings=function(e,t,r){var n=z(r);"value"===t||"string"!==n&&("number"!==n||isNaN(r))?"value"===t||"boolean"===n?F(r)||r===!1?(e.removeAttr(t),"required"===t?e.removeProp(t):e.prop(t,"")):r!==e.prop(t)&&e.prop(t,r):r||e.removeAttr(t):r!==e.attr(t)&&e.attr(t,r)},O["default"]=it}),e("ember",["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"],function(){"use strict";i.__loader.registry["ember-testing"]&&t("ember-testing")}),e("morph",["./morph/morph","./morph/dom-helper","exports"],function(e,t,r){"use strict";var n,n=e["default"];r.Morph=n;var i,i=t["default"];r.DOMHelper=i}),e("morph/dom-helper",["../morph/morph","./dom-helper/build-html-dom","exports"],function(e,t,r){"use strict";function n(e){return e===c}function i(e){return e&&e.namespaceURI===c&&!h[e.tagName]?c:null}function a(e,t){if("TABLE"===t.tagName){var r=f.exec(e);if(r){var n=r[1];return"tr"===n||"col"===n}}}function s(e,t){var r=t.document.createElement("div");return r.innerHTML=""+e+"",r.firstChild.childNodes}function o(e){this.document=e||window.document,this.namespace=null}var u=e["default"],l=t.buildHTMLDOM,c=t.svgNamespace,h=t.svgHTMLIntegrationPoints,p=function(){var e=document.createElement("div");e.appendChild(document.createTextNode(""));var t=e.cloneNode(!0);return 0===t.childNodes.length}(),m=function(){var e=document.createElement("input");e.setAttribute("checked","checked");var t=e.cloneNode(!1);return!t.checked}(),f=/<([\w:]+)/,d=o.prototype;d.constructor=o,d.insertBefore=function(e,t,r){return e.insertBefore(t,r)},d.appendChild=function(e,t){return e.appendChild(t)},d.appendText=function(e,t){return e.appendChild(this.document.createTextNode(t))},d.setAttribute=function(e,t,r){e.setAttribute(t,r)},d.createElement=document.createElementNS?function(e,t){var r=this.namespace;return t&&(r="svg"===e?c:i(t)),r?this.document.createElementNS(r,e):this.document.createElement(e)}:function(e){return this.document.createElement(e)},d.setNamespace=function(e){this.namespace=e},d.detectNamespace=function(e){this.namespace=i(e)},d.createDocumentFragment=function(){return this.document.createDocumentFragment()},d.createTextNode=function(e){return this.document.createTextNode(e)},d.repairClonedNode=function(e,t,r){if(p&&t.length>0)for(var n=0,i=t.length;i>n;n++){var a=this.document.createTextNode(""),s=t[n],o=e.childNodes[s];o?e.insertBefore(a,o):e.appendChild(a)}m&&r&&e.setAttribute("checked","checked")},d.cloneNode=function(e,t){var r=e.cloneNode(!!t);return r},d.createMorph=function(e,t,r,n){return n||1!==e.nodeType||(n=e),new u(e,t,r,this,n)},d.createMorphAt=function(e,t,r,n){var i=e.childNodes,a=-1===t?null:i[t],s=-1===r?null:i[r];return this.createMorph(e,a,s,n)},d.insertMorphBefore=function(e,t,r){var n=this.document.createTextNode(""),i=this.document.createTextNode("");return e.insertBefore(n,t),e.insertBefore(i,t),this.createMorph(e,n,i,r)},d.appendMorph=function(e,t){var r=this.document.createTextNode(""),n=this.document.createTextNode("");return e.appendChild(r),e.appendChild(n),this.createMorph(e,r,n,t)},d.parseHTML=function(e,t){var r=n(this.namespace)&&!h[t.tagName];if(r)return s(e,this);var i=l(e,t,this);if(a(e,t)){for(var o=i[0];o&&1!==o.nodeType;)o=o.nextSibling;return o.childNodes}return i},r["default"]=o}),e("morph/dom-helper/build-html-dom",["exports"],function(e){"use strict";function t(e,t){t="­"+t,e.innerHTML=t;for(var r=e.childNodes,n=r[0];1===n.nodeType&&!n.nodeName;)n=n.firstChild;if(3===n.nodeType&&"­"===n.nodeValue.charAt(0)){var i=n.nodeValue.slice(1);i.length?n.nodeValue=n.nodeValue.slice(1):n.parentNode.removeChild(n)}return r}function r(e,r){var n=r.tagName,i=r.outerHTML||(new XMLSerializer).serializeToString(r);if(!i)throw"Can't set innerHTML on "+n+" in this browser";for(var s=a[n.toLowerCase()],o=i.match(new RegExp("<"+n+"([^>]*)>","i"))[0],u="",l=[o,e,u],c=s.length,h=1+c;c--;)l.unshift("<"+s[c]+">"),l.push("");var p=document.createElement("div");t(p,l.join(""));for(var m=p;h--;)for(m=m.firstChild;m&&1!==m.nodeType;)m=m.nextSibling;for(;m&&m.tagName!==n;)m=m.nextSibling;return m?m.childNodes:[]}var n={foreignObject:1,desc:1,title:1};e.svgHTMLIntegrationPoints=n;var i="http://www.w3.org/2000/svg";e.svgNamespace=i;var a,s,o=document.createElementNS&&function(){var e=document.createElementNS(i,"foreignObject");return e.innerHTML="
    ",0===e.childNodes.length}(),u=function(){var e=document.createElement("div");return e.innerHTML="
    ",e.firstChild.innerHTML="",""===e.firstChild.innerHTML}(),l=document&&function(){var e=document.createElement("div");return e.innerHTML="Test: Value","Test:"===e.childNodes[0].nodeValue&&" Value"===e.childNodes[2].nodeValue}(),c=document.createElement("table");try{c.innerHTML="
    "}catch(h){}finally{s=0===c.childNodes.length}a=s?{colgroup:["table"],table:[],tbody:["table"],tfoot:["table"],thead:["table"],tr:["table","tbody"]}:{};var p=document.createElement("select");p.innerHTML="",p&&(a.select=[]);var m;m=u?function(e,r,n){return r=n.cloneNode(r,!1),t(r,e),r.childNodes}:function(e,t,r){return t=r.cloneNode(t,!1),t.innerHTML=e,t.childNodes};var f;f=a.length>0||l?function(e,t,n){var i=[],s=[];e=e.replace(/(\s*)()(\s*)/g,function(e,t,r){return s.push(r),t});var o;o=a[t.tagName.toLowerCase()]?r(e,t):m(e,t,n);var u,l,c,h,p=[];for(u=0;c=o[u];u++)if(1===c.nodeType)if("SCRIPT"===c.tagName)p.push(c);else for(h=c.getElementsByTagName("script"),l=0;l0&&(f=n.document.createTextNode(d),scriptNode.parentNode.insertBefore(f,scriptNode)),v=s[u],v&&v.length>0&&(f=n.document.createTextNode(v),scriptNode.parentNode.insertBefore(f,scriptNode.nextSibling));return o}:o?function(e,t,r){return n[t.tagName]?m(e,document.createElement("div"),r):m(e,t,r)}:m,e.buildHTMLDOM=f}),e("morph/morph",["exports"],function(e){"use strict";function t(e,t){if(null===e||null===t)throw new Error("a fragment parent must have boundary nodes in order to detect insertion")}function r(e){if(!e||1!==e.nodeType)throw new Error("An element node must be provided for a contextualElement, you provided "+(e?"nodeType "+e.nodeType:"nothing"))}function n(e,n,i,a,s){11===e.nodeType?(t(n,i),this.element=null):this.element=e,this._parent=e,this.start=n,this.end=i,this.domHelper=a,r(s),this.contextualElement=s,this.reset()}function i(e,t,r){for(var n,i=t,a=r.length;a--;)n=r[a],e.insertBefore(n,i),i=n}function a(e,t,r){var n,i;for(n=null===r?e.lastChild:r.previousSibling;null!==n&&n!==t;)i=n.previousSibling,e.removeChild(n),n=i}var s=Array.prototype.splice;n.prototype.reset=function(){this.text=null,this.owner=null,this.morphs=null,this.before=null,this.after=null,this.escaped=!0},n.prototype.parent=function(){if(!this.element){var e=this.start.parentNode;this._parent!==e&&(this.element=this._parent=e)}return this._parent},n.prototype.destroy=function(){this.owner?this.owner.removeMorph(this):a(this.element||this.parent(),this.start,this.end)},n.prototype.removeMorph=function(e){for(var t=this.morphs,r=0,n=t.length;n>r;r++)if(t[r]===e){this.replace(r,1);break}},n.prototype.update=function(e){this._update(this.element||this.parent(),e)},n.prototype.updateNode=function(e){var t=this.element||this.parent();return e?void this._updateNode(t,e):this._updateText(t,"")},n.prototype.updateText=function(e){this._updateText(this.element||this.parent(),e)},n.prototype.updateHTML=function(e){var t=this.element||this.parent();return e?void this._updateHTML(t,e):this._updateText(t,"")},n.prototype._update=function(e,t){null===t||void 0===t?this._updateText(e,""):"string"==typeof t?this.escaped?this._updateText(e,t):this._updateHTML(e,t):t.nodeType?this._updateNode(e,t):t.string?this._updateHTML(e,t.string):this._updateText(e,t.toString())},n.prototype._updateNode=function(e,t){if(this.text){if(3===t.nodeType)return void(this.text.nodeValue=t.nodeValue);this.text=null}var r=this.start,n=this.end;a(e,r,n),e.insertBefore(t,n),null!==this.before&&(this.before.end=r.nextSibling),null!==this.after&&(this.after.start=n.previousSibling)},n.prototype._updateText=function(e,t){if(this.text)return void(this.text.nodeValue=t);var r=this.domHelper.createTextNode(t);this.text=r,a(e,this.start,this.end),e.insertBefore(r,this.end),null!==this.before&&(this.before.end=r),null!==this.after&&(this.after.start=r)},n.prototype._updateHTML=function(e,t){var r=this.start,n=this.end;a(e,r,n),this.text=null;var s=this.domHelper.parseHTML(t,this.contextualElement);i(e,n,s),null!==this.before&&(this.before.end=r.nextSibling),null!==this.after&&(this.after.start=n.previousSibling)},n.prototype.append=function(e){null===this.morphs&&(this.morphs=[]);var t=this.morphs.length;return this.insert(t,e)},n.prototype.insert=function(e,t){null===this.morphs&&(this.morphs=[]);var r=this.element||this.parent(),i=this.morphs,a=e>0?i[e-1]:null,s=e0?c[e-1]:null,p=e+t0&&a(l,m,f),0===d)return null!==h&&(h.after=p,h.end=f),null!==p&&(p.before=h,p.start=m),void c.splice(e,t);if(i=new Array(d+2),d>0){for(o=0;d>o;o++)i[o+2]=u=new n(l,m,f,this.domHelper,this.contextualElement),u._update(l,r[o]),u.owner=this,null!==h&&(u.before=h,h.end=m.nextSibling,h.after=u),h=u,m=null===f?l.lastChild:f.previousSibling;null!==p&&(u.after=p,p.before=u,p.start=f.previousSibling)}i[0]=e,i[1]=t,s.apply(c,i)},e["default"]=n}),e("route-recognizer",["route-recognizer/dsl","exports"],function(e,t){"use strict";function r(e){return"[object Array]"===Object.prototype.toString.call(e)}function n(e){this.string=e}function i(e){this.name=e}function a(e){this.name=e}function s(){}function o(e,t,r){"/"===e.charAt(0)&&(e=e.substr(1));for(var o=e.split("/"),u=[],l=0,c=o.length;c>l;l++){var h,p=o[l];(h=p.match(/^:([^\/]+)$/))?(u.push(new i(h[1])),t.push(h[1]),r.dynamics++):(h=p.match(/^\*([^\/]+)$/))?(u.push(new a(h[1])),t.push(h[1]),r.stars++):""===p?u.push(new s):(u.push(new n(p)),r.statics++)}return u}function u(e){this.charSpec=e,this.nextStates=[]}function l(e){return e.sort(function(e,t){if(e.types.stars!==t.types.stars)return e.types.stars-t.types.stars;if(e.types.stars){if(e.types.statics!==t.types.statics)return t.types.statics-e.types.statics;if(e.types.dynamics!==t.types.dynamics)return t.types.dynamics-e.types.dynamics}return e.types.dynamics!==t.types.dynamics?e.types.dynamics-t.types.dynamics:e.types.statics!==t.types.statics?t.types.statics-e.types.statics:0})}function c(e,t){for(var r=[],n=0,i=e.length;i>n;n++){var a=e[n];r=r.concat(a.match(t))}return r}function h(e){this.queryParams=e||{}}function p(e,t,r){for(var n=e.handlers,i=e.regex,a=t.match(i),s=1,o=new h(r),u=0,l=n.length;l>u;u++){for(var c=n[u],p=c.names,m={},f=0,d=p.length;d>f;f++)m[p[f]]=a[s++];o.push({handler:c.handler,params:m,isDynamic:!!p.length})}return o}function m(e,t){return t.eachChar(function(t){e=e.put(t)}),e}var f=e["default"],d=["/",".","*","+","?","|","(",")","[","]","{","}","\\"],v=new RegExp("(\\"+d.join("|\\")+")","g");n.prototype={eachChar:function(e){for(var t,r=this.string,n=0,i=r.length;i>n;n++)t=r.charAt(n),e({validChars:t})},regex:function(){return this.string.replace(v,"\\$1")},generate:function(){return this.string}},i.prototype={eachChar:function(e){e({invalidChars:"/",repeat:!0})},regex:function(){return"([^/]+)"},generate:function(e){return e[this.name]}},a.prototype={eachChar:function(e){e({invalidChars:"",repeat:!0})},regex:function(){return"(.+)"},generate:function(e){return e[this.name]}},s.prototype={eachChar:function(){},regex:function(){return""},generate:function(){return""}},u.prototype={get:function(e){for(var t=this.nextStates,r=0,n=t.length;n>r;r++){var i=t[r],a=i.charSpec.validChars===e.validChars;if(a=a&&i.charSpec.invalidChars===e.invalidChars)return i}},put:function(e){var t;return(t=this.get(e))?t:(t=new u(e),this.nextStates.push(t),e.repeat&&t.nextStates.push(t),t)},match:function(e){for(var t,r,n,i=this.nextStates,a=[],s=0,o=i.length;o>s;s++)t=i[s],r=t.charSpec,"undefined"!=typeof(n=r.validChars)?-1!==n.indexOf(e)&&a.push(t):"undefined"!=typeof(n=r.invalidChars)&&-1===n.indexOf(e)&&a.push(t);return a}};var b=Object.create||function(e){function t(){}return t.prototype=e,new t};h.prototype=b({splice:Array.prototype.splice,slice:Array.prototype.slice,push:Array.prototype.push,length:0,queryParams:null});var g=function(){this.rootState=new u,this.names={}};g.prototype={add:function(e,t){for(var r,n=this.rootState,i="^",a={statics:0,dynamics:0,stars:0},u=[],l=[],c=!0,h=0,p=e.length;p>h;h++){var f=e[h],d=[],v=o(f.path,d,a);l=l.concat(v);for(var b=0,g=v.length;g>b;b++){var y=v[b];y instanceof s||(c=!1,n=n.put({validChars:"/"}),i+="/",n=m(n,y),i+=y.regex())}var _={handler:f.handler,names:d};u.push(_)}c&&(n=n.put({validChars:"/"}),i+="/"),n.handlers=u,n.regex=new RegExp(i+"$"),n.types=a,(r=t&&t.as)&&(this.names[r]={segments:l,handlers:u})},handlersFor:function(e){var t=this.names[e],r=[];if(!t)throw new Error("There is no route named "+e);for(var n=0,i=t.handlers.length;i>n;n++)r.push(t.handlers[n]);return r},hasRoute:function(e){return!!this.names[e]},generate:function(e,t){var r=this.names[e],n="";if(!r)throw new Error("There is no route named "+e);for(var i=r.segments,a=0,o=i.length;o>a;a++){var u=i[a];u instanceof s||(n+="/",n+=u.generate(t))}return"/"!==n.charAt(0)&&(n="/"+n),t&&t.queryParams&&(n+=this.generateQueryString(t.queryParams,r.handlers)),n},generateQueryString:function(e){var t=[],n=[];for(var i in e)e.hasOwnProperty(i)&&n.push(i);n.sort();for(var a=0,s=n.length;s>a;a++){i=n[a];var o=e[i];if(null!=o){var u=encodeURIComponent(i);if(r(o))for(var l=0,c=o.length;c>l;l++){var h=i+"[]="+encodeURIComponent(o[l]);t.push(h)}else u+="="+encodeURIComponent(o),t.push(u)}}return 0===t.length?"":"?"+t.join("&")},parseQueryString:function(e){for(var t=e.split("&"),r={},n=0;n2&&"[]"===s.slice(o-2)&&(u=!0,s=s.slice(0,o-2),r[s]||(r[s]=[])),i=a[1]?decodeURIComponent(a[1]):""),u?r[s].push(i):r[s]=i}return r},recognize:function(e){var t,r,n,i,a=[this.rootState],s={},o=!1;if(i=e.indexOf("?"),-1!==i){var u=e.substr(i+1,e.length);e=e.substr(0,i),s=this.parseQueryString(u)}for(e=decodeURI(e),"/"!==e.charAt(0)&&(e="/"+e),t=e.length,t>1&&"/"===e.charAt(t-1)&&(e=e.substr(0,t-1),o=!0),r=0,n=e.length;n>r&&(a=c(a,e.charAt(r)),a.length);r++);var h=[];for(r=0,n=a.length;n>r;r++)a[r].handlers&&h.push(a[r]);a=l(h);var m=h[0];return m&&m.handlers?(o&&"(.+)$"===m.regex.source.slice(-5)&&(e+="/"),p(m,e,s)):void 0}},g.prototype.map=f,t["default"]=g}),e("route-recognizer/dsl",["exports"],function(e){"use strict";function t(e,t,r){this.path=e,this.matcher=t,this.delegate=r}function r(e){this.routes={},this.children={},this.target=e}function n(e,r,i){return function(a,s){var o=e+a;return s?void s(n(o,r,i)):new t(e+a,r,i)}}function i(e,t,r){for(var n=0,i=0,a=e.length;a>i;i++)n+=e[i].path.length;t=t.substr(n);var s={path:t,handler:r};e.push(s)}function a(e,t,r,n){var s=t.routes;for(var o in s)if(s.hasOwnProperty(o)){var u=e.slice();i(u,o,s[o]),t.children[o]?a(u,t.children[o],r,n):r.call(n,u)}}t.prototype={to:function(e,t){var r=this.delegate;if(r&&r.willAddRoute&&(e=r.willAddRoute(this.matcher.target,e)),this.matcher.add(this.path,e),t){if(0===t.length)throw new Error("You must have an argument in the function passed to `to`");this.matcher.addChild(this.path,e,t,this.delegate)}return this}},r.prototype={add:function(e,t){this.routes[e]=t},addChild:function(e,t,i,a){var s=new r(t);this.children[e]=s;var o=n(e,s,a);a&&a.contextEntered&&a.contextEntered(t,o),i(o)}},e["default"]=function(e,t){var i=new r;e(n("",i,this.delegate)),a([],i,function(e){t?t(this,e):this.add(e)},this)}}),e("router",["./router/router","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=r}),e("router/handler-info",["./utils","rsvp/promise","exports"],function(e,t,r){"use strict";function n(e){var t=e||{};s(this,t),this.initialize(t)}function i(e,t){if(!e^!t)return!1;if(!e)return!0;for(var r in e)if(e.hasOwnProperty(r)&&e[r]!==t[r])return!1;return!0}var a=e.bind,s=e.merge,o=(e.serialize,e.promiseLabel),u=e.applyHook,l=t["default"];n.prototype={name:null,handler:null,params:null,context:null,factory:null,initialize:function(){},log:function(e,t){e.log&&e.log(this.name+": "+t)},promiseLabel:function(e){return o("'"+this.name+"' "+e)},getUnresolved:function(){return this},serialize:function(){return this.params||{}},resolve:function(e,t){var r=a(this,this.checkForAbort,e),n=a(this,this.runBeforeModelHook,t),i=a(this,this.getModel,t),s=a(this,this.runAfterModelHook,t),o=a(this,this.becomeResolved,t);return l.resolve(void 0,this.promiseLabel("Start handler")).then(r,null,this.promiseLabel("Check for abort")).then(n,null,this.promiseLabel("Before model")).then(r,null,this.promiseLabel("Check if aborted during 'beforeModel' hook")).then(i,null,this.promiseLabel("Model")).then(r,null,this.promiseLabel("Check if aborted in 'model' hook")).then(s,null,this.promiseLabel("After model")).then(r,null,this.promiseLabel("Check if aborted in 'afterModel' hook")).then(o,null,this.promiseLabel("Become resolved")) +},runBeforeModelHook:function(e){return e.trigger&&e.trigger(!0,"willResolveModel",e,this.handler),this.runSharedModelHook(e,"beforeModel",[])},runAfterModelHook:function(e,t){var r=this.name;return this.stashResolvedModel(e,t),this.runSharedModelHook(e,"afterModel",[t]).then(function(){return e.resolvedModels[r]},null,this.promiseLabel("Ignore fulfillment value and return model value"))},runSharedModelHook:function(e,t,r){this.log(e,"calling "+t+" hook"),this.queryParams&&r.push(this.queryParams),r.push(e);var n=u(this.handler,t,r);return n&&n.isTransition&&(n=null),l.resolve(n,this.promiseLabel("Resolve value returned from one of the model hooks"))},getModel:null,checkForAbort:function(e,t){return l.resolve(e(),this.promiseLabel("Check for abort")).then(function(){return t},null,this.promiseLabel("Ignore fulfillment value and continue"))},stashResolvedModel:function(e,t){e.resolvedModels=e.resolvedModels||{},e.resolvedModels[this.name]=t},becomeResolved:function(e,t){var r=this.serialize(t);return e&&(this.stashResolvedModel(e,t),e.params=e.params||{},e.params[this.name]=r),this.factory("resolved",{context:t,name:this.name,handler:this.handler,params:r})},shouldSupercede:function(e){if(!e)return!0;var t=e.context===this.context;return e.name!==this.name||this.hasOwnProperty("context")&&!t||this.hasOwnProperty("params")&&!i(this.params,e.params)}},r["default"]=n}),e("router/handler-info/factory",["router/handler-info/resolved-handler-info","router/handler-info/unresolved-handler-info-by-object","router/handler-info/unresolved-handler-info-by-param","exports"],function(e,t,r,n){"use strict";function i(e,t){var r=i.klasses[e],n=new r(t||{});return n.factory=i,n}var a=e["default"],s=t["default"],o=r["default"];i.klasses={resolved:a,param:o,object:s},n["default"]=i}),e("router/handler-info/resolved-handler-info",["../handler-info","router/utils","rsvp/promise","exports"],function(e,t,r,n){"use strict";var i=e["default"],a=t.subclass,s=(t.promiseLabel,r["default"]),o=a(i,{resolve:function(e,t){return t&&t.resolvedModels&&(t.resolvedModels[this.name]=this.context),s.resolve(this,this.promiseLabel("Resolve"))},getUnresolved:function(){return this.factory("param",{name:this.name,handler:this.handler,params:this.params})},isResolved:!0});n["default"]=o}),e("router/handler-info/unresolved-handler-info-by-object",["../handler-info","router/utils","rsvp/promise","exports"],function(e,t,r,n){"use strict";var i=e["default"],a=(t.merge,t.subclass),s=(t.promiseLabel,t.isParam),o=r["default"],u=a(i,{getModel:function(e){return this.log(e,this.name+": resolving provided model"),o.resolve(this.context)},initialize:function(e){this.names=e.names||[],this.context=e.context},serialize:function(e){var t=e||this.context,r=this.names,n=this.handler,i={};if(s(t))return i[r[0]]=t,i;if(n.serialize)return n.serialize(t,r);if(1===r.length){var a=r[0];return i[a]=/_id$/.test(a)?t.id:t,i}}});n["default"]=u}),e("router/handler-info/unresolved-handler-info-by-param",["../handler-info","router/utils","exports"],function(e,t,r){"use strict";var n=e["default"],i=t.resolveHook,a=t.merge,s=t.subclass,o=(t.promiseLabel,s(n,{initialize:function(e){this.params=e.params||{}},getModel:function(e){var t=this.params;e&&e.queryParams&&(t={},a(t,this.params),t.queryParams=e.queryParams);var r=this.handler,n=i(r,"deserialize")||i(r,"model");return this.runSharedModelHook(e,n,[t])}}));r["default"]=o}),e("router/router",["route-recognizer","rsvp/promise","./utils","./transition-state","./transition","./transition-intent/named-transition-intent","./transition-intent/url-transition-intent","./handler-info","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(){this.recognizer=new w,this.reset()}function c(e,t){var r,n=!!this.activeTransition,i=n?this.activeTransition.state:this.state,a=e.applyToState(i,this.recognizer,this.getHandler,t),s=N(i.queryParams,a.queryParams);return g(a.handlerInfos,i.handlerInfos)?s&&(r=this.queryParamsTransition(s,n,i,a))?r:new j(this):t?void p(this,a):(r=new j(this,e,a),this.activeTransition&&this.activeTransition.abort(),this.activeTransition=r,r.promise=r.promise.then(function(e){return v(r,e.state)},null,S("Settle transition promise when transition is finalized")),n||_(this,a,r),h(this,a,s),r)}function h(e,t,r){r&&(e._changedQueryParams=r.all,C(e,t.handlerInfos,!0,["queryParamsDidChange",r.changed,r.all,r.removed]),e._changedQueryParams=null)}function p(e,t,r){var n=f(e.state,t);E(n.exited,function(e){var t=e.handler;delete t.context,V(t,"reset",!0,r),V(t,"exit",r)});var i=e.oldState=e.state;e.state=t;var a=e.currentHandlerInfos=n.unchanged.slice();try{E(n.reset,function(e){var t=e.handler;V(t,"reset",!1,r)}),E(n.updatedContext,function(e){return m(a,e,!1,r)}),E(n.entered,function(e){return m(a,e,!0,r)})}catch(s){throw e.state=i,e.currentHandlerInfos=i.handlerInfos,s}e.state.queryParams=y(e,a,t.queryParams,r)}function m(e,t,r,n){var i=t.handler,a=t.context;if(r&&V(i,"enter",n),n&&n.isAborted)throw new D;if(i.context=a,V(i,"contextDidChange"),V(i,"setup",a,n),n&&n.isAborted)throw new D;return e.push(t),!0}function f(e,t){var r,n,i,a=e.handlerInfos,s=t.handlerInfos,o={updatedContext:[],exited:[],entered:[],unchanged:[]},u=!1;for(n=0,i=s.length;i>n;n++){var l=a[n],c=s[n];l&&l.handler===c.handler||(r=!0),r?(o.entered.push(c),l&&o.exited.unshift(l)):u||l.context!==c.context?(u=!0,o.updatedContext.push(c)):o.unchanged.push(l)}for(n=s.length,i=a.length;i>n;n++)o.exited.unshift(a[n]);return o.reset=o.updatedContext.slice(),o.reset.reverse(),o}function d(e,t){var r=e.urlMethod;if(r){for(var n=e.router,i=t.handlerInfos,a=i[i.length-1].name,s={},o=i.length-1;o>=0;--o){var u=i[o];A(s,u.params),u.handler.inaccessibleByURL&&(r=null)}if(r){s.queryParams=e._visibleQueryParams||t.queryParams;var l=n.recognizer.generate(a,s);"replace"===r?n.replaceURL(l):n.updateURL(l)}}}function v(e,t){try{O(e.router,e.sequence,"Resolved all models on destination route; finalizing transition.");{var r=e.router,n=t.handlerInfos;e.sequence}return p(r,t,e),e.isAborted?(r.state.handlerInfos=r.currentHandlerInfos,x.reject(I(e))):(d(e,t,e.intent.url),e.isActive=!1,r.activeTransition=null,C(r,r.currentHandlerInfos,!0,["didTransition"]),r.didTransition&&r.didTransition(r.currentHandlerInfos),O(r,e.sequence,"TRANSITION COMPLETE."),n[n.length-1].handler)}catch(i){if(!(i instanceof D)){var a=e.state.handlerInfos;e.trigger(!0,"error",i,e,a[a.length-1].handler),e.abort()}throw i}}function b(e,t,r){var n=t[0]||"/",i=t[t.length-1],a={};i&&i.hasOwnProperty("queryParams")&&(a=L.call(t).queryParams);var s;if(0===t.length){O(e,"Updating query params");var o=e.state.handlerInfos;s=new R({name:o[o.length-1].name,contexts:[],queryParams:a})}else"/"===n.charAt(0)?(O(e,"Attempting URL transition to "+n),s=new M({url:n})):(O(e,"Attempting transition to "+n),s=new R({name:t[0],contexts:P.call(t,1),queryParams:a}));return e.transitionByIntent(s,r)}function g(e,t){if(e.length!==t.length)return!1;for(var r=0,n=e.length;n>r;++r)if(e[r]!==t[r])return!1;return!0}function y(e,t,r,n){for(var i in r)r.hasOwnProperty(i)&&null===r[i]&&delete r[i];var a=[];C(e,t,!0,["finalizeQueryParamChange",r,a,n]),n&&(n._visibleQueryParams={});for(var s={},o=0,u=a.length;u>o;++o){var l=a[o];s[l.key]=l.value,n&&l.visible!==!1&&(n._visibleQueryParams[l.key]=l.value)}return s}function _(e,t,r){var n,i,a,s,o,u,l=e.state.handlerInfos,c=[],h=null;for(s=l.length,a=0;s>a;a++){if(o=l[a],u=t.handlerInfos[a],!u||o.name!==u.name){h=a;break}u.isResolved||c.push(o)}null!==h&&(n=l.slice(h,s),i=function(e){for(var t=0,r=n.length;r>t;t++)if(n[t].name===e)return!0;return!1},e._triggerWillLeave(n,r,i)),c.length>0&&e._triggerWillChangeContext(c,r),C(e,l,!0,["willTransition",r])}var w=e["default"],x=t["default"],C=r.trigger,O=r.log,P=r.slice,E=r.forEach,A=r.merge,T=(r.serialize,r.extractQueryParams),N=r.getChangelist,S=r.promiseLabel,V=r.callHook,k=n["default"],I=i.logAbort,j=i.Transition,D=i.TransitionAborted,R=a["default"],M=s["default"],L=(o.ResolvedHandlerInfo,Array.prototype.pop);l.prototype={map:function(e){this.recognizer.delegate=this.delegate,this.recognizer.map(e,function(e,t){for(var r=t.length-1,n=!0;r>=0&&n;--r){var i=t[r];e.add(t,{as:i.handler}),n="/"===i.path||""===i.path||".index"===i.handler.slice(-6)}})},hasRoute:function(e){return this.recognizer.hasRoute(e)},queryParamsTransition:function(e,t,r,n){var i=this;if(h(this,n,e),!t&&this.activeTransition)return this.activeTransition;var a=new j(this);return a.queryParamsOnly=!0,r.queryParams=y(this,n.handlerInfos,n.queryParams,a),a.promise=a.promise.then(function(e){return d(a,r,!0),i.didTransition&&i.didTransition(i.currentHandlerInfos),e},null,S("Transition complete")),a},transitionByIntent:function(e){try{return c.apply(this,arguments)}catch(t){return new j(this,e,null,t)}},reset:function(){this.state&&E(this.state.handlerInfos.slice().reverse(),function(e){var t=e.handler;V(t,"exit")}),this.state=new k,this.currentHandlerInfos=null},activeTransition:null,handleURL:function(e){var t=P.call(arguments);return"/"!==e.charAt(0)&&(t[0]="/"+e),b(this,t).method(null)},updateURL:function(){throw new Error("updateURL is not implemented")},replaceURL:function(e){this.updateURL(e)},transitionTo:function(){return b(this,arguments)},intermediateTransitionTo:function(){return b(this,arguments,!0)},refresh:function(e){for(var t=this.activeTransition?this.activeTransition.state:this.state,r=t.handlerInfos,n={},i=0,a=r.length;a>i;++i){var s=r[i];n[s.name]=s.params||{}}O(this,"Starting a refresh transition");var o=new R({name:r[r.length-1].name,pivotHandler:e||r[0].handler,contexts:[],queryParams:this._changedQueryParams||t.queryParams||{}});return this.transitionByIntent(o,!1)},replaceWith:function(){return b(this,arguments).method("replace")},generate:function(e){for(var t=T(P.call(arguments,1)),r=t[0],n=t[1],i=new R({name:e,contexts:r}),a=i.applyToState(this.state,this.recognizer,this.getHandler),s={},o=0,u=a.handlerInfos.length;u>o;++o){var l=a.handlerInfos[o],c=l.serialize();A(s,c)}return s.queryParams=n,this.recognizer.generate(e,s)},applyIntent:function(e,t){var r=new R({name:e,contexts:t}),n=this.activeTransition&&this.activeTransition.state||this.state;return r.applyToState(n,this.recognizer,this.getHandler)},isActiveIntent:function(e,t,r){var n,i,a=this.state.handlerInfos;if(!a.length)return!1;var s=a[a.length-1].name,o=this.recognizer.handlersFor(s),u=0;for(i=o.length;i>u&&(n=a[u],n.name!==e);++u);if(u===o.length)return!1;var l=new k;l.handlerInfos=a.slice(0,u+1),o=o.slice(0,u+1);var c=new R({name:s,contexts:t}),h=c.applyToHandlers(l,o,this.getHandler,s,!0,!0),p=g(h.handlerInfos,l.handlerInfos);if(!r||!p)return p;var m={};A(m,r);var f=this.state.queryParams;for(var d in f)f.hasOwnProperty(d)&&m.hasOwnProperty(d)&&(m[d]=f[d]);return p&&!N(m,r)},isActive:function(e){var t=T(P.call(arguments,1));return this.isActiveIntent(e,t[0],t[1])},trigger:function(){var e=P.call(arguments);C(this,this.currentHandlerInfos,!1,e)},log:null,_willChangeContextEvent:"willChangeContext",_triggerWillChangeContext:function(e,t){C(this,e,!0,[this._willChangeContextEvent,t])},_triggerWillLeave:function(e,t,r){C(this,e,!0,["willLeave",t,r])}},u["default"]=l}),e("router/transition-intent",["./utils","exports"],function(e,t){"use strict";function r(e){this.initialize(e),this.data=this.data||{}}e.merge;r.prototype={initialize:null,applyToState:null},t["default"]=r}),e("router/transition-intent/named-transition-intent",["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"],function(e,t,r,n,i){"use strict";var a=e["default"],s=t["default"],o=r["default"],u=n.isParam,l=n.extractQueryParams,c=n.merge,h=n.subclass;i["default"]=h(a,{name:null,pivotHandler:null,contexts:null,queryParams:null,initialize:function(e){this.name=e.name,this.pivotHandler=e.pivotHandler,this.contexts=e.contexts||[],this.queryParams=e.queryParams},applyToState:function(e,t,r,n){var i=l([this.name].concat(this.contexts)),a=i[0],s=(i[1],t.handlersFor(a[0])),o=s[s.length-1].handler;return this.applyToHandlers(e,s,r,o,n)},applyToHandlers:function(e,t,r,n,i,a){var o,u,l=new s,h=this.contexts.slice(0),p=t.length;if(this.pivotHandler)for(o=0,u=t.length;u>o;++o)if(r(t[o].handler)===this.pivotHandler){p=o;break}!this.pivotHandler;for(o=t.length-1;o>=0;--o){var m=t[o],f=m.handler,d=r(f),v=e.handlerInfos[o],b=null;if(b=m.names.length>0?o>=p?this.createParamHandlerInfo(f,d,m.names,h,v):this.getHandlerInfoForDynamicSegment(f,d,m.names,h,v,n,o):this.createParamHandlerInfo(f,d,m.names,h,v),a){b=b.becomeResolved(null,b.context);var g=v&&v.context;m.names.length>0&&b.context===g&&(b.params=v&&v.params),b.context=g}var y=v;(o>=p||b.shouldSupercede(v))&&(p=Math.min(o,p),y=b),i&&!a&&(y=y.becomeResolved(null,y.context)),l.handlerInfos.unshift(y)}if(h.length>0)throw new Error("More context objects were passed than there are dynamic segments for the route: "+n);return i||this.invalidateChildren(l.handlerInfos,p),c(l.queryParams,this.queryParams||{}),l},invalidateChildren:function(e,t){for(var r=t,n=e.length;n>r;++r){{e[r]}e[r]=e[r].getUnresolved()}},getHandlerInfoForDynamicSegment:function(e,t,r,n,i,a,s){{var l;r.length}if(n.length>0){if(l=n[n.length-1],u(l))return this.createParamHandlerInfo(e,t,r,n,i);n.pop()}else{if(i&&i.name===e)return i;if(!this.preTransitionState)return i;var c=this.preTransitionState.handlerInfos[s];l=c&&c.context}return o("object",{name:e,handler:t,context:l,names:r})},createParamHandlerInfo:function(e,t,r,n,i){for(var a={},s=r.length;s--;){var l=i&&e===i.name&&i.params||{},c=n[n.length-1],h=r[s];if(u(c))a[h]=""+n.pop();else{if(!l.hasOwnProperty(h))throw new Error("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route "+e);a[h]=l[h]}}return o("param",{name:e,handler:t,params:a})}})}),e("router/transition-intent/url-transition-intent",["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"],function(e,t,r,n,i){"use strict";function a(e){this.message=e||"UnrecognizedURLError",this.name="UnrecognizedURLError"}var s=e["default"],o=t["default"],u=r["default"],l=(n.oCreate,n.merge),c=n.subclass;i["default"]=c(s,{url:null,initialize:function(e){this.url=e.url},applyToState:function(e,t,r){var n,i,s=new o,c=t.recognize(this.url);if(!c)throw new a(this.url);var h=!1;for(n=0,i=c.length;i>n;++n){var p=c[n],m=p.handler,f=r(m);if(f.inaccessibleByURL)throw new a(this.url);var d=u("param",{name:m,handler:f,params:p.params}),v=e.handlerInfos[n];h||d.shouldSupercede(v)?(h=!0,s.handlerInfos[n]=d):s.handlerInfos[n]=v}return l(s.queryParams,c.queryParams),s}})}),e("router/transition-state",["./handler-info","./utils","rsvp/promise","exports"],function(e,t,r,n){"use strict";function i(){this.handlerInfos=[],this.queryParams={},this.params={}}var a=(e.ResolvedHandlerInfo,t.forEach),s=t.promiseLabel,o=t.callHook,u=r["default"];i.prototype={handlerInfos:null,queryParams:null,params:null,promiseLabel:function(e){var t="";return a(this.handlerInfos,function(e){""!==t&&(t+="."),t+=e.name}),s("'"+t+"': "+e)},resolve:function(e,t){function r(){return u.resolve(e(),c.promiseLabel("Check if should continue"))["catch"](function(e){return h=!0,u.reject(e)},c.promiseLabel("Handle abort"))}function n(e){var r=c.handlerInfos,n=t.resolveIndex>=r.length?r.length-1:t.resolveIndex;return u.reject({error:e,handlerWithError:c.handlerInfos[n].handler,wasAborted:h,state:c})}function i(e){var n=c.handlerInfos[t.resolveIndex].isResolved;if(c.handlerInfos[t.resolveIndex++]=e,!n){var i=e.handler;o(i,"redirect",e.context,t)}return r().then(s,null,c.promiseLabel("Resolve handler"))}function s(){if(t.resolveIndex===c.handlerInfos.length)return{error:null,state:c};var e=c.handlerInfos[t.resolveIndex];return e.resolve(r,t).then(i,null,c.promiseLabel("Proceed"))}var l=this.params;a(this.handlerInfos,function(e){l[e.name]=e.params||{}}),t=t||{},t.resolveIndex=0;var c=this,h=!1;return u.resolve(null,this.promiseLabel("Start transition")).then(s,null,this.promiseLabel("Resolve handler"))["catch"](n,this.promiseLabel("Handle error"))}},n["default"]=i}),e("router/transition",["rsvp/promise","./handler-info","./utils","exports"],function(e,t,r,n){"use strict";function i(e,t,r,n){function s(){return u.isAborted?o.reject(void 0,h("Transition aborted - reject")):void 0}var u=this;if(this.state=r||e.state,this.intent=t,this.router=e,this.data=this.intent&&this.intent.data||{},this.resolvedModels={},this.queryParams={},n)return void(this.promise=o.reject(n));if(r){this.params=r.params,this.queryParams=r.queryParams,this.handlerInfos=r.handlerInfos;var l=r.handlerInfos.length;l&&(this.targetName=r.handlerInfos[l-1].name);for(var c=0;l>c;++c){var p=r.handlerInfos[c];if(!p.isResolved)break;this.pivotHandler=p.handler}this.sequence=i.currentSequence++,this.promise=r.resolve(s,this)["catch"](function(e){return e.wasAborted||u.isAborted?o.reject(a(u)):(u.trigger("error",e.error,u,e.handlerWithError),u.abort(),o.reject(e.error))},h("Handle Abort"))}else this.promise=o.resolve(this.state),this.params={}}function a(e){return c(e.router,e.sequence,"detected abort."),new s}function s(e){this.message=e||"TransitionAborted",this.name="TransitionAborted"}var o=e["default"],u=(t.ResolvedHandlerInfo,r.trigger),l=r.slice,c=r.log,h=r.promiseLabel;i.currentSequence=0,i.prototype={targetName:null,urlMethod:"update",intent:null,params:null,pivotHandler:null,resolveIndex:0,handlerInfos:null,resolvedModels:null,isActive:!0,state:null,queryParamsOnly:!1,isTransition:!0,isExiting:function(e){for(var t=this.handlerInfos,r=0,n=t.length;n>r;++r){var i=t[r];if(i.name===e||i.handler===e)return!1}return!0},promise:null,data:null,then:function(e,t,r){return this.promise.then(e,t,r)},"catch":function(e,t){return this.promise["catch"](e,t)},"finally":function(e,t){return this.promise["finally"](e,t)},abort:function(){return this.isAborted?this:(c(this.router,this.sequence,this.targetName+": transition was aborted"),this.intent.preTransitionState=this.router.state,this.isAborted=!0,this.isActive=!1,this.router.activeTransition=null,this)},retry:function(){return this.abort(),this.router.transitionByIntent(this.intent,!1)},method:function(e){return this.urlMethod=e,this},trigger:function(e){var t=l.call(arguments);"boolean"==typeof e?t.shift():e=!1,u(this.router,this.state.handlerInfos.slice(0,this.resolveIndex+1),e,t)},followRedirects:function(){var e=this.router;return this.promise["catch"](function(t){return e.activeTransition?e.activeTransition.followRedirects():o.reject(t)})},toString:function(){return"Transition (sequence "+this.sequence+")"},log:function(e){c(this.router,this.sequence,e)}},i.prototype.send=i.prototype.trigger,n.Transition=i,n.logAbort=a,n.TransitionAborted=s}),e("router/utils",["exports"],function(e){"use strict";function t(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])}function r(e){var t,r,n=e&&e.length;return n&&n>0&&e[n-1]&&e[n-1].hasOwnProperty("queryParams")?(r=e[n-1].queryParams,t=v.call(e,0,n-1),[t,r]):[e,null]}function n(e){for(var t in e)if("number"==typeof e[t])e[t]=""+e[t];else if(b(e[t]))for(var r=0,n=e[t].length;n>r;r++)e[t][r]=""+e[t][r]}function i(e,t,r){e.log&&(3===arguments.length?e.log("Transition #"+t+": "+r):(r=t,e.log(r)))}function a(e,t){var r=arguments;return function(n){var i=v.call(r,2);return i.push(n),t.apply(e,i)}}function s(e){return"string"==typeof e||e instanceof String||"number"==typeof e||e instanceof Number}function o(e,t){for(var r=0,n=e.length;n>r&&!1!==t(e[r]);r++);}function u(e,t,r,n){if(e.triggerEvent)return void e.triggerEvent(t,r,n);var i=n.shift();if(!t){if(r)return;throw new Error("Could not trigger event '"+i+"'. There are no active handlers")}for(var a=!1,s=t.length-1;s>=0;s--){var o=t[s],u=o.handler;if(u.events&&u.events[i]){if(u.events[i].apply(u,n)!==!0)return;a=!0}}if(!a&&!r)throw new Error("Nothing handled the event '"+i+"'.")}function l(e,r){var i,a={all:{},changed:{},removed:{}};t(a.all,r);var s=!1;n(e),n(r);for(i in e)e.hasOwnProperty(i)&&(r.hasOwnProperty(i)||(s=!0,a.removed[i]=e[i]));for(i in r)if(r.hasOwnProperty(i))if(b(e[i])&&b(r[i]))if(e[i].length!==r[i].length)a.changed[i]=r[i],s=!0;else for(var o=0,u=e[i].length;u>o;o++)e[i][o]!==r[i][o]&&(a.changed[i]=r[i],s=!0);else e[i]!==r[i]&&(a.changed[i]=r[i],s=!0);return s&&a}function c(e){return"Router: "+e}function h(e,r){function n(t){e.call(this,t||{})}return n.prototype=g(e.prototype),t(n.prototype,r),n}function p(e,t){if(e){var r="_"+t;return e[r]&&r||e[t]&&t}}function m(e,t){var r=v.call(arguments,2);return f(e,t,r)}function f(e,t,r){var n=p(e,t);return n?e[n].apply(e,r):void 0}var d,v=Array.prototype.slice;d=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};var b=d;e.isArray=b;var g=Object.create||function(e){function t(){}return t.prototype=e,new t};e.oCreate=g,e.extractQueryParams=r,e.log=i,e.bind=a,e.forEach=o,e.trigger=u,e.getChangelist=l,e.promiseLabel=c,e.subclass=h,e.merge=t,e.slice=v,e.isParam=s,e.coerceQueryParamsToString=n,e.callHook=m,e.resolveHook=p,e.applyHook=f}),e("rsvp",["./rsvp/promise","./rsvp/events","./rsvp/node","./rsvp/all","./rsvp/all-settled","./rsvp/race","./rsvp/hash","./rsvp/hash-settled","./rsvp/rethrow","./rsvp/defer","./rsvp/config","./rsvp/map","./rsvp/resolve","./rsvp/reject","./rsvp/filter","./rsvp/asap","exports"],function(e,t,r,n,i,a,s,o,u,l,c,h,p,m,f,d,v){"use strict";function b(e,t){S.async(e,t)}function g(){S.on.apply(S,arguments)}function y(){S.off.apply(S,arguments)}var _=e["default"],w=t["default"],x=r["default"],C=n["default"],O=i["default"],P=a["default"],E=s["default"],A=o["default"],T=u["default"],N=l["default"],S=c.config,V=c.configure,k=h["default"],I=p["default"],j=m["default"],D=f["default"],R=d["default"];S.async=R;var M=I;if("undefined"!=typeof window&&"object"==typeof window.__PROMISE_INSTRUMENTATION__){var L=window.__PROMISE_INSTRUMENTATION__;V("instrument",!0);for(var H in L)L.hasOwnProperty(H)&&g(H,L[H])}v.cast=M,v.Promise=_,v.EventTarget=w,v.all=C,v.allSettled=O,v.race=P,v.hash=E,v.hashSettled=A,v.rethrow=T,v.defer=N,v.denodeify=x,v.configure=V,v.on=g,v.off=y,v.resolve=I,v.reject=j,v.async=b,v.map=k,v.filter=D}),e("rsvp.umd",["./rsvp"],function(t){"use strict";var r=t.Promise,n=t.allSettled,i=t.hash,a=t.hashSettled,s=t.denodeify,o=t.on,u=t.off,l=t.map,c=t.filter,h=t.resolve,p=t.reject,m=t.rethrow,f=t.all,d=t.defer,v=t.EventTarget,b=t.configure,g=t.race,y=t.async,_={race:g,Promise:r,allSettled:n,hash:i,hashSettled:a,denodeify:s,on:o,off:u,map:l,filter:c,resolve:h,reject:p,all:f,rethrow:m,defer:d,EventTarget:v,configure:b,async:y};"function"==typeof e&&e.amd?e(function(){return _}):"undefined"!=typeof module&&module.exports?module.exports=_:"undefined"!=typeof this&&(this.RSVP=_)}),e("rsvp/-internal",["./utils","./instrument","./config","exports"],function(e,t,r,n){"use strict";function i(){return new TypeError("A promises callback cannot return that same promise.")}function a(){}function s(e){try{return e.then}catch(t){return T.error=t,T}}function o(e,t,r,n){try{e.call(t,r,n)}catch(i){return i}}function u(e,t,r){O.async(function(e){var n=!1,i=o(r,t,function(r){n||(n=!0,t!==r?h(e,r):m(e,r))},function(t){n||(n=!0,f(e,t))},"Settle: "+(e._label||" unknown promise"));!n&&i&&(n=!0,f(e,i))},e)}function l(e,t){t._state===E?m(e,t._result):e._state===A?f(e,t._result):d(t,void 0,function(r){t!==r?h(e,r):m(e,r)},function(t){f(e,t)})}function c(e,t){if(t.constructor===e.constructor)l(e,t);else{var r=s(t);r===T?f(e,T.error):void 0===r?m(e,t):x(r)?u(e,t,r):m(e,t)}}function h(e,t){e===t?m(e,t):w(t)?c(e,t):m(e,t)}function p(e){e._onerror&&e._onerror(e._result),v(e)}function m(e,t){e._state===P&&(e._result=t,e._state=E,0===e._subscribers.length?O.instrument&&C("fulfilled",e):O.async(v,e))}function f(e,t){e._state===P&&(e._state=A,e._result=t,O.async(p,e))}function d(e,t,r,n){var i=e._subscribers,a=i.length;e._onerror=null,i[a]=t,i[a+E]=r,i[a+A]=n,0===a&&e._state&&O.async(v,e)}function v(e){var t=e._subscribers,r=e._state;if(O.instrument&&C(r===E?"fulfilled":"rejected",e),0!==t.length){for(var n,i,a=e._result,s=0;se;e+=2){var t=d[e],r=d[e+1];t(r),d[e]=void 0,d[e+1]=void 0}l=0}function u(){try{{var e=r("vertx");e.runOnLoop||e.runOnContext}return n()}catch(t){return s()}}var l=0;e["default"]=function(e,t){d[l]=e,d[l+1]=t,l+=2,2===l&&c()};var c,h="undefined"!=typeof window?window:void 0,p=h||{},m=p.MutationObserver||p.WebKitMutationObserver,f="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,d=new Array(1e3);c="undefined"!=typeof process&&"[object process]"==={}.toString.call(process)?t():m?i():f?a():void 0===h&&"function"==typeof r?u():s()}),e("rsvp/config",["./events","exports"],function(e,t){"use strict";function r(e,t){return"onerror"===e?void i.on("error",t):2!==arguments.length?i[e]:void(i[e]=t)}var n=e["default"],i={instrument:!1};n.mixin(i),t.config=i,t.configure=r}),e("rsvp/defer",["./promise","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=function(e){var t={};return t.promise=new r(function(e,r){t.resolve=e,t.reject=r},e),t}}),e("rsvp/enumerator",["./utils","./-internal","exports"],function(e,t,r){"use strict";function n(e,t,r){return e===h?{state:"fulfilled",value:r}:{state:"rejected",reason:r}}function i(e,t,r,n){this._instanceConstructor=e,this.promise=new e(o,n),this._abortOnReject=r,this._validateInput(t)?(this._input=t,this.length=t.length,this._remaining=t.length,this._init(),0===this.length?l(this.promise,this._result):(this.length=this.length||0,this._enumerate(),0===this._remaining&&l(this.promise,this._result))):u(this.promise,this._validationError())}var a=e.isArray,s=e.isMaybeThenable,o=t.noop,u=t.reject,l=t.fulfill,c=t.subscribe,h=t.FULFILLED,p=t.REJECTED,m=t.PENDING;r.makeSettledResult=n,i.prototype._validateInput=function(e){return a(e)},i.prototype._validationError=function(){return new Error("Array Methods must be provided an Array")},i.prototype._init=function(){this._result=new Array(this.length)},r["default"]=i,i.prototype._enumerate=function(){for(var e=this.length,t=this.promise,r=this._input,n=0;t._state===m&&e>n;n++)this._eachEntry(r[n],n)},i.prototype._eachEntry=function(e,t){var r=this._instanceConstructor;s(e)?e.constructor===r&&e._state!==m?(e._onerror=null,this._settledAt(e._state,t,e._result)):this._willSettleAt(r.resolve(e),t):(this._remaining--,this._result[t]=this._makeResult(h,t,e))},i.prototype._settledAt=function(e,t,r){var n=this.promise;n._state===m&&(this._remaining--,this._abortOnReject&&e===p?u(n,r):this._result[t]=this._makeResult(e,t,r)),0===this._remaining&&l(n,this._result)},i.prototype._makeResult=function(e,t,r){return r},i.prototype._willSettleAt=function(e,t){var r=this;c(e,void 0,function(e){r._settledAt(h,t,e)},function(e){r._settledAt(p,t,e)})}}),e("rsvp/events",["exports"],function(e){"use strict";function t(e,t){for(var r=0,n=e.length;n>r;r++)if(e[r]===t)return r;return-1}function r(e){var t=e._promiseCallbacks;return t||(t=e._promiseCallbacks={}),t}e["default"]={mixin:function(e){return e.on=this.on,e.off=this.off,e.trigger=this.trigger,e._promiseCallbacks=void 0,e},on:function(e,n){var i,a=r(this);i=a[e],i||(i=a[e]=[]),-1===t(i,n)&&i.push(n)},off:function(e,n){var i,a,s=r(this);return n?(i=s[e],a=t(i,n),void(-1!==a&&i.splice(a,1))):void(s[e]=[])},trigger:function(e,t){var n,i,a=r(this);if(n=a[e])for(var s=0;so;o++)s[o]=t(e[o]);return n.all(s,r).then(function(t){for(var r=new Array(a),n=0,i=0;a>i;i++)t[i]&&(r[n]=e[i],n++);return r.length=n,r})})}}),e("rsvp/hash-settled",["./promise","./enumerator","./promise-hash","./utils","exports"],function(e,t,r,n,i){"use strict";function a(e,t,r){this._superConstructor(e,t,!1,r)}var s=e["default"],o=t.makeSettledResult,u=r["default"],l=t["default"],c=n.o_create;a.prototype=c(u.prototype),a.prototype._superConstructor=l,a.prototype._makeResult=o,a.prototype._validationError=function(){return new Error("hashSettled must be called with an object")},i["default"]=function(e,t){return new a(s,e,t).promise}}),e("rsvp/hash",["./promise","./promise-hash","exports"],function(e,t,r){"use strict";var n=e["default"],i=t["default"];r["default"]=function(e,t){return new i(n,e,t).promise}}),e("rsvp/instrument",["./config","./utils","exports"],function(e,t,r){"use strict";function n(){setTimeout(function(){for(var e,t=0;to;o++)s[o]=t(e[o]);return n.all(s,r)})}}),e("rsvp/node",["./promise","./-internal","./utils","exports"],function(e,t,r,n){"use strict";function i(){this.value=void 0}function a(e){try{return e.then}catch(t){return g.value=t,g}}function s(e,t,r){try{e.apply(t,r)}catch(n){return g.value=n,g}}function o(e,t){for(var r,n,i={},a=e.length,s=new Array(a),o=0;a>o;o++)s[o]=e[o];for(n=0;nn;n++)r[n-1]=e[n];return r}function l(e,t){return{then:function(r,n){return e.call(t,r,n)}}}function c(e,t,r,n){var i=s(r,n,t);return i===g&&v(e,i.value),e}function h(e,t,r,n){return m.all(t).then(function(t){var i=s(r,n,t);return i===g&&v(e,i.value),e})}function p(e){return e&&"object"==typeof e?e.constructor===m?!0:a(e):!1}var m=e["default"],f=t.noop,d=t.resolve,v=t.reject,b=r.isArray,g=new i,y=new i; +n["default"]=function(e,t){var r=function(){for(var r,n=this,i=arguments.length,a=new Array(i+1),s=!1,g=0;i>g;++g){if(r=arguments[g],!s){if(s=p(r),s===y){var _=new m(f);return v(_,y.value),_}s&&s!==!0&&(r=l(s,r))}a[g]=r}var w=new m(f);return a[i]=function(e,r){e?v(w,e):void 0===t?d(w,r):t===!0?d(w,u(arguments)):b(t)?d(w,o(arguments,t)):d(w,r)},s?h(w,a,e,n):c(w,a,e,n)};return r.__proto__=e,r}}),e("rsvp/promise-hash",["./enumerator","./-internal","./utils","exports"],function(e,t,r,n){"use strict";function i(e,t,r){this._superConstructor(e,t,!0,r)}var a=e["default"],s=t.PENDING,o=r.o_create;n["default"]=i,i.prototype=o(a.prototype),i.prototype._superConstructor=a,i.prototype._init=function(){this._result={}},i.prototype._validateInput=function(e){return e&&"object"==typeof e},i.prototype._validationError=function(){return new Error("Promise.hash must be called with an object")},i.prototype._enumerate=function(){var e=this.promise,t=this._input,r=[];for(var n in t)e._state===s&&t.hasOwnProperty(n)&&r.push({position:n,entry:t[n]});var i=r.length;this._remaining=i;for(var a,o=0;e._state===s&&i>o;o++)a=r[o],this._eachEntry(a.entry,a.position)}}),e("rsvp/promise",["./config","./instrument","./utils","./-internal","./promise/all","./promise/race","./promise/resolve","./promise/reject","exports"],function(e,t,r,n,i,a,s,o,u){"use strict";function l(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function c(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function h(e,t){this._id=A++,this._label=t,this._state=void 0,this._result=void 0,this._subscribers=[],p.instrument&&m("created",this),v!==e&&(f(e)||l(),this instanceof h||c(),g(this,e))}var p=e.config,m=t["default"],f=r.isFunction,d=r.now,v=n.noop,b=n.subscribe,g=n.initializePromise,y=n.invokeCallback,_=n.FULFILLED,w=n.REJECTED,x=i["default"],C=a["default"],O=s["default"],P=o["default"],E="rsvp_"+d()+"-",A=0;u["default"]=h,h.cast=O,h.all=x,h.race=C,h.resolve=O,h.reject=P,h.prototype={constructor:h,_guidKey:E,_onerror:function(e){p.trigger("error",e)},then:function(e,t,r){var n=this,i=n._state;if(i===_&&!e||i===w&&!t)return p.instrument&&m("chained",this,this),this;n._onerror=null;var a=new this.constructor(v,r),s=n._result;if(p.instrument&&m("chained",n,a),i){var o=arguments[i-1];p.async(function(){y(i,a,o,s)})}else b(n,a,e,t);return a},"catch":function(e,t){return this.then(null,e,t)},"finally":function(e,t){var r=this.constructor;return this.then(function(t){return r.resolve(e()).then(function(){return t})},function(t){return r.resolve(e()).then(function(){throw t})},t)}}}),e("rsvp/promise/all",["../enumerator","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=function(e,t){return new r(this,e,!0,t).promise}}),e("rsvp/promise/race",["../utils","../-internal","exports"],function(e,t,r){"use strict";var n=e.isArray,i=t.noop,a=t.resolve,s=t.reject,o=t.subscribe,u=t.PENDING;r["default"]=function(e,t){function r(e){a(h,e)}function l(e){s(h,e)}var c=this,h=new c(i,t);if(!n(e))return s(h,new TypeError("You must pass an array to race.")),h;for(var p=e.length,m=0;h._state===u&&p>m;m++)o(c.resolve(e[m]),void 0,r,l);return h}}),e("rsvp/promise/reject",["../-internal","exports"],function(e,t){"use strict";var r=e.noop,n=e.reject;t["default"]=function(e,t){var i=this,a=new i(r,t);return n(a,e),a}}),e("rsvp/promise/resolve",["../-internal","exports"],function(e,t){"use strict";var r=e.noop,n=e.resolve;t["default"]=function(e,t){var i=this;if(e&&"object"==typeof e&&e.constructor===i)return e;var a=new i(r,t);return n(a,e),a}}),e("rsvp/race",["./promise","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=function(e,t){return r.race(e,t)}}),e("rsvp/reject",["./promise","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=function(e,t){return r.reject(e,t)}}),e("rsvp/resolve",["./promise","exports"],function(e,t){"use strict";var r=e["default"];t["default"]=function(e,t){return r.resolve(e,t)}}),e("rsvp/rethrow",["exports"],function(e){"use strict";e["default"]=function(e){throw setTimeout(function(){throw e}),e}}),e("rsvp/utils",["exports"],function(e){"use strict";function t(e){return"function"==typeof e||"object"==typeof e&&null!==e}function r(e){return"function"==typeof e}function n(e){return"object"==typeof e&&null!==e}function i(){}e.objectOrFunction=t,e.isFunction=r,e.isMaybeThenable=n;var a;a=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};var s=a;e.isArray=s;var o=Date.now||function(){return(new Date).getTime()};e.now=o;var u=Object.create||function(e){if(arguments.length>1)throw new Error("Second argument not supported");if("object"!=typeof e)throw new TypeError("Argument must be an object");return i.prototype=e,new i};e.o_create=u}),t("ember")}(); \ No newline at end of file diff --git a/ajax/libs/ember.js/1.8.0-beta.4/ember.prod.js b/ajax/libs/ember.js/1.8.0-beta.4/ember.prod.js new file mode 100644 index 000000000..c0f95d1b1 --- /dev/null +++ b/ajax/libs/ember.js/1.8.0-beta.4/ember.prod.js @@ -0,0 +1,48944 @@ +/*! + * @overview Ember - JavaScript Application Framework + * @copyright Copyright 2011-2014 Tilde Inc. and contributors + * Portions Copyright 2006-2011 Strobe Inc. + * Portions Copyright 2008-2011 Apple Inc. All rights reserved. + * @license Licensed under MIT license + * See https://raw.github.com/emberjs/ember.js/master/LICENSE + * @version 1.8.0-beta.4 + */ + +(function() { +var define, requireModule, require, requirejs, Ember; + +(function() { + Ember = this.Ember = this.Ember || {}; + if (typeof Ember === 'undefined') { Ember = {}; }; + + if (typeof Ember.__loader === 'undefined') { + var registry = {}, seen = {}; + + define = function(name, deps, callback) { + registry[name] = { deps: deps, callback: callback }; + }; + + requirejs = require = requireModule = function(name) { + if (seen.hasOwnProperty(name)) { return seen[name]; } + seen[name] = {}; + + if (!registry[name]) { + throw new Error("Could not find module " + name); + } + + var mod = registry[name]; + var deps = mod.deps; + var callback = mod.callback; + var reified = []; + var exports; + + for (var i=0, l=deps.length; i 3) { + args = new Array(length - 3); + for (var i = 3; i < length; i++) { + args[i-3] = arguments[i]; + } + } else { + args = undefined; + } + + if (!this.currentInstance) { createAutorun(this); } + return this.currentInstance.schedule(queueName, target, method, args, false, stack); + }, + + deferOnce: function(queueName, target, method /* , args */) { + if (!method) { + method = target; + target = null; + } + + if (isString(method)) { + method = target[method]; + } + + var stack = this.DEBUG ? new Error() : undefined; + var length = arguments.length; + var args; + + if (length > 3) { + args = new Array(length - 3); + for (var i = 3; i < length; i++) { + args[i-3] = arguments[i]; + } + } else { + args = undefined; + } + + if (!this.currentInstance) { + createAutorun(this); + } + return this.currentInstance.schedule(queueName, target, method, args, true, stack); + }, + + setTimeout: function() { + var l = arguments.length; + var args = new Array(l); + + for (var x = 0; x < l; x++) { + args[x] = arguments[x]; + } + + var length = args.length, + method, wait, target, + methodOrTarget, methodOrWait, methodOrArgs; + + if (length === 0) { + return; + } else if (length === 1) { + method = args.shift(); + wait = 0; + } else if (length === 2) { + methodOrTarget = args[0]; + methodOrWait = args[1]; + + if (isFunction(methodOrWait) || isFunction(methodOrTarget[methodOrWait])) { + target = args.shift(); + method = args.shift(); + wait = 0; + } else if (isCoercableNumber(methodOrWait)) { + method = args.shift(); + wait = args.shift(); + } else { + method = args.shift(); + wait = 0; + } + } else { + var last = args[args.length - 1]; + + if (isCoercableNumber(last)) { + wait = args.pop(); + } else { + wait = 0; + } + + methodOrTarget = args[0]; + methodOrArgs = args[1]; + + if (isFunction(methodOrArgs) || (isString(methodOrArgs) && + methodOrTarget !== null && + methodOrArgs in methodOrTarget)) { + target = args.shift(); + method = args.shift(); + } else { + method = args.shift(); + } + } + + var executeAt = now() + parseInt(wait, 10); + + if (isString(method)) { + method = target[method]; + } + + var onError = getOnError(this.options); + + function fn() { + if (onError) { + try { + method.apply(target, args); + } catch (e) { + onError(e); + } + } else { + method.apply(target, args); + } + } + + // find position to insert + var i = searchTimer(executeAt, this._timers); + + this._timers.splice(i, 0, executeAt, fn); + + updateLaterTimer(this, executeAt, wait); + + return fn; + }, + + throttle: function(target, method /* , args, wait, [immediate] */) { + var backburner = this; + var args = arguments; + var immediate = pop.call(args); + var wait, throttler, index, timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = true; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + + index = findThrottler(target, method, this._throttlers); + if (index > -1) { return this._throttlers[index]; } // throttled + + timer = global.setTimeout(function() { + if (!immediate) { + backburner.run.apply(backburner, args); + } + var index = findThrottler(target, method, backburner._throttlers); + if (index > -1) { + backburner._throttlers.splice(index, 1); + } + }, wait); + + if (immediate) { + this.run.apply(this, args); + } + + throttler = [target, method, timer]; + + this._throttlers.push(throttler); + + return throttler; + }, + + debounce: function(target, method /* , args, wait, [immediate] */) { + var backburner = this; + var args = arguments; + var immediate = pop.call(args); + var wait, index, debouncee, timer; + + if (isNumber(immediate) || isString(immediate)) { + wait = immediate; + immediate = false; + } else { + wait = pop.call(args); + } + + wait = parseInt(wait, 10); + // Remove debouncee + index = findDebouncee(target, method, this._debouncees); + + if (index > -1) { + debouncee = this._debouncees[index]; + this._debouncees.splice(index, 1); + clearTimeout(debouncee[2]); + } + + timer = global.setTimeout(function() { + if (!immediate) { + backburner.run.apply(backburner, args); + } + var index = findDebouncee(target, method, backburner._debouncees); + if (index > -1) { + backburner._debouncees.splice(index, 1); + } + }, wait); + + if (immediate && index === -1) { + backburner.run.apply(backburner, args); + } + + debouncee = [ + target, + method, + timer + ]; + + backburner._debouncees.push(debouncee); + + return debouncee; + }, + + cancelTimers: function() { + var clearItems = function(item) { + clearTimeout(item[2]); + }; + + each(this._throttlers, clearItems); + this._throttlers = []; + + each(this._debouncees, clearItems); + this._debouncees = []; + + if (this._laterTimer) { + clearTimeout(this._laterTimer); + this._laterTimer = null; + } + this._timers = []; + + if (this._autorun) { + clearTimeout(this._autorun); + this._autorun = null; + } + }, + + hasTimers: function() { + return !!this._timers.length || !!this._debouncees.length || !!this._throttlers.length || this._autorun; + }, + + cancel: function(timer) { + var timerType = typeof timer; + + if (timer && timerType === 'object' && timer.queue && timer.method) { // we're cancelling a deferOnce + return timer.queue.cancel(timer); + } else if (timerType === 'function') { // we're cancelling a setTimeout + for (var i = 0, l = this._timers.length; i < l; i += 2) { + if (this._timers[i + 1] === timer) { + this._timers.splice(i, 2); // remove the two elements + if (i === 0) { + if (this._laterTimer) { // Active timer? Then clear timer and reset for future timer + clearTimeout(this._laterTimer); + this._laterTimer = null; + } + if (this._timers.length > 0) { // Update to next available timer when available + updateLaterTimer(this, this._timers[0], this._timers[0] - now()); + } + } + return true; + } + } + } else if (Object.prototype.toString.call(timer) === "[object Array]"){ // we're cancelling a throttle or debounce + return this._cancelItem(findThrottler, this._throttlers, timer) || + this._cancelItem(findDebouncee, this._debouncees, timer); + } else { + return; // timer was null or not a timer + } + }, + + _cancelItem: function(findMethod, array, timer){ + var item, index; + + if (timer.length < 3) { return false; } + + index = findMethod(timer[0], timer[1], array); + + if (index > -1) { + + item = array[index]; + + if (item[2] === timer[2]) { + array.splice(index, 1); + clearTimeout(timer[2]); + return true; + } + } + + return false; + } + }; + + Backburner.prototype.schedule = Backburner.prototype.defer; + Backburner.prototype.scheduleOnce = Backburner.prototype.deferOnce; + Backburner.prototype.later = Backburner.prototype.setTimeout; + + if (needsIETryCatchFix) { + var originalRun = Backburner.prototype.run; + Backburner.prototype.run = wrapInTryCatch(originalRun); + + var originalEnd = Backburner.prototype.end; + Backburner.prototype.end = wrapInTryCatch(originalEnd); + } + + function getOnError(options) { + return options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + } + + function createAutorun(backburner) { + backburner.begin(); + backburner._autorun = global.setTimeout(function() { + backburner._autorun = null; + backburner.end(); + }); + } + + function updateLaterTimer(backburner, executeAt, wait) { + var n = now(); + if (!backburner._laterTimer || executeAt < backburner._laterTimerExpiresAt || backburner._laterTimerExpiresAt < n) { + + if (backburner._laterTimer) { + // Clear when: + // - Already expired + // - New timer is earlier + clearTimeout(backburner._laterTimer); + + if (backburner._laterTimerExpiresAt < n) { // If timer was never triggered + // Calculate the left-over wait-time + wait = Math.max(0, executeAt - n); + } + } + + backburner._laterTimer = global.setTimeout(function() { + backburner._laterTimer = null; + backburner._laterTimerExpiresAt = null; + executeTimers(backburner); + }, wait); + + backburner._laterTimerExpiresAt = n + wait; + } + } + + function executeTimers(backburner) { + var n = now(); + var fns, i, l; + + backburner.run(function() { + i = searchTimer(n, backburner._timers); + + fns = backburner._timers.splice(0, i); + + for (i = 1, l = fns.length; i < l; i += 2) { + backburner.schedule(backburner.options.defaultQueue, null, fns[i]); + } + }); + + if (backburner._timers.length) { + updateLaterTimer(backburner, backburner._timers[0], backburner._timers[0] - n); + } + } + + function findDebouncee(target, method, debouncees) { + return findItem(target, method, debouncees); + } + + function findThrottler(target, method, throttlers) { + return findItem(target, method, throttlers); + } + + function findItem(target, method, collection) { + var item; + var index = -1; + + for (var i = 0, l = collection.length; i < l; i++) { + item = collection[i]; + if (item[0] === target && item[1] === method) { + index = i; + break; + } + } + + return index; + } + + __exports__["default"] = Backburner; + }); +define("backburner.umd", + ["./backburner"], + function(__dependency1__) { + "use strict"; + var Backburner = __dependency1__["default"]; + + /* global define:true module:true window: true */ + if (typeof define === 'function' && define.amd) { + define(function() { return Backburner; }); + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = Backburner; + } else if (typeof this !== 'undefined') { + this['Backburner'] = Backburner; + } + }); +define("backburner/binary-search", + ["exports"], + function(__exports__) { + "use strict"; + __exports__["default"] = function binarySearch(time, timers) { + var start = 0; + var end = timers.length - 2; + var middle, l; + + while (start < end) { + // since timers is an array of pairs 'l' will always + // be an integer + l = (end - start) / 2; + + // compensate for the index in case even number + // of pairs inside timers + middle = start + l - (l % 2); + + if (time >= timers[middle]) { + start = middle + 2; + } else { + end = middle; + } + } + + return (time >= timers[start]) ? start + 2 : start; + } + }); +define("backburner/deferred-action-queues", + ["./utils","./queue","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var each = __dependency1__.each; + var isString = __dependency1__.isString; + var Queue = __dependency2__["default"]; + + function DeferredActionQueues(queueNames, options) { + var queues = this.queues = {}; + this.queueNames = queueNames = queueNames || []; + + this.options = options; + + each(queueNames, function(queueName) { + queues[queueName] = new Queue(queueName, options[queueName], options); + }); + } + + function noSuchQueue(name) { + throw new Error("You attempted to schedule an action in a queue (" + name + ") that doesn't exist"); + } + + DeferredActionQueues.prototype = { + schedule: function(name, target, method, args, onceFlag, stack) { + var queues = this.queues; + var queue = queues[name]; + + if (!queue) { noSuchQueue(name); } + + if (onceFlag) { + return queue.pushUnique(target, method, args, stack); + } else { + return queue.push(target, method, args, stack); + } + }, + + invoke: function(target, method, args, _, _errorRecordedForStack) { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + }, + + invokeWithOnError: function(target, method, args, onError, errorRecordedForStack) { + try { + if (args && args.length > 0) { + method.apply(target, args); + } else { + method.call(target); + } + } catch(error) { + onError(error, errorRecordedForStack); + } + }, + + flush: function() { + var queues = this.queues; + var queueNames = this.queueNames; + var queueName, queue, queueItems, priorQueueNameIndex; + var queueNameIndex = 0; + var numberOfQueues = queueNames.length; + var options = this.options; + var onError = options.onError || (options.onErrorTarget && options.onErrorTarget[options.onErrorMethod]); + var invoke = onError ? this.invokeWithOnError : this.invoke; + + while (queueNameIndex < numberOfQueues) { + queueName = queueNames[queueNameIndex]; + queue = queues[queueName]; + queueItems = queue._queueBeingFlushed = queue._queue.slice(); + queue._queue = []; + queue.targetQueues = Object.create(null); + + var queueOptions = queue.options; // TODO: write a test for this + var before = queueOptions && queueOptions.before; + var after = queueOptions && queueOptions.after; + var target, method, args, errorRecordedForStack; + var queueIndex = 0; + var numberOfQueueItems = queueItems.length; + + if (numberOfQueueItems && before) { + before(); + } + + while (queueIndex < numberOfQueueItems) { + target = queueItems[queueIndex]; + method = queueItems[queueIndex+1]; + args = queueItems[queueIndex+2]; + errorRecordedForStack = queueItems[queueIndex+3]; // Debugging assistance + + // + + if (isString(method)) { + method = target[method]; + } + + // method could have been nullified / canceled during flush + if (method) { + // + // ** Attention intrepid developer ** + // + // To find out the stack of this task when it was scheduled onto + // the run loop, add the following to your app.js: + // + // Ember.run.backburner.DEBUG = true; // NOTE: This slows your app, don't leave it on in production. + // + // Once that is in place, when you are at a breakpoint and navigate + // here in the stack explorer, you can look at `errorRecordedForStack.stack`, + // which will be the captured stack when this job was scheduled. + // + invoke(target, method, args, onError, errorRecordedForStack); + } + + queueIndex += 4; + } + + queue._queueBeingFlushed = null; + if (numberOfQueueItems && after) { + after(); + } + + if ((priorQueueNameIndex = indexOfPriorQueueWithActions(this, queueNameIndex)) !== -1) { + queueNameIndex = priorQueueNameIndex; + } else { + queueNameIndex++; + } + } + } + }; + + function indexOfPriorQueueWithActions(daq, currentQueueIndex) { + var queueName, queue; + + for (var i = 0, l = currentQueueIndex; i <= l; i++) { + queueName = daq.queueNames[i]; + queue = daq.queues[queueName]; + if (queue._queue.length) { return i; } + } + + return -1; + } + + __exports__["default"] = DeferredActionQueues; + }); +define("backburner/platform", + ["exports"], + function(__exports__) { + "use strict"; + // In IE 6-8, try/finally doesn't work without a catch. + // Unfortunately, this is impossible to test for since wrapping it in a parent try/catch doesn't trigger the bug. + // This tests for another broken try/catch behavior that only exhibits in the same versions of IE. + var needsIETryCatchFix = (function(e,x){ + try{ x(); } + catch(e) { } // jshint ignore:line + return !!e; + })(); + __exports__.needsIETryCatchFix = needsIETryCatchFix; + }); +define("backburner/queue", + ["exports"], + function(__exports__) { + "use strict"; + function Queue(name, options, globalOptions) { + this.name = name; + this.globalOptions = globalOptions || {}; + this.options = options; + this._queue = []; + this.targetQueues = Object.create(null); + this._queueBeingFlushed = undefined; + } + + Queue.prototype = { + push: function(target, method, args, stack) { + var queue = this._queue; + queue.push(target, method, args, stack); + + return { + queue: this, + target: target, + method: method + }; + }, + + pushUniqueWithoutGuid: function(target, method, args, stack) { + var queue = this._queue; + + for (var i = 0, l = queue.length; i < l; i += 4) { + var currentTarget = queue[i]; + var currentMethod = queue[i+1]; + + if (currentTarget === target && currentMethod === method) { + queue[i+2] = args; // replace args + queue[i+3] = stack; // replace stack + return; + } + } + + queue.push(target, method, args, stack); + }, + + targetQueue: function(targetQueue, target, method, args, stack) { + var queue = this._queue; + + for (var i = 0, l = targetQueue.length; i < l; i += 4) { + var currentMethod = targetQueue[i]; + var currentIndex = targetQueue[i + 1]; + + if (currentMethod === method) { + queue[currentIndex + 2] = args; // replace args + queue[currentIndex + 3] = stack; // replace stack + return; + } + } + + targetQueue.push( + method, + queue.push(target, method, args, stack) - 4 + ); + }, + + pushUniqueWithGuid: function(guid, target, method, args, stack) { + var hasLocalQueue = this.targetQueues[guid]; + + if (hasLocalQueue) { + this.targetQueue(hasLocalQueue, target, method, args, stack); + } else { + this.targetQueues[guid] = [ + method, + this._queue.push(target, method, args, stack) - 4 + ]; + } + + return { + queue: this, + target: target, + method: method + }; + }, + + pushUnique: function(target, method, args, stack) { + var queue = this._queue, currentTarget, currentMethod, i, l; + var KEY = this.globalOptions.GUID_KEY; + + if (target && KEY) { + var guid = target[KEY]; + if (guid) { + return this.pushUniqueWithGuid(guid, target, method, args, stack); + } + } + + this.pushUniqueWithoutGuid(target, method, args, stack); + + return { + queue: this, + target: target, + method: method + }; + }, + + // TODO: remove me, only being used for Ember.run.sync + flush: function() { + var queue = this._queue; + var globalOptions = this.globalOptions; + var options = this.options; + var before = options && options.before; + var after = options && options.after; + var onError = globalOptions.onError || (globalOptions.onErrorTarget && globalOptions.onErrorTarget[globalOptions.onErrorMethod]); + var target, method, args, stack, i, l = queue.length; + + this.targetQueues = Object.create(null); + + if (l && before) { before(); } + for (i = 0; i < l; i += 4) { + target = queue[i]; + method = queue[i+1]; + args = queue[i+2]; + stack = queue[i+3]; // Debugging assistance + + // TODO: error handling + if (args && args.length > 0) { + if (onError) { + try { + method.apply(target, args); + } catch (e) { + onError(e); + } + } else { + method.apply(target, args); + } + } else { + if (onError) { + try { + method.call(target); + } catch(e) { + onError(e); + } + } else { + method.call(target); + } + } + } + if (l && after) { after(); } + + // check if new items have been added + if (queue.length > l) { + this._queue = queue.slice(l); + this.flush(); + } else { + this._queue.length = 0; + } + }, + + cancel: function(actionToCancel) { + var queue = this._queue, currentTarget, currentMethod, i, l; + var target = actionToCancel.target; + var method = actionToCancel.method; + var GUID_KEY = this.globalOptions.GUID_KEY; + + if (GUID_KEY && this.targetQueues && target) { + var targetQueue = this.targetQueues[target[GUID_KEY]]; + + if (targetQueue) { + for (i = 0, l = targetQueue.length; i < l; i++) { + if (targetQueue[i] === method) { + targetQueue.splice(i, 1); + } + } + } + } + + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && + currentMethod === method) { + queue.splice(i, 4); + return true; + } + } + + // if not found in current queue + // could be in the queue that is being flushed + queue = this._queueBeingFlushed; + if (!queue) { + return; + } + for (i = 0, l = queue.length; i < l; i += 4) { + currentTarget = queue[i]; + currentMethod = queue[i+1]; + + if (currentTarget === target && + currentMethod === method) { + // don't mess with array during flush + // just nullify the method + queue[i+1] = null; + return true; + } + } + } + }; + + __exports__["default"] = Queue; + }); +define("backburner/utils", + ["exports"], + function(__exports__) { + "use strict"; + var NUMBER = /\d+/; + + function each(collection, callback) { + for (var i = 0; i < collection.length; i++) { + callback(collection[i]); + } + } + + __exports__.each = each;// Date.now is not available in browsers < IE9 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility + var now = Date.now || function() { return new Date().getTime(); }; + __exports__.now = now; + function isString(suspect) { + return typeof suspect === 'string'; + } + + __exports__.isString = isString;function isFunction(suspect) { + return typeof suspect === 'function'; + } + + __exports__.isFunction = isFunction;function isNumber(suspect) { + return typeof suspect === 'number'; + } + + __exports__.isNumber = isNumber;function isCoercableNumber(number) { + return isNumber(number) || NUMBER.test(number); + } + + __exports__.isCoercableNumber = isCoercableNumber;function wrapInTryCatch(func) { + return function () { + try { + return func.apply(this, arguments); + } catch (e) { + throw e; + } + }; + } + + __exports__.wrapInTryCatch = wrapInTryCatch; + }); +define("calculateVersion", + [], + function() { + "use strict"; + 'use strict'; + + var fs = require('fs'); + var path = require('path'); + + module.exports = function () { + var packageVersion = require('../package.json').version; + var output = [packageVersion]; + var gitPath = path.join(__dirname,'..','.git'); + var headFilePath = path.join(gitPath, 'HEAD'); + + if (packageVersion.indexOf('+') > -1) { + try { + if (fs.existsSync(headFilePath)) { + var headFile = fs.readFileSync(headFilePath, {encoding: 'utf8'}); + var branchName = headFile.split('/').slice(-1)[0].trim(); + var refPath = headFile.split(' ')[1]; + var branchSHA; + + if (refPath) { + var branchPath = path.join(gitPath, refPath.trim()); + branchSHA = fs.readFileSync(branchPath); + } else { + branchSHA = branchName; + } + + output.push(branchSHA.slice(0,10)); + } + } catch (err) { + console.error(err.stack); + } + return output.join('.'); + } else { + return packageVersion; + } + }; + }); +define("container", + ["container/container","exports"], + function(__dependency1__, __exports__) { + "use strict"; + /* + Public api for the container is still in flux. + The public api, specified on the application namespace should be considered the stable api. + // @module container + @private + */ + + /* + Flag to enable/disable model factory injections (disabled by default) + If model factory injections are enabled, models should not be + accessed globally (only through `container.lookupFactory('model:modelName'))`); + */ + Ember.MODEL_FACTORY_INJECTIONS = false; + + if (Ember.ENV && typeof Ember.ENV.MODEL_FACTORY_INJECTIONS !== 'undefined') { + Ember.MODEL_FACTORY_INJECTIONS = !!Ember.ENV.MODEL_FACTORY_INJECTIONS; + } + + + var Container = __dependency1__["default"]; + + __exports__["default"] = Container; + }); +define("container/container", + ["ember-metal/core","ember-metal/keys","ember-metal/dictionary","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var emberKeys = __dependency2__["default"]; + var dictionary = __dependency3__["default"]; + + // A lightweight container that helps to assemble and decouple components. + // Public api for the container is still in flux. + // The public api, specified on the application namespace should be considered the stable api. + function Container(parent) { + this.parent = parent; + this.children = []; + + this.resolver = parent && parent.resolver || function() {}; + + this.registry = dictionary(parent ? parent.registry : null); + this.cache = dictionary(parent ? parent.cache : null); + this.factoryCache = dictionary(parent ? parent.factoryCache : null); + this.resolveCache = dictionary(parent ? parent.resolveCache : null); + this.typeInjections = dictionary(parent ? parent.typeInjections : null); + this.injections = dictionary(null); + this.normalizeCache = dictionary(null); + + this.factoryTypeInjections = dictionary(parent ? parent.factoryTypeInjections : null); + this.factoryInjections = dictionary(null); + + this._options = dictionary(parent ? parent._options : null); + this._typeOptions = dictionary(parent ? parent._typeOptions : null); + } + + Container.prototype = { + + /** + @property parent + @type Container + @default null + */ + parent: null, + + /** + @property children + @type Array + @default [] + */ + children: null, + + /** + @property resolver + @type function + */ + resolver: null, + + /** + @property registry + @type InheritingDict + */ + registry: null, + + /** + @property cache + @type InheritingDict + */ + cache: null, + + /** + @property typeInjections + @type InheritingDict + */ + typeInjections: null, + + /** + @property injections + @type Object + @default {} + */ + injections: null, + + /** + @private + + @property _options + @type InheritingDict + @default null + */ + _options: null, + + /** + @private + + @property _typeOptions + @type InheritingDict + */ + _typeOptions: null, + + /** + Returns a new child of the current container. These children are configured + to correctly inherit from the current container. + + @method child + @return {Container} + */ + child: function() { + var container = new Container(this); + this.children.push(container); + return container; + }, + + /** + Sets a key-value pair on the current container. If a parent container, + has the same key, once set on a child, the parent and child will diverge + as expected. + + @method set + @param {Object} object + @param {String} key + @param {any} value + */ + set: function(object, key, value) { + object[key] = value; + }, + + /** + Registers a factory for later injection. + + Example: + + ```javascript + var container = new Container(); + + container.register('model:user', Person, {singleton: false }); + container.register('fruit:favorite', Orange); + container.register('communication:main', Email, {singleton: false}); + ``` + + @method register + @param {String} fullName + @param {Function} factory + @param {Object} options + */ + register: function(fullName, factory, options) { + + if (factory === undefined) { + throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`'); + } + + var normalizedName = this.normalize(fullName); + + if (normalizedName in this.cache) { + throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.'); + } + + this.registry[normalizedName] = factory; + this._options[normalizedName] = (options || {}); + }, + + /** + Unregister a fullName + + ```javascript + var container = new Container(); + container.register('model:user', User); + + container.lookup('model:user') instanceof User //=> true + + container.unregister('model:user') + container.lookup('model:user') === undefined //=> true + ``` + + @method unregister + @param {String} fullName + */ + unregister: function(fullName) { + + var normalizedName = this.normalize(fullName); + + delete this.registry[normalizedName]; + delete this.cache[normalizedName]; + delete this.factoryCache[normalizedName]; + delete this.resolveCache[normalizedName]; + delete this._options[normalizedName]; + }, + + /** + Given a fullName return the corresponding factory. + + By default `resolve` will retrieve the factory from + its container's registry. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + container.resolve('api:twitter') // => Twitter + ``` + + Optionally the container can be provided with a custom resolver. + If provided, `resolve` will first provide the custom resolver + the opportunity to resolve the fullName, otherwise it will fallback + to the registry. + + ```javascript + var container = new Container(); + container.resolver = function(fullName) { + // lookup via the module system of choice + }; + + // the twitter factory is added to the module system + container.resolve('api:twitter') // => Twitter + ``` + + @method resolve + @param {String} fullName + @return {Function} fullName's factory + */ + resolve: function(fullName) { + return resolve(this, this.normalize(fullName)); + }, + + /** + A hook that can be used to describe how the resolver will + attempt to find the factory. + + For example, the default Ember `.describe` returns the full + class name (including namespace) where Ember's resolver expects + to find the `fullName`. + + @method describe + @param {String} fullName + @return {string} described fullName + */ + describe: function(fullName) { + return fullName; + }, + + /** + A hook to enable custom fullName normalization behaviour + + @method normalizeFullName + @param {String} fullName + @return {string} normalized fullName + */ + normalizeFullName: function(fullName) { + return fullName; + }, + + /** + normalize a fullName based on the applications conventions + + @method normalize + @param {String} fullName + @return {string} normalized fullName + */ + normalize: function(fullName) { + return this.normalizeCache[fullName] || ( + this.normalizeCache[fullName] = this.normalizeFullName(fullName) + ); + }, + + /** + @method makeToString + + @param {any} factory + @param {string} fullName + @return {function} toString function + */ + makeToString: function(factory, fullName) { + return factory.toString(); + }, + + /** + Given a fullName return a corresponding instance. + + The default behaviour is for lookup to return a singleton instance. + The singleton is scoped to the container, allowing multiple containers + to all have their own locally scoped singletons. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter'); + + twitter instanceof Twitter; // => true + + // by default the container will return singletons + var twitter2 = container.lookup('api:twitter'); + twitter2 instanceof Twitter; // => true + + twitter === twitter2; //=> true + ``` + + If singletons are not wanted an optional flag can be provided at lookup. + + ```javascript + var container = new Container(); + container.register('api:twitter', Twitter); + + var twitter = container.lookup('api:twitter', { singleton: false }); + var twitter2 = container.lookup('api:twitter', { singleton: false }); + + twitter === twitter2; //=> false + ``` + + @method lookup + @param {String} fullName + @param {Object} options + @return {any} + */ + lookup: function(fullName, options) { + return lookup(this, this.normalize(fullName), options); + }, + + /** + Given a fullName return the corresponding factory. + + @method lookupFactory + @param {String} fullName + @return {any} + */ + lookupFactory: function(fullName) { + return factoryFor(this, this.normalize(fullName)); + }, + + /** + Given a fullName check if the container is aware of its factory + or singleton instance. + + @method has + @param {String} fullName + @return {Boolean} + */ + has: function(fullName) { + return has(this, this.normalize(fullName)); + }, + + /** + Allow registering options for all factories of a type. + + ```javascript + var container = new Container(); + + // if all of type `connection` must not be singletons + container.optionsForType('connection', { singleton: false }); + + container.register('connection:twitter', TwitterConnection); + container.register('connection:facebook', FacebookConnection); + + var twitter = container.lookup('connection:twitter'); + var twitter2 = container.lookup('connection:twitter'); + + twitter === twitter2; // => false + + var facebook = container.lookup('connection:facebook'); + var facebook2 = container.lookup('connection:facebook'); + + facebook === facebook2; // => false + ``` + + @method optionsForType + @param {String} type + @param {Object} options + */ + optionsForType: function(type, options) { + if (this.parent) { illegalChildOperation('optionsForType'); } + + this._typeOptions[type] = options; + }, + + /** + @method options + @param {String} type + @param {Object} options + */ + options: function(type, options) { + this.optionsForType(type, options); + }, + + /** + Used only via `injection`. + + Provides a specialized form of injection, specifically enabling + all objects of one type to be injected with a reference to another + object. + + For example, provided each object of type `controller` needed a `router`. + one would do the following: + + ```javascript + var container = new Container(); + + container.register('router:main', Router); + container.register('controller:user', UserController); + container.register('controller:post', PostController); + + container.typeInjection('controller', 'router', 'router:main'); + + var user = container.lookup('controller:user'); + var post = container.lookup('controller:post'); + + user.router instanceof Router; //=> true + post.router instanceof Router; //=> true + + // both controllers share the same router + user.router === post.router; //=> true + ``` + + @private + @method typeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + typeInjection: function(type, property, fullName) { + + if (this.parent) { illegalChildOperation('typeInjection'); } + + var fullNameType = fullName.split(':')[0]; + if (fullNameType === type) { + throw new Error('Cannot inject a `' + fullName + '` on other ' + type + '(s). Register the `' + fullName + '` as a different type and perform the typeInjection.'); + } + + addTypeInjection(this.typeInjections, type, property, fullName); + }, + + /** + Defines injection rules. + + These rules are used to inject dependencies onto objects when they + are instantiated. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('source:main', Source); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another fullName + // eg. each user model gets a post model + container.injection('model:user', 'post', 'model:post'); + + // injecting one fullName on another type + container.injection('model', 'source', 'source:main'); + + var user = container.lookup('model:user'); + var post = container.lookup('model:post'); + + user.source instanceof Source; //=> true + post.source instanceof Source; //=> true + + user.post instanceof Post; //=> true + + // and both models share the same source + user.source === post.source; //=> true + ``` + + @method injection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + injection: function(fullName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + validateFullName(injectionName); + var normalizedInjectionName = this.normalize(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.typeInjection(fullName, property, normalizedInjectionName); + } + + var normalizedName = this.normalize(fullName); + + if (this.cache[normalizedName]) { + throw new Error("Attempted to register an injection for a type that has already been looked up. ('" + normalizedName + "', '" + property + "', '" + injectionName + "')"); + } + addInjection(this.injections, normalizedName, property, normalizedInjectionName); + }, + + + /** + Used only via `factoryInjection`. + + Provides a specialized form of injection, specifically enabling + all factory of one type to be injected with a reference to another + object. + + For example, provided each factory of type `model` needed a `store`. + one would do the following: + + ```javascript + var container = new Container(); + + container.register('store:main', SomeStore); + + container.factoryTypeInjection('model', 'store', 'store:main'); + + var store = container.lookup('store:main'); + var UserFactory = container.lookupFactory('model:user'); + + UserFactory.store instanceof SomeStore; //=> true + ``` + + @private + @method factoryTypeInjection + @param {String} type + @param {String} property + @param {String} fullName + */ + factoryTypeInjection: function(type, property, fullName) { + if (this.parent) { illegalChildOperation('factoryTypeInjection'); } + + addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName)); + }, + + /** + Defines factory injection rules. + + Similar to regular injection rules, but are run against factories, via + `Container#lookupFactory`. + + These rules are used to inject objects onto factories when they + are looked up. + + Two forms of injections are possible: + + * Injecting one fullName on another fullName + * Injecting one fullName on a type + + Example: + + ```javascript + var container = new Container(); + + container.register('store:main', Store); + container.register('store:secondary', OtherStore); + container.register('model:user', User); + container.register('model:post', Post); + + // injecting one fullName on another type + container.factoryInjection('model', 'store', 'store:main'); + + // injecting one fullName on another fullName + container.factoryInjection('model:post', 'secondaryStore', 'store:secondary'); + + var UserFactory = container.lookupFactory('model:user'); + var PostFactory = container.lookupFactory('model:post'); + var store = container.lookup('store:main'); + + UserFactory.store instanceof Store; //=> true + UserFactory.secondaryStore instanceof OtherStore; //=> false + + PostFactory.store instanceof Store; //=> true + PostFactory.secondaryStore instanceof OtherStore; //=> true + + // and both models share the same source instance + UserFactory.store === PostFactory.store; //=> true + ``` + + @method factoryInjection + @param {String} factoryName + @param {String} property + @param {String} injectionName + */ + factoryInjection: function(fullName, property, injectionName) { + if (this.parent) { illegalChildOperation('injection'); } + + var normalizedName = this.normalize(fullName); + var normalizedInjectionName = this.normalize(injectionName); + + validateFullName(injectionName); + + if (fullName.indexOf(':') === -1) { + return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName); + } + + + if (this.factoryCache[normalizedName]) { + throw new Error('Attempted to register a factoryInjection for a type that has already ' + + 'been looked up. (\'' + normalizedName + '\', \'' + property + '\', \'' + injectionName + '\')'); + } + + addInjection(this.factoryInjections, normalizedName, property, normalizedInjectionName); + }, + + /** + A depth first traversal, destroying the container, its descendant containers and all + their managed objects. + + @method destroy + */ + destroy: function() { + for (var i = 0, length = this.children.length; i < length; i++) { + this.children[i].destroy(); + } + + this.children = []; + + eachDestroyable(this, function(item) { + item.destroy(); + }); + + this.parent = undefined; + this.isDestroyed = true; + }, + + /** + @method reset + */ + reset: function() { + for (var i = 0, length = this.children.length; i < length; i++) { + resetCache(this.children[i]); + } + + resetCache(this); + } + }; + + function resolve(container, normalizedName) { + var cached = container.resolveCache[normalizedName]; + if (cached) { return cached; } + + var resolved = container.resolver(normalizedName) || container.registry[normalizedName]; + container.resolveCache[normalizedName] = resolved; + + return resolved; + } + + function has(container, fullName){ + if (container.cache[fullName]) { + return true; + } + + return !!container.resolve(fullName); + } + + function lookup(container, fullName, options) { + options = options || {}; + + if (container.cache[fullName] && options.singleton !== false) { + return container.cache[fullName]; + } + + var value = instantiate(container, fullName); + + if (value === undefined) { return; } + + if (isSingleton(container, fullName) && options.singleton !== false) { + container.cache[fullName] = value; + } + + return value; + } + + function illegalChildOperation(operation) { + throw new Error(operation + ' is not currently supported on child containers'); + } + + function isSingleton(container, fullName) { + var singleton = option(container, fullName, 'singleton'); + + return singleton !== false; + } + + function buildInjections(container, injections) { + var hash = {}; + + if (!injections) { return hash; } + + var injection, injectable; + + for (var i = 0, length = injections.length; i < length; i++) { + injection = injections[i]; + injectable = lookup(container, injection.fullName); + + if (injectable !== undefined) { + hash[injection.property] = injectable; + } else { + throw new Error('Attempting to inject an unknown injection: `' + injection.fullName + '`'); + } + } + + return hash; + } + + function option(container, fullName, optionName) { + var options = container._options[fullName]; + + if (options && options[optionName] !== undefined) { + return options[optionName]; + } + + var type = fullName.split(':')[0]; + options = container._typeOptions[type]; + + if (options) { + return options[optionName]; + } + } + + function factoryFor(container, fullName) { + var cache = container.factoryCache; + if (cache[fullName]) { + return cache[fullName]; + } + var factory = container.resolve(fullName); + if (factory === undefined) { return; } + + var type = fullName.split(':')[0]; + if (!factory || typeof factory.extend !== 'function' || (!Ember.MODEL_FACTORY_INJECTIONS && type === 'model')) { + // TODO: think about a 'safe' merge style extension + // for now just fallback to create time injection + cache[fullName] = factory; + return factory; + } else { + var injections = injectionsFor(container, fullName); + var factoryInjections = factoryInjectionsFor(container, fullName); + + factoryInjections._toString = container.makeToString(factory, fullName); + + var injectedFactory = factory.extend(injections); + injectedFactory.reopenClass(factoryInjections); + + cache[fullName] = injectedFactory; + + return injectedFactory; + } + } + + function injectionsFor(container, fullName) { + var splitName = fullName.split(':'); + var type = splitName[0]; + var injections = []; + + injections = injections.concat(container.typeInjections[type] || []); + injections = injections.concat(container.injections[fullName] || []); + + injections = buildInjections(container, injections); + injections._debugContainerKey = fullName; + injections.container = container; + + return injections; + } + + function factoryInjectionsFor(container, fullName) { + var splitName = fullName.split(':'); + var type = splitName[0]; + var factoryInjections = []; + + factoryInjections = factoryInjections.concat(container.factoryTypeInjections[type] || []); + factoryInjections = factoryInjections.concat(container.factoryInjections[fullName] || []); + + factoryInjections = buildInjections(container, factoryInjections); + factoryInjections._debugContainerKey = fullName; + + return factoryInjections; + } + + function instantiate(container, fullName) { + var factory = factoryFor(container, fullName); + + if (option(container, fullName, 'instantiate') === false) { + return factory; + } + + if (factory) { + if (typeof factory.create !== 'function') { + throw new Error('Failed to create an instance of \'' + fullName + '\'. ' + + 'Most likely an improperly defined class or an invalid module export.'); + } + + if (typeof factory.extend === 'function') { + // assume the factory was extendable and is already injected + return factory.create(); + } else { + // assume the factory was extendable + // to create time injections + // TODO: support new'ing for instantiation and merge injections for pure JS Functions + return factory.create(injectionsFor(container, fullName)); + } + } + } + + function eachDestroyable(container, callback) { + var cache = container.cache; + var keys = emberKeys(cache); + var key, value; + + for (var i = 0, l = keys.length; i < l; i++) { + key = keys[i]; + value = cache[key]; + + if (option(container, key, 'instantiate') !== false) { + callback(value); + } + } + } + + function resetCache(container) { + eachDestroyable(container, function(value) { + value.destroy(); + }); + + container.cache.dict = dictionary(null); + } + + function addTypeInjection(rules, type, property, fullName) { + var injections = rules[type]; + + if (!injections) { + injections = []; + rules[type] = injections; + } + + injections.push({ + property: property, + fullName: fullName + }); + } + + var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/; + function validateFullName(fullName) { + if (!VALID_FULL_NAME_REGEXP.test(fullName)) { + throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName); + } + return true; + } + + function addInjection(rules, factoryName, property, injectionName) { + var injections = rules[factoryName] = rules[factoryName] || []; + injections.push({ + property: property, + fullName: injectionName + }); + } + + __exports__["default"] = Container; + }); +define("ember-application", + ["ember-metal/core","ember-runtime/system/lazy_load","ember-application/system/dag","ember-application/system/resolver","ember-application/system/application","ember-application/ext/controller"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__) { + "use strict"; + var Ember = __dependency1__["default"]; + var runLoadHooks = __dependency2__.runLoadHooks; + + /** + Ember Application + + @module ember + @submodule ember-application + @requires ember-views, ember-routing + */ + + var DAG = __dependency3__["default"]; + var Resolver = __dependency4__.Resolver; + var DefaultResolver = __dependency4__["default"]; + var Application = __dependency5__["default"]; + // side effect of extending ControllerMixin + + Ember.Application = Application; + Ember.DAG = DAG; + Ember.Resolver = Resolver; + Ember.DefaultResolver = DefaultResolver; + + runLoadHooks('Ember.Application', Application); + }); +define("ember-application/ext/controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/error","ember-metal/utils","ember-metal/computed","ember-runtime/mixins/controller","ember-routing/system/controller_for","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var EmberError = __dependency4__["default"]; + var inspect = __dependency5__.inspect; + var computed = __dependency6__.computed; + var ControllerMixin = __dependency7__["default"]; + var meta = __dependency5__.meta; + var controllerFor = __dependency8__["default"]; + + function verifyNeedsDependencies(controller, container, needs) { + var dependency, i, l; + var missing = []; + + for (i=0, l=needs.length; i 1 ? 'they' : 'it') + " could not be found"); + } + } + + var defaultControllersComputedProperty = computed(function() { + var controller = this; + + return { + needs: get(controller, 'needs'), + container: get(controller, 'container'), + unknownProperty: function(controllerName) { + var needs = this.needs; + var dependency, i, l; + + for (i=0, l=needs.length; i 0) { + + if (this.container) { + verifyNeedsDependencies(this, this.container, needs); + } + + // if needs then initialize controllers proxy + get(this, 'controllers'); + } + + this._super.apply(this, arguments); + }, + + /** + @method controllerFor + @see {Ember.Route#controllerFor} + @deprecated Use `needs` instead + */ + controllerFor: function(controllerName) { + return controllerFor(get(this, 'container'), controllerName); + }, + + /** + Stores the instances of other controllers available from within + this controller. Any controller listed by name in the `needs` + property will be accessible by name through this property. + + ```javascript + App.CommentsController = Ember.ArrayController.extend({ + needs: ['post'], + postTitle: function(){ + var currentPost = this.get('controllers.post'); // instance of App.PostController + return currentPost.get('title'); + }.property('controllers.post.title') + }); + ``` + + @see {Ember.ControllerMixin#needs} + @property {Object} controllers + @default null + */ + controllers: defaultControllersComputedProperty + }); + + __exports__["default"] = ControllerMixin; + }); +define("ember-application/system/application", + ["ember-metal","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-application/system/dag","ember-runtime/system/namespace","ember-runtime/mixins/deferred","ember-application/system/resolver","ember-metal/platform","ember-metal/run_loop","ember-metal/utils","container/container","ember-runtime/controllers/controller","ember-metal/enumerable_utils","ember-runtime/controllers/object_controller","ember-runtime/controllers/array_controller","ember-handlebars/controls/select","ember-views/system/event_dispatcher","ember-views/system/jquery","ember-routing/system/route","ember-routing/system/router","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/location/none_location","ember-routing/system/cache","ember-metal/core","ember-handlebars-compiler","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __dependency27__, __dependency28__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.deprecate, Ember.assert, Ember.libraries, LOG_VERSION, Namespace, BOOTED + var get = __dependency2__.get; + var set = __dependency3__.set; + var runLoadHooks = __dependency4__.runLoadHooks; + var DAG = __dependency5__["default"]; + var Namespace = __dependency6__["default"]; + var DeferredMixin = __dependency7__["default"]; + var DefaultResolver = __dependency8__["default"]; + var create = __dependency9__.create; + var run = __dependency10__["default"]; + var canInvoke = __dependency11__.canInvoke; + var Container = __dependency12__["default"]; + var Controller = __dependency13__["default"]; + var EnumerableUtils = __dependency14__["default"]; + var ObjectController = __dependency15__["default"]; + var ArrayController = __dependency16__["default"]; + var SelectView = __dependency17__["default"]; + var EventDispatcher = __dependency18__["default"]; + //import ContainerDebugAdapter from "ember-extension-support/container_debug_adapter"; + var jQuery = __dependency19__["default"]; + var Route = __dependency20__["default"]; + var Router = __dependency21__["default"]; + var HashLocation = __dependency22__["default"]; + var HistoryLocation = __dependency23__["default"]; + var AutoLocation = __dependency24__["default"]; + var NoneLocation = __dependency25__["default"]; + var BucketCache = __dependency26__["default"]; + + var K = __dependency27__.K; + var EmberHandlebars = __dependency28__["default"]; + + var ContainerDebugAdapter; + function props(obj) { + var properties = []; + + for (var key in obj) { + properties.push(key); + } + + return properties; + } + + /** + An instance of `Ember.Application` is the starting point for every Ember + application. It helps to instantiate, initialize and coordinate the many + objects that make up your app. + + Each Ember app has one and only one `Ember.Application` object. In fact, the + very first thing you should do in your application is create the instance: + + ```javascript + window.App = Ember.Application.create(); + ``` + + Typically, the application object is the only global variable. All other + classes in your app should be properties on the `Ember.Application` instance, + which highlights its first role: a global namespace. + + For example, if you define a view class, it might look like this: + + ```javascript + App.MyView = Ember.View.extend(); + ``` + + By default, calling `Ember.Application.create()` will automatically initialize + your application by calling the `Ember.Application.initialize()` method. If + you need to delay initialization, you can call your app's `deferReadiness()` + method. When you are ready for your app to be initialized, call its + `advanceReadiness()` method. + + You can define a `ready` method on the `Ember.Application` instance, which + will be run by Ember when the application is initialized. + + Because `Ember.Application` inherits from `Ember.Namespace`, any classes + you create will have useful string representations when calling `toString()`. + See the `Ember.Namespace` documentation for more information. + + While you can think of your `Ember.Application` as a container that holds the + other classes in your application, there are several other responsibilities + going on under-the-hood that you may want to understand. + + ### Event Delegation + + Ember uses a technique called _event delegation_. This allows the framework + to set up a global, shared event listener instead of requiring each view to + do it manually. For example, instead of each view registering its own + `mousedown` listener on its associated element, Ember sets up a `mousedown` + listener on the `body`. + + If a `mousedown` event occurs, Ember will look at the target of the event and + start walking up the DOM node tree, finding corresponding views and invoking + their `mouseDown` method as it goes. + + `Ember.Application` has a number of default events that it listens for, as + well as a mapping from lowercase events to camel-cased view method names. For + example, the `keypress` event causes the `keyPress` method on the view to be + called, the `dblclick` event causes `doubleClick` to be called, and so on. + + If there is a bubbling browser event that Ember does not listen for by + default, you can specify custom events and their corresponding view method + names by setting the application's `customEvents` property: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + paste: "paste" + } + }); + ``` + + By default, the application sets up these event listeners on the document + body. However, in cases where you are embedding an Ember application inside + an existing page, you may want it to set up the listeners on an element + inside the body. + + For example, if only events inside a DOM element with the ID of `ember-app` + should be delegated, set your application's `rootElement` property: + + ```javascript + window.App = Ember.Application.create({ + rootElement: '#ember-app' + }); + ``` + + The `rootElement` can be either a DOM element or a jQuery-compatible selector + string. Note that *views appended to the DOM outside the root element will + not receive events.* If you specify a custom root element, make sure you only + append views inside it! + + To learn more about the advantages of event delegation and the Ember view + layer, and a list of the event listeners that are setup by default, visit the + [Ember View Layer guide](http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_event-delegation). + + ### Initializers + + Libraries on top of Ember can add initializers, like so: + + ```javascript + Ember.Application.initializer({ + name: 'api-adapter', + + initialize: function(container, application) { + application.register('api-adapter:main', ApiAdapter); + } + }); + ``` + + Initializers provide an opportunity to access the container, which + organizes the different components of an Ember application. Additionally + they provide a chance to access the instantiated application. Beyond + being used for libraries, initializers are also a great way to organize + dependency injection or setup in your own application. + + ### Routing + + In addition to creating your application's router, `Ember.Application` is + also responsible for telling the router when to start routing. Transitions + between routes can be logged with the `LOG_TRANSITIONS` flag, and more + detailed intra-transition logging can be logged with + the `LOG_TRANSITIONS_INTERNAL` flag: + + ```javascript + window.App = Ember.Application.create({ + LOG_TRANSITIONS: true, // basic logging of successful transitions + LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps + }); + ``` + + By default, the router will begin trying to translate the current URL into + application state once the browser emits the `DOMContentReady` event. If you + need to defer routing, you can call the application's `deferReadiness()` + method. Once routing can begin, call the `advanceReadiness()` method. + + If there is any setup required before routing begins, you can implement a + `ready()` method on your app that will be invoked immediately before routing + begins. + ``` + + @class Application + @namespace Ember + @extends Ember.Namespace + */ + + var Application = Namespace.extend(DeferredMixin, { + _suppressDeferredDeprecation: true, + + /** + The root DOM element of the Application. This can be specified as an + element or a + [jQuery-compatible selector string](http://api.jquery.com/category/selectors/). + + This is the element that will be passed to the Application's, + `eventDispatcher`, which sets up the listeners for event delegation. Every + view in your application should be a child of the element you specify here. + + @property rootElement + @type DOMElement + @default 'body' + */ + rootElement: 'body', + + /** + The `Ember.EventDispatcher` responsible for delegating events to this + application's views. + + The event dispatcher is created by the application at initialization time + and sets up event listeners on the DOM element described by the + application's `rootElement` property. + + See the documentation for `Ember.EventDispatcher` for more information. + + @property eventDispatcher + @type Ember.EventDispatcher + @default null + */ + eventDispatcher: null, + + /** + The DOM events for which the event dispatcher should listen. + + By default, the application's `Ember.EventDispatcher` listens + for a set of standard DOM events, such as `mousedown` and + `keyup`, and delegates them to your application's `Ember.View` + instances. + + If you would like additional bubbling events to be delegated to your + views, set your `Ember.Application`'s `customEvents` property + to a hash containing the DOM event name as the key and the + corresponding view method name as the value. For example: + + ```javascript + App = Ember.Application.create({ + customEvents: { + // add support for the paste event + paste: "paste" + } + }); + ``` + + @property customEvents + @type Object + @default null + */ + customEvents: null, + + // Start off the number of deferrals at 1. This will be + // decremented by the Application's own `initialize` method. + _readinessDeferrals: 1, + + init: function() { + if (!this.$) { this.$ = jQuery; } + this.__container__ = this.buildContainer(); + + this.Router = this.defaultRouter(); + + this._super(); + + this.scheduleInitialize(); + + Ember.libraries.registerCoreLibrary('Handlebars' + (EmberHandlebars.compile ? '' : '-runtime'), EmberHandlebars.VERSION); + Ember.libraries.registerCoreLibrary('jQuery', jQuery().jquery); + + if ( Ember.LOG_VERSION ) { + Ember.LOG_VERSION = false; // we only need to see this once per Application#init + + var nameLengths = EnumerableUtils.map(Ember.libraries, function(item) { + return get(item, "name.length"); + }); + + var maxNameLength = Math.max.apply(this, nameLengths); + + Ember.libraries.each(function(name, version) { + var spaces = new Array(maxNameLength - name.length + 1).join(" "); + }); + } + }, + + /** + Build the container for the current application. + + Also register a default application view in case the application + itself does not. + + @private + @method buildContainer + @return {Ember.Container} the configured container + */ + buildContainer: function() { + var container = this.__container__ = Application.buildContainer(this); + + return container; + }, + + /** + If the application has not opted out of routing and has not explicitly + defined a router, supply a default router for the application author + to configure. + + This allows application developers to do: + + ```javascript + var App = Ember.Application.create(); + + App.Router.map(function() { + this.resource('posts'); + }); + ``` + + @private + @method defaultRouter + @return {Ember.Router} the default router + */ + + defaultRouter: function() { + if (this.Router === false) { return; } + var container = this.__container__; + + if (this.Router) { + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + return container.lookupFactory('router:main'); + }, + + /** + Automatically initialize the application once the DOM has + become ready. + + The initialization itself is scheduled on the actions queue + which ensures that application loading finishes before + booting. + + If you are asynchronously loading code, you should call + `deferReadiness()` to defer booting, and then call + `advanceReadiness()` once all of your code has finished + loading. + + @private + @method scheduleInitialize + */ + scheduleInitialize: function() { + var self = this; + + if (!this.$ || this.$.isReady) { + run.schedule('actions', self, '_initialize'); + } else { + this.$().ready(function runInitialize() { + run(self, '_initialize'); + }); + } + }, + + /** + Use this to defer readiness until some condition is true. + + Example: + + ```javascript + App = Ember.Application.create(); + App.deferReadiness(); + + jQuery.getJSON("/auth-token", function(token) { + App.token = token; + App.advanceReadiness(); + }); + ``` + + This allows you to perform asynchronous setup logic and defer + booting your application until the setup has finished. + + However, if the setup requires a loading UI, it might be better + to use the router for this purpose. + + @method deferReadiness + */ + deferReadiness: function() { + this._readinessDeferrals++; + }, + + /** + Call `advanceReadiness` after any asynchronous setup logic has completed. + Each call to `deferReadiness` must be matched by a call to `advanceReadiness` + or the application will never become ready and routing will not begin. + + @method advanceReadiness + @see {Ember.Application#deferReadiness} + */ + advanceReadiness: function() { + this._readinessDeferrals--; + + if (this._readinessDeferrals === 0) { + run.once(this, this.didBecomeReady); + } + }, + + /** + Registers a factory that can be used for dependency injection (with + `App.inject`) or for service lookup. Each factory is registered with + a full name including two parts: `type:name`. + + A simple example: + + ```javascript + var App = Ember.Application.create(); + App.Orange = Ember.Object.extend(); + App.register('fruit:favorite', App.Orange); + ``` + + Ember will resolve factories from the `App` namespace automatically. + For example `App.CarsController` will be discovered and returned if + an application requests `controller:cars`. + + An example of registering a controller with a non-standard name: + + ```javascript + var App = Ember.Application.create(), + Session = Ember.Controller.extend(); + + App.register('controller:session', Session); + + // The Session controller can now be treated like a normal controller, + // despite its non-standard name. + App.ApplicationController = Ember.Controller.extend({ + needs: ['session'] + }); + ``` + + Registered factories are **instantiated** by having `create` + called on them. Additionally they are **singletons**, each time + they are looked up they return the same instance. + + Some examples modifying that default behavior: + + ```javascript + var App = Ember.Application.create(); + + App.Person = Ember.Object.extend(); + App.Orange = Ember.Object.extend(); + App.Email = Ember.Object.extend(); + App.session = Ember.Object.create(); + + App.register('model:user', App.Person, {singleton: false }); + App.register('fruit:favorite', App.Orange); + App.register('communication:main', App.Email, {singleton: false}); + App.register('session', App.session, {instantiate: false}); + ``` + + @method register + @param fullName {String} type:name (e.g., 'model:user') + @param factory {Function} (e.g., App.Person) + @param options {Object} (optional) disable instantiation or singleton usage + **/ + register: function() { + var container = this.__container__; + container.register.apply(container, arguments); + }, + + /** + Define a dependency injection onto a specific factory or all factories + of a type. + + When Ember instantiates a controller, view, or other framework component + it can attach a dependency to that component. This is often used to + provide services to a set of framework components. + + An example of providing a session object to all controllers: + + ```javascript + var App = Ember.Application.create(), + Session = Ember.Object.extend({ isAuthenticated: false }); + + // A factory must be registered before it can be injected + App.register('session:main', Session); + + // Inject 'session:main' onto all factories of the type 'controller' + // with the name 'session' + App.inject('controller', 'session', 'session:main'); + + App.IndexController = Ember.Controller.extend({ + isLoggedIn: Ember.computed.alias('session.isAuthenticated') + }); + ``` + + Injections can also be performed on specific factories. + + ```javascript + App.inject(, , ) + App.inject('route', 'source', 'source:main') + App.inject('route:application', 'email', 'model:email') + ``` + + It is important to note that injections can only be performed on + classes that are instantiated by Ember itself. Instantiating a class + directly (via `create` or `new`) bypasses the dependency injection + system. + + Ember-Data instantiates its models in a unique manner, and consequently + injections onto models (or all models) will not work as expected. Injections + on models can be enabled by setting `Ember.MODEL_FACTORY_INJECTIONS` + to `true`. + + @method inject + @param factoryNameOrType {String} + @param property {String} + @param injectionName {String} + **/ + inject: function() { + var container = this.__container__; + container.injection.apply(container, arguments); + }, + + /** + Calling initialize manually is not supported. + + Please see Ember.Application#advanceReadiness and + Ember.Application#deferReadiness. + + @private + @deprecated + @method initialize + **/ + initialize: function() { + }, + + /** + Initialize the application. This happens automatically. + + Run any initializers and run the application load hook. These hooks may + choose to defer readiness. For example, an authentication hook might want + to defer readiness until the auth token has been retrieved. + + @private + @method _initialize + */ + _initialize: function() { + if (this.isDestroyed) { return; } + + // At this point, the App.Router must already be assigned + if (this.Router) { + var container = this.__container__; + container.unregister('router:main'); + container.register('router:main', this.Router); + } + + this.runInitializers(); + runLoadHooks('application', this); + + // At this point, any initializers or load hooks that would have wanted + // to defer readiness have fired. In general, advancing readiness here + // will proceed to didBecomeReady. + this.advanceReadiness(); + + return this; + }, + + /** + Reset the application. This is typically used only in tests. It cleans up + the application in the following order: + + 1. Deactivate existing routes + 2. Destroy all objects in the container + 3. Create a new application container + 4. Re-route to the existing url + + Typical Example: + + ```javascript + + var App; + + run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + App.reset(); + } + }); + + test("first test", function() { + // App is freshly reset + }); + + test("first test", function() { + // App is again freshly reset + }); + ``` + + Advanced Example: + + Occasionally you may want to prevent the app from initializing during + setup. This could enable extra configuration, or enable asserting prior + to the app becoming ready. + + ```javascript + + var App; + + run(function() { + App = Ember.Application.create(); + }); + + module("acceptance test", { + setup: function() { + run(function() { + App.reset(); + App.deferReadiness(); + }); + } + }); + + test("first test", function() { + ok(true, 'something before app is initialized'); + + run(function() { + App.advanceReadiness(); + }); + ok(true, 'something after app is initialized'); + }); + ``` + + @method reset + **/ + reset: function() { + this._readinessDeferrals = 1; + + function handleReset() { + var router = this.__container__.lookup('router:main'); + router.reset(); + + run(this.__container__, 'destroy'); + + this.buildContainer(); + + run.schedule('actions', this, function() { + this._initialize(); + }); + } + + run.join(this, handleReset); + }, + + /** + @private + @method runInitializers + */ + runInitializers: function() { + var initializersByName = get(this.constructor, 'initializers'); + var initializers = props(initializersByName); + var container = this.__container__; + var graph = new DAG(); + var namespace = this; + var name, initializer; + + for (var i = 0; i < initializers.length; i++) { + initializer = initializersByName[initializers[i]]; + graph.addEdges(initializer.name, initializer.initialize, initializer.before, initializer.after); + } + + graph.topsort(function (vertex) { + var initializer = vertex.value; + initializer(container, namespace); + }); + }, + + /** + @private + @method didBecomeReady + */ + didBecomeReady: function() { + this.setupEventDispatcher(); + this.ready(); // user hook + this.startRouting(); + + if (!Ember.testing) { + // Eagerly name all classes that are already loaded + Ember.Namespace.processAll(); + Ember.BOOTED = true; + } + + this.resolve(this); + }, + + /** + Setup up the event dispatcher to receive events on the + application's `rootElement` with any registered + `customEvents`. + + @private + @method setupEventDispatcher + */ + setupEventDispatcher: function() { + var customEvents = get(this, 'customEvents'); + var rootElement = get(this, 'rootElement'); + var dispatcher = this.__container__.lookup('event_dispatcher:main'); + + set(this, 'eventDispatcher', dispatcher); + dispatcher.setup(customEvents, rootElement); + }, + + /** + If the application has a router, use it to route to the current URL, and + trigger a new call to `route` whenever the URL changes. + + @private + @method startRouting + @property router {Ember.Router} + */ + startRouting: function() { + var router = this.__container__.lookup('router:main'); + if (!router) { return; } + + router.startRouting(); + }, + + handleURL: function(url) { + var router = this.__container__.lookup('router:main'); + + router.handleURL(url); + }, + + /** + Called when the Application has become ready. + The call will be delayed until the DOM has become ready. + + @event ready + */ + ready: K, + + /** + @deprecated Use 'Resolver' instead + Set this to provide an alternate class to `Ember.DefaultResolver` + + + @property resolver + */ + resolver: null, + + /** + Set this to provide an alternate class to `Ember.DefaultResolver` + + @property resolver + */ + Resolver: null, + + willDestroy: function() { + Ember.BOOTED = false; + // Ensure deactivation of routes before objects are destroyed + this.__container__.lookup('router:main').reset(); + + this.__container__.destroy(); + }, + + initializer: function(options) { + this.constructor.initializer(options); + }, + + /** + @method then + @private + @deprecated + */ + then: function() { + + this._super.apply(this, arguments); + } + }); + + Application.reopenClass({ + initializers: Object.create(null), + + /** + Initializer receives an object which has the following attributes: + `name`, `before`, `after`, `initialize`. The only required attribute is + `initialize, all others are optional. + + * `name` allows you to specify under which name the initializer is registered. + This must be a unique name, as trying to register two initializers with the + same name will result in an error. + + ```javascript + Ember.Application.initializer({ + name: 'namedInitializer', + initialize: function(container, application) { + Ember.debug("Running namedInitializer!"); + } + }); + ``` + + * `before` and `after` are used to ensure that this initializer is ran prior + or after the one identified by the value. This value can be a single string + or an array of strings, referencing the `name` of other initializers. + + An example of ordering initializers, we create an initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'first', + initialize: function(container, application) { + Ember.debug("First initializer!"); + } + }); + + // DEBUG: First initializer! + ``` + + We add another initializer named `second`, specifying that it should run + after the initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'second', + after: 'first', + + initialize: function(container, application) { + Ember.debug("Second initializer!"); + } + }); + + // DEBUG: First initializer! + // DEBUG: Second initializer! + ``` + + Afterwards we add a further initializer named `pre`, this time specifying + that it should run before the initializer named `first`: + + ```javascript + Ember.Application.initializer({ + name: 'pre', + before: 'first', + + initialize: function(container, application) { + Ember.debug("Pre initializer!"); + } + }); + + // DEBUG: Pre initializer! + // DEBUG: First initializer! + // DEBUG: Second initializer! + ``` + + Finally we add an initializer named `post`, specifying it should run after + both the `first` and the `second` initializers: + + ```javascript + Ember.Application.initializer({ + name: 'post', + after: ['first', 'second'], + + initialize: function(container, application) { + Ember.debug("Post initializer!"); + } + }); + + // DEBUG: Pre initializer! + // DEBUG: First initializer! + // DEBUG: Second initializer! + // DEBUG: Post initializer! + ``` + + * `initialize` is a callback function that receives two arguments, `container` + and `application` on which you can operate. + + Example of using `container` to preload data into the store: + + ```javascript + Ember.Application.initializer({ + name: "preload-data", + + initialize: function(container, application) { + var store = container.lookup('store:main'); + store.pushPayload(preloadedData); + } + }); + ``` + + Example of using `application` to register an adapter: + + ```javascript + Ember.Application.initializer({ + name: 'api-adapter', + + initialize: function(container, application) { + application.register('api-adapter:main', ApiAdapter); + } + }); + ``` + + @method initializer + @param initializer {Object} + */ + initializer: function(initializer) { + // If this is the first initializer being added to a subclass, we are going to reopen the class + // to make sure we have a new `initializers` object, which extends from the parent class' using + // prototypal inheritance. Without this, attempting to add initializers to the subclass would + // pollute the parent class as well as other subclasses. + if (this.superclass.initializers !== undefined && this.superclass.initializers === this.initializers) { + this.reopenClass({ + initializers: create(this.initializers) + }); + } + + + this.initializers[initializer.name] = initializer; + }, + + /** + This creates a container with the default Ember naming conventions. + + It also configures the container: + + * registered views are created every time they are looked up (they are + not singletons) + * registered templates are not factories; the registered value is + returned directly. + * the router receives the application as its `namespace` property + * all controllers receive the router as their `target` and `controllers` + properties + * all controllers receive the application as their `namespace` property + * the application view receives the application controller as its + `controller` property + * the application view receives the application template as its + `defaultTemplate` property + + @private + @method buildContainer + @static + @param {Ember.Application} namespace the application to build the + container for. + @return {Ember.Container} the built container + */ + buildContainer: function(namespace) { + var container = new Container(); + + container.set = set; + container.resolver = resolverFor(namespace); + container.normalizeFullName = container.resolver.normalize; + container.describe = container.resolver.describe; + container.makeToString = container.resolver.makeToString; + + container.optionsForType('component', { singleton: false }); + container.optionsForType('view', { singleton: false }); + container.optionsForType('template', { instantiate: false }); + container.optionsForType('helper', { instantiate: false }); + + container.register('application:main', namespace, { instantiate: false }); + + container.register('controller:basic', Controller, { instantiate: false }); + container.register('controller:object', ObjectController, { instantiate: false }); + container.register('controller:array', ArrayController, { instantiate: false }); + + container.register('view:select', SelectView); + + container.register('route:basic', Route, { instantiate: false }); + container.register('event_dispatcher:main', EventDispatcher); + + container.register('router:main', Router); + container.injection('router:main', 'namespace', 'application:main'); + + container.register('location:auto', AutoLocation); + container.register('location:hash', HashLocation); + container.register('location:history', HistoryLocation); + container.register('location:none', NoneLocation); + + container.injection('controller', 'target', 'router:main'); + container.injection('controller', 'namespace', 'application:main'); + + container.register('-bucket-cache:main', BucketCache); + container.injection('router', '_bucketCache', '-bucket-cache:main'); + container.injection('route', '_bucketCache', '-bucket-cache:main'); + container.injection('controller', '_bucketCache', '-bucket-cache:main'); + + container.injection('route', 'router', 'router:main'); + container.injection('location', 'rootURL', '-location-setting:root-url'); + + // DEBUGGING + container.register('resolver-for-debugging:main', container.resolver.__resolver__, { instantiate: false }); + container.injection('container-debug-adapter:main', 'resolver', 'resolver-for-debugging:main'); + container.injection('data-adapter:main', 'containerDebugAdapter', 'container-debug-adapter:main'); + // Custom resolver authors may want to register their own ContainerDebugAdapter with this key + + // ES6TODO: resolve this via import once ember-application package is ES6'ed + if (!ContainerDebugAdapter) { ContainerDebugAdapter = requireModule('ember-extension-support/container_debug_adapter')['default']; } + container.register('container-debug-adapter:main', ContainerDebugAdapter); + + return container; + } + }); + + /** + This function defines the default lookup rules for container lookups: + + * templates are looked up on `Ember.TEMPLATES` + * other names are looked up on the application after classifying the name. + For example, `controller:post` looks up `App.PostController` by default. + * if the default lookup fails, look for registered classes on the container + + This allows the application to register default injections in the container + that could be overridden by the normal naming convention. + + @private + @method resolverFor + @param {Ember.Namespace} namespace the namespace to look for classes + @return {*} the resolved value for a given lookup + */ + function resolverFor(namespace) { + if (namespace.get('resolver')) { + } + + var ResolverClass = namespace.get('resolver') || namespace.get('Resolver') || DefaultResolver; + var resolver = ResolverClass.create({ + namespace: namespace + }); + + function resolve(fullName) { + return resolver.resolve(fullName); + } + + resolve.describe = function(fullName) { + return resolver.lookupDescription(fullName); + }; + + resolve.makeToString = function(factory, fullName) { + return resolver.makeToString(factory, fullName); + }; + + resolve.normalize = function(fullName) { + if (resolver.normalize) { + return resolver.normalize(fullName); + } else { + return fullName; + } + }; + + resolve.__resolver__ = resolver; + + return resolve; + } + + __exports__["default"] = Application; + }); +define("ember-application/system/dag", + ["ember-metal/error","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberError = __dependency1__["default"]; + + function visit(vertex, fn, visited, path) { + var name = vertex.name; + var vertices = vertex.incoming; + var names = vertex.incomingNames; + var len = names.length; + var i; + + if (!visited) { + visited = {}; + } + if (!path) { + path = []; + } + if (visited.hasOwnProperty(name)) { + return; + } + path.push(name); + visited[name] = true; + for (i = 0; i < len; i++) { + visit(vertices[names[i]], fn, visited, path); + } + fn(vertex, path); + path.pop(); + } + + + /** + * DAG stands for Directed acyclic graph. + * + * It is used to build a graph of dependencies checking that there isn't circular + * dependencies. p.e Registering initializers with a certain precedence order. + * + * @class DAG + * @constructor + */ + function DAG() { + this.names = []; + this.vertices = Object.create(null); + } + + /** + * DAG Vertex + * + * @class Vertex + * @constructor + */ + + function Vertex(name) { + this.name = name; + this.incoming = {}; + this.incomingNames = []; + this.hasOutgoing = false; + this.value = null; + } + + /** + * Adds a vertex entry to the graph unless it is already added. + * + * @private + * @method add + * @param {String} name The name of the vertex to add + */ + DAG.prototype.add = function(name) { + if (!name) { + throw new Error("Can't add Vertex without name"); + } + if (this.vertices[name] !== undefined) { + return this.vertices[name]; + } + var vertex = new Vertex(name); + this.vertices[name] = vertex; + this.names.push(name); + return vertex; + }; + + /** + * Adds a vertex to the graph and sets its value. + * + * @private + * @method map + * @param {String} name The name of the vertex. + * @param value The value to put in the vertex. + */ + DAG.prototype.map = function(name, value) { + this.add(name).value = value; + }; + + /** + * Connects the vertices with the given names, adding them to the graph if + * necessary, only if this does not produce is any circular dependency. + * + * @private + * @method addEdge + * @param {String} fromName The name the vertex where the edge starts. + * @param {String} toName The name the vertex where the edge ends. + */ + DAG.prototype.addEdge = function(fromName, toName) { + if (!fromName || !toName || fromName === toName) { + return; + } + var from = this.add(fromName); + var to = this.add(toName); + if (to.incoming.hasOwnProperty(fromName)) { + return; + } + function checkCycle(vertex, path) { + if (vertex.name === toName) { + throw new EmberError("cycle detected: " + toName + " <- " + path.join(" <- ")); + } + } + visit(from, checkCycle); + from.hasOutgoing = true; + to.incoming[fromName] = from; + to.incomingNames.push(fromName); + }; + + /** + * Visits all the vertex of the graph calling the given function with each one, + * ensuring that the vertices are visited respecting their precedence. + * + * @method topsort + * @param {Function} fn The function to be invoked on each vertex. + */ + DAG.prototype.topsort = function(fn) { + var visited = {}; + var vertices = this.vertices; + var names = this.names; + var len = names.length; + var i, vertex; + + for (i = 0; i < len; i++) { + vertex = vertices[names[i]]; + if (!vertex.hasOutgoing) { + visit(vertex, fn, visited); + } + } + }; + + /** + * Adds a vertex with the given name and value to the graph and joins it with the + * vertices referenced in _before_ and _after_. If there isn't vertices with those + * names, they are added too. + * + * If either _before_ or _after_ are falsy/empty, the added vertex will not have + * an incoming/outgoing edge. + * + * @method addEdges + * @param {String} name The name of the vertex to be added. + * @param value The value of that vertex. + * @param before An string or array of strings with the names of the vertices before + * which this vertex must be visited. + * @param after An string or array of strings with the names of the vertex after + * which this vertex must be visited. + * + */ + DAG.prototype.addEdges = function(name, value, before, after) { + var i; + this.map(name, value); + if (before) { + if (typeof before === 'string') { + this.addEdge(name, before); + } else { + for (i = 0; i < before.length; i++) { + this.addEdge(name, before[i]); + } + } + } + if (after) { + if (typeof after === 'string') { + this.addEdge(after, name); + } else { + for (i = 0; i < after.length; i++) { + this.addEdge(after[i], name); + } + } + } + }; + + __exports__["default"] = DAG; + }); +define("ember-application/system/resolver", + ["ember-metal/core","ember-metal/property_get","ember-metal/logger","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/system/namespace","ember-handlebars","ember-metal/dictionary","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-application + */ + + var Ember = __dependency1__["default"]; + // Ember.TEMPLATES, Ember.assert + var get = __dependency2__.get; + var Logger = __dependency3__["default"]; + var classify = __dependency4__.classify; + var capitalize = __dependency4__.capitalize; + var decamelize = __dependency4__.decamelize; + var EmberObject = __dependency5__["default"]; + var Namespace = __dependency6__["default"]; + var EmberHandlebars = __dependency7__["default"]; + + var Resolver = EmberObject.extend({ + /** + This will be set to the Application instance when it is + created. + + @property namespace + */ + namespace: null, + normalize: Ember.required(Function), + resolve: Ember.required(Function), + parseName: Ember.required(Function), + lookupDescription: Ember.required(Function), + makeToString: Ember.required(Function), + resolveOther: Ember.required(Function), + _logLookup: Ember.required(Function) + }); + __exports__.Resolver = Resolver; + /** + The DefaultResolver defines the default lookup rules to resolve + container lookups before consulting the container for registered + items: + + * templates are looked up on `Ember.TEMPLATES` + * other names are looked up on the application after converting + the name. For example, `controller:post` looks up + `App.PostController` by default. + * there are some nuances (see examples below) + + ### How Resolving Works + + The container calls this object's `resolve` method with the + `fullName` argument. + + It first parses the fullName into an object using `parseName`. + + Then it checks for the presence of a type-specific instance + method of the form `resolve[Type]` and calls it if it exists. + For example if it was resolving 'template:post', it would call + the `resolveTemplate` method. + + Its last resort is to call the `resolveOther` method. + + The methods of this object are designed to be easy to override + in a subclass. For example, you could enhance how a template + is resolved like so: + + ```javascript + App = Ember.Application.create({ + Resolver: Ember.DefaultResolver.extend({ + resolveTemplate: function(parsedName) { + var resolvedTemplate = this._super(parsedName); + if (resolvedTemplate) { return resolvedTemplate; } + return Ember.TEMPLATES['not_found']; + } + }) + }); + ``` + + Some examples of how names are resolved: + + ``` + 'template:post' //=> Ember.TEMPLATES['post'] + 'template:posts/byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:posts.byline' //=> Ember.TEMPLATES['posts/byline'] + 'template:blogPost' //=> Ember.TEMPLATES['blogPost'] + // OR + // Ember.TEMPLATES['blog_post'] + 'controller:post' //=> App.PostController + 'controller:posts.index' //=> App.PostsIndexController + 'controller:blog/post' //=> Blog.PostController + 'controller:basic' //=> Ember.Controller + 'route:post' //=> App.PostRoute + 'route:posts.index' //=> App.PostsIndexRoute + 'route:blog/post' //=> Blog.PostRoute + 'route:basic' //=> Ember.Route + 'view:post' //=> App.PostView + 'view:posts.index' //=> App.PostsIndexView + 'view:blog/post' //=> Blog.PostView + 'view:basic' //=> Ember.View + 'foo:post' //=> App.PostFoo + 'model:post' //=> App.Post + ``` + + @class DefaultResolver + @namespace Ember + @extends Ember.Object + */ + var dictionary = __dependency8__["default"]; + + __exports__["default"] = EmberObject.extend({ + /** + This will be set to the Application instance when it is + created. + + @property namespace + */ + namespace: null, + + init: function() { + this._parseNameCache = dictionary(null); + }, + normalize: function(fullName) { + var split = fullName.split(':', 2); + var type = split[0]; + var name = split[1]; + + + if (type !== 'template') { + var result = name; + + if (result.indexOf('.') > -1) { + result = result.replace(/\.(.)/g, function(m) { + return m.charAt(1).toUpperCase(); + }); + } + + if (name.indexOf('_') > -1) { + result = result.replace(/_(.)/g, function(m) { + return m.charAt(1).toUpperCase(); + }); + } + + return type + ':' + result; + } else { + return fullName; + } + }, + + + /** + This method is called via the container's resolver method. + It parses the provided `fullName` and then looks up and + returns the appropriate template or class. + + @method resolve + @param {String} fullName the lookup string + @return {Object} the resolved factory + */ + resolve: function(fullName) { + var parsedName = this.parseName(fullName); + var resolveMethodName = parsedName.resolveMethodName; + var resolved; + + if (!(parsedName.name && parsedName.type)) { + throw new TypeError('Invalid fullName: `' + fullName + '`, must be of the form `type:name` '); + } + + if (this[resolveMethodName]) { + resolved = this[resolveMethodName](parsedName); + } + + if (!resolved) { + resolved = this.resolveOther(parsedName); + } + + if (parsedName.root && parsedName.root.LOG_RESOLVER) { + this._logLookup(resolved, parsedName); + } + + return resolved; + }, + /** + Convert the string name of the form 'type:name' to + a Javascript object with the parsed aspects of the name + broken out. + + @protected + @param {String} fullName the lookup string + @method parseName + */ + + parseName: function(fullName) { + return this._parseNameCache[fullName] || ( + this._parseNameCache[fullName] = this._parseName(fullName) + ); + }, + + _parseName: function(fullName) { + var nameParts = fullName.split(':'); + var type = nameParts[0], fullNameWithoutType = nameParts[1]; + var name = fullNameWithoutType; + var namespace = get(this, 'namespace'); + var root = namespace; + + if (type !== 'template' && name.indexOf('/') !== -1) { + var parts = name.split('/'); + name = parts[parts.length - 1]; + var namespaceName = capitalize(parts.slice(0, -1).join('.')); + root = Namespace.byName(namespaceName); + + } + + return { + fullName: fullName, + type: type, + fullNameWithoutType: fullNameWithoutType, + name: name, + root: root, + resolveMethodName: 'resolve' + classify(type) + }; + }, + + /** + Returns a human-readable description for a fullName. Used by the + Application namespace in assertions to describe the + precise name of the class that Ember is looking for, rather than + container keys. + + @protected + @param {String} fullName the lookup string + @method lookupDescription + */ + lookupDescription: function(fullName) { + var parsedName = this.parseName(fullName); + + if (parsedName.type === 'template') { + return 'template at ' + parsedName.fullNameWithoutType.replace(/\./g, '/'); + } + + var description = parsedName.root + '.' + classify(parsedName.name); + + if (parsedName.type !== 'model') { + description += classify(parsedName.type); + } + + return description; + }, + + makeToString: function(factory, fullName) { + return factory.toString(); + }, + /** + Given a parseName object (output from `parseName`), apply + the conventions expected by `Ember.Router` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method useRouterNaming + */ + useRouterNaming: function(parsedName) { + parsedName.name = parsedName.name.replace(/\./g, '_'); + if (parsedName.name === 'basic') { + parsedName.name = ''; + } + }, + /** + Look up the template in Ember.TEMPLATES + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveTemplate + */ + resolveTemplate: function(parsedName) { + var templateName = parsedName.fullNameWithoutType.replace(/\./g, '/'); + + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + + templateName = decamelize(templateName); + if (Ember.TEMPLATES[templateName]) { + return Ember.TEMPLATES[templateName]; + } + }, + + /** + Lookup the view using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveView + */ + resolveView: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + + /** + Lookup the controller using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveController + */ + resolveController: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + /** + Lookup the route using `resolveOther` + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveRoute + */ + resolveRoute: function(parsedName) { + this.useRouterNaming(parsedName); + return this.resolveOther(parsedName); + }, + + /** + Lookup the model on the Application namespace + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveModel + */ + resolveModel: function(parsedName) { + var className = classify(parsedName.name); + var factory = get(parsedName.root, className); + + if (factory) { return factory; } + }, + /** + Look up the specified object (from parsedName) on the appropriate + namespace (usually on the Application) + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveHelper + */ + resolveHelper: function(parsedName) { + return this.resolveOther(parsedName) || EmberHandlebars.helpers[parsedName.fullNameWithoutType]; + }, + /** + Look up the specified object (from parsedName) on the appropriate + namespace (usually on the Application) + + @protected + @param {Object} parsedName a parseName object with the parsed + fullName lookup string + @method resolveOther + */ + resolveOther: function(parsedName) { + var className = classify(parsedName.name) + classify(parsedName.type); + var factory = get(parsedName.root, className); + if (factory) { return factory; } + }, + + /** + @method _logLookup + @param {Boolean} found + @param {Object} parsedName + @private + */ + _logLookup: function(found, parsedName) { + var symbol, padding; + + if (found) { symbol = '[✓]'; } + else { symbol = '[ ]'; } + + if (parsedName.fullName.length > 60) { + padding = '.'; + } else { + padding = new Array(60 - parsedName.fullName.length).join('.'); + } + + Logger.info(symbol, parsedName.fullName, padding, this.lookupDescription(parsedName.fullName)); + } + }); + }); +define("ember-extension-support", + ["ember-metal/core","ember-extension-support/data_adapter","ember-extension-support/container_debug_adapter"], + function(__dependency1__, __dependency2__, __dependency3__) { + "use strict"; + /** + Ember Extension Support + + @module ember + @submodule ember-extension-support + @requires ember-application + */ + + var Ember = __dependency1__["default"]; + var DataAdapter = __dependency2__["default"]; + var ContainerDebugAdapter = __dependency3__["default"]; + + Ember.DataAdapter = DataAdapter; + Ember.ContainerDebugAdapter = ContainerDebugAdapter; + }); +define("ember-extension-support/container_debug_adapter", + ["ember-metal/core","ember-runtime/system/native_array","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var emberA = __dependency2__.A; + var typeOf = __dependency3__.typeOf; + var dasherize = __dependency4__.dasherize; + var classify = __dependency4__.classify; + var Namespace = __dependency5__["default"]; + var EmberObject = __dependency6__["default"]; + + /** + @module ember + @submodule ember-extension-support + */ + + /** + The `ContainerDebugAdapter` helps the container and resolver interface + with tools that debug Ember such as the + [Ember Extension](https://github.com/tildeio/ember-extension) + for Chrome and Firefox. + + This class can be extended by a custom resolver implementer + to override some of the methods with library-specific code. + + The methods likely to be overridden are: + + * `canCatalogEntriesByType` + * `catalogEntriesByType` + + The adapter will need to be registered + in the application's container as `container-debug-adapter:main` + + Example: + + ```javascript + Application.initializer({ + name: "containerDebugAdapter", + + initialize: function(container, application) { + application.register('container-debug-adapter:main', require('app/container-debug-adapter')); + } + }); + ``` + + @class ContainerDebugAdapter + @namespace Ember + @extends EmberObject + @since 1.5.0 + */ + __exports__["default"] = EmberObject.extend({ + /** + The container of the application being debugged. + This property will be injected + on creation. + + @property container + @default null + */ + container: null, + + /** + The resolver instance of the application + being debugged. This property will be injected + on creation. + + @property resolver + @default null + */ + resolver: null, + + /** + Returns true if it is possible to catalog a list of available + classes in the resolver for a given type. + + @method canCatalogEntriesByType + @param {String} type The type. e.g. "model", "controller", "route" + @return {boolean} whether a list is available for this type. + */ + canCatalogEntriesByType: function(type) { + if (type === 'model' || type === 'template') return false; + return true; + }, + + /** + Returns the available classes a given type. + + @method catalogEntriesByType + @param {String} type The type. e.g. "model", "controller", "route" + @return {Array} An array of strings. + */ + catalogEntriesByType: function(type) { + var namespaces = emberA(Namespace.NAMESPACES), types = emberA(), self = this; + var typeSuffixRegex = new RegExp(classify(type) + "$"); + + namespaces.forEach(function(namespace) { + if (namespace !== Ember) { + for (var key in namespace) { + if (!namespace.hasOwnProperty(key)) { continue; } + if (typeSuffixRegex.test(key)) { + var klass = namespace[key]; + if (typeOf(klass) === 'class') { + types.push(dasherize(key.replace(typeSuffixRegex, ''))); + } + } + } + } + }); + return types; + } + }); + }); +define("ember-extension-support/data_adapter", + ["ember-metal/core","ember-metal/property_get","ember-metal/run_loop","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/native_array","ember-application/system/application","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var run = __dependency3__["default"]; + var dasherize = __dependency4__.dasherize; + var Namespace = __dependency5__["default"]; + var EmberObject = __dependency6__["default"]; + var emberA = __dependency7__.A; + var Application = __dependency8__["default"]; + + /** + @module ember + @submodule ember-extension-support + */ + + /** + The `DataAdapter` helps a data persistence library + interface with tools that debug Ember such + as the [Ember Extension](https://github.com/tildeio/ember-extension) + for Chrome and Firefox. + + This class will be extended by a persistence library + which will override some of the methods with + library-specific code. + + The methods likely to be overridden are: + + * `getFilters` + * `detect` + * `columnsForType` + * `getRecords` + * `getRecordColumnValues` + * `getRecordKeywords` + * `getRecordFilterValues` + * `getRecordColor` + * `observeRecord` + + The adapter will need to be registered + in the application's container as `dataAdapter:main` + + Example: + + ```javascript + Application.initializer({ + name: "data-adapter", + + initialize: function(container, application) { + application.register('data-adapter:main', DS.DataAdapter); + } + }); + ``` + + @class DataAdapter + @namespace Ember + @extends EmberObject + */ + __exports__["default"] = EmberObject.extend({ + init: function() { + this._super(); + this.releaseMethods = emberA(); + }, + + /** + The container of the application being debugged. + This property will be injected + on creation. + + @property container + @default null + @since 1.3.0 + */ + container: null, + + + /** + The container-debug-adapter which is used + to list all models. + + @property containerDebugAdapter + @default undefined + @since 1.5.0 + **/ + containerDebugAdapter: undefined, + + /** + Number of attributes to send + as columns. (Enough to make the record + identifiable). + + @private + @property attributeLimit + @default 3 + @since 1.3.0 + */ + attributeLimit: 3, + + /** + Stores all methods that clear observers. + These methods will be called on destruction. + + @private + @property releaseMethods + @since 1.3.0 + */ + releaseMethods: emberA(), + + /** + Specifies how records can be filtered. + Records returned will need to have a `filterValues` + property with a key for every name in the returned array. + + @public + @method getFilters + @return {Array} List of objects defining filters. + The object should have a `name` and `desc` property. + */ + getFilters: function() { + return emberA(); + }, + + /** + Fetch the model types and observe them for changes. + + @public + @method watchModelTypes + + @param {Function} typesAdded Callback to call to add types. + Takes an array of objects containing wrapped types (returned from `wrapModelType`). + + @param {Function} typesUpdated Callback to call when a type has changed. + Takes an array of objects containing wrapped types. + + @return {Function} Method to call to remove all observers + */ + watchModelTypes: function(typesAdded, typesUpdated) { + var modelTypes = this.getModelTypes(); + var self = this; + var releaseMethods = emberA(); + var typesToSend; + + typesToSend = modelTypes.map(function(type) { + var klass = type.klass; + var wrapped = self.wrapModelType(klass, type.name); + releaseMethods.push(self.observeModelType(klass, typesUpdated)); + return wrapped; + }); + + typesAdded(typesToSend); + + var release = function() { + releaseMethods.forEach(function(fn) { fn(); }); + self.releaseMethods.removeObject(release); + }; + this.releaseMethods.pushObject(release); + return release; + }, + + _nameToClass: function(type) { + if (typeof type === 'string') { + type = this.container.lookupFactory('model:' + type); + } + return type; + }, + + /** + Fetch the records of a given type and observe them for changes. + + @public + @method watchRecords + + @param {Function} recordsAdded Callback to call to add records. + Takes an array of objects containing wrapped records. + The object should have the following properties: + columnValues: {Object} key and value of a table cell + object: {Object} the actual record object + + @param {Function} recordsUpdated Callback to call when a record has changed. + Takes an array of objects containing wrapped records. + + @param {Function} recordsRemoved Callback to call when a record has removed. + Takes the following parameters: + index: the array index where the records were removed + count: the number of records removed + + @return {Function} Method to call to remove all observers + */ + watchRecords: function(type, recordsAdded, recordsUpdated, recordsRemoved) { + var self = this, releaseMethods = emberA(), records = this.getRecords(type), release; + + var recordUpdated = function(updatedRecord) { + recordsUpdated([updatedRecord]); + }; + + var recordsToSend = records.map(function(record) { + releaseMethods.push(self.observeRecord(record, recordUpdated)); + return self.wrapRecord(record); + }); + + + var contentDidChange = function(array, idx, removedCount, addedCount) { + for (var i = idx; i < idx + addedCount; i++) { + var record = array.objectAt(i); + var wrapped = self.wrapRecord(record); + releaseMethods.push(self.observeRecord(record, recordUpdated)); + recordsAdded([wrapped]); + } + + if (removedCount) { + recordsRemoved(idx, removedCount); + } + }; + + var observer = { didChange: contentDidChange, willChange: Ember.K }; + records.addArrayObserver(self, observer); + + release = function() { + releaseMethods.forEach(function(fn) { fn(); }); + records.removeArrayObserver(self, observer); + self.releaseMethods.removeObject(release); + }; + + recordsAdded(recordsToSend); + + this.releaseMethods.pushObject(release); + return release; + }, + + /** + Clear all observers before destruction + @private + @method willDestroy + */ + willDestroy: function() { + this._super(); + this.releaseMethods.forEach(function(fn) { + fn(); + }); + }, + + /** + Detect whether a class is a model. + + Test that against the model class + of your persistence library + + @private + @method detect + @param {Class} klass The class to test + @return boolean Whether the class is a model class or not + */ + detect: function(klass) { + return false; + }, + + /** + Get the columns for a given model type. + + @private + @method columnsForType + @param {Class} type The model type + @return {Array} An array of columns of the following format: + name: {String} name of the column + desc: {String} Humanized description (what would show in a table column name) + */ + columnsForType: function(type) { + return emberA(); + }, + + /** + Adds observers to a model type class. + + @private + @method observeModelType + @param {Class} type The model type class + @param {Function} typesUpdated Called when a type is modified. + @return {Function} The function to call to remove observers + */ + + observeModelType: function(type, typesUpdated) { + var self = this; + var records = this.getRecords(type); + + var onChange = function() { + typesUpdated([self.wrapModelType(type)]); + }; + var observer = { + didChange: function() { + run.scheduleOnce('actions', this, onChange); + }, + willChange: Ember.K + }; + + records.addArrayObserver(this, observer); + + var release = function() { + records.removeArrayObserver(self, observer); + }; + + return release; + }, + + + /** + Wraps a given model type and observes changes to it. + + @private + @method wrapModelType + @param {Class} type A model class + @param {String} Optional name of the class + @return {Object} contains the wrapped type and the function to remove observers + Format: + type: {Object} the wrapped type + The wrapped type has the following format: + name: {String} name of the type + count: {Integer} number of records available + columns: {Columns} array of columns to describe the record + object: {Class} the actual Model type class + release: {Function} The function to remove observers + */ + wrapModelType: function(type, name) { + var records = this.getRecords(type); + var self = this; + var release, typeToSend; + + typeToSend = { + name: name || type.toString(), + count: get(records, 'length'), + columns: this.columnsForType(type), + object: type + }; + + + return typeToSend; + }, + + + /** + Fetches all models defined in the application. + + @private + @method getModelTypes + @return {Array} Array of model types + */ + getModelTypes: function() { + var self = this; + var containerDebugAdapter = this.get('containerDebugAdapter'); + var types; + + if (containerDebugAdapter.canCatalogEntriesByType('model')) { + types = containerDebugAdapter.catalogEntriesByType('model'); + } else { + types = this._getObjectsOnNamespaces(); + } + + // New adapters return strings instead of classes + types = emberA(types).map(function(name) { + return { + klass: self._nameToClass(name), + name: name + }; + }); + types = emberA(types).filter(function(type) { + return self.detect(type.klass); + }); + + return emberA(types); + }, + + /** + Loops over all namespaces and all objects + attached to them + + @private + @method _getObjectsOnNamespaces + @return {Array} Array of model type strings + */ + _getObjectsOnNamespaces: function() { + var namespaces = emberA(Namespace.NAMESPACES); + var types = emberA(); + var self = this; + + namespaces.forEach(function(namespace) { + for (var key in namespace) { + if (!namespace.hasOwnProperty(key)) { continue; } + // Even though we will filter again in `getModelTypes`, + // we should not call `lookupContainer` on non-models + // (especially when `Ember.MODEL_FACTORY_INJECTIONS` is `true`) + if (!self.detect(namespace[key])) { continue; } + var name = dasherize(key); + if (!(namespace instanceof Application) && namespace.toString()) { + name = namespace + '/' + name; + } + types.push(name); + } + }); + return types; + }, + + /** + Fetches all loaded records for a given type. + + @private + @method getRecords + @return {Array} An array of records. + This array will be observed for changes, + so it should update when new records are added/removed. + */ + getRecords: function(type) { + return emberA(); + }, + + /** + Wraps a record and observers changes to it. + + @private + @method wrapRecord + @param {Object} record The record instance. + @return {Object} The wrapped record. Format: + columnValues: {Array} + searchKeywords: {Array} + */ + wrapRecord: function(record) { + var recordToSend = { object: record }; + var columnValues = {}; + var self = this; + + recordToSend.columnValues = this.getRecordColumnValues(record); + recordToSend.searchKeywords = this.getRecordKeywords(record); + recordToSend.filterValues = this.getRecordFilterValues(record); + recordToSend.color = this.getRecordColor(record); + + return recordToSend; + }, + + /** + Gets the values for each column. + + @private + @method getRecordColumnValues + @return {Object} Keys should match column names defined + by the model type. + */ + getRecordColumnValues: function(record) { + return {}; + }, + + /** + Returns keywords to match when searching records. + + @private + @method getRecordKeywords + @return {Array} Relevant keywords for search. + */ + getRecordKeywords: function(record) { + return emberA(); + }, + + /** + Returns the values of filters defined by `getFilters`. + + @private + @method getRecordFilterValues + @param {Object} record The record instance + @return {Object} The filter values + */ + getRecordFilterValues: function(record) { + return {}; + }, + + /** + Each record can have a color that represents its state. + + @private + @method getRecordColor + @param {Object} record The record instance + @return {String} The record's color + Possible options: black, red, blue, green + */ + getRecordColor: function(record) { + return null; + }, + + /** + Observes all relevant properties and re-sends the wrapped record + when a change occurs. + + @private + @method observerRecord + @param {Object} record The record instance + @param {Function} recordUpdated The callback to call when a record is updated. + @return {Function} The function to call to remove all observers. + */ + observeRecord: function(record, recordUpdated) { + return function(){}; + } + }); + }); +define("ember-extension-support/initializers", + [], + function() { + "use strict"; + + }); +define("ember-handlebars-compiler", + ["ember-metal/core","exports"], + function(__dependency1__, __exports__) { + "use strict"; + /* global Handlebars:true */ + + /** + @module ember + @submodule ember-handlebars-compiler + */ + + var Ember = __dependency1__["default"]; + + // ES6Todo: you'll need to import debugger once debugger is es6'd. + if (typeof Ember.assert === 'undefined') { Ember.assert = function(){}; } + if (typeof Ember.FEATURES === 'undefined') { Ember.FEATURES = { isEnabled: function(){} }; } + + var objectCreate = Object.create || function(parent) { + function F() {} + F.prototype = parent; + return new F(); + }; + + // set up for circular references later + var View, Component; + + // ES6Todo: when ember-debug is es6'ed import this. + // var emberAssert = Ember.assert; + var Handlebars = (Ember.imports && Ember.imports.Handlebars) || (this && this.Handlebars); + if (!Handlebars && typeof require === 'function') { + Handlebars = require('handlebars'); + } + + + + /** + Prepares the Handlebars templating library for use inside Ember's view + system. + + The `Ember.Handlebars` object is the standard Handlebars library, extended to + use Ember's `get()` method instead of direct property access, which allows + computed properties to be used inside templates. + + To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`. + This will return a function that can be used by `Ember.View` for rendering. + + @class Handlebars + @namespace Ember + */ + var EmberHandlebars = Ember.Handlebars = objectCreate(Handlebars); + + /** + Register a bound helper or custom view helper. + + ## Simple bound helper example + + ```javascript + Ember.Handlebars.helper('capitalize', function(value) { + return value.toUpperCase(); + }); + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{capitalize name}} + ``` + + In this case, when the `name` property of the template's context changes, + the rendered value of the helper will update to reflect this change. + + For more examples of bound helpers, see documentation for + `Ember.Handlebars.registerBoundHelper`. + + ## Custom view helper example + + Assuming a view subclass named `App.CalendarView` were defined, a helper + for rendering instances of this view could be registered as follows: + + ```javascript + Ember.Handlebars.helper('calendar', App.CalendarView): + ``` + + The above bound helper can be used inside of templates as follows: + + ```handlebars + {{calendar}} + ``` + + Which is functionally equivalent to: + + ```handlebars + {{view 'calendar'}} + ``` + + Options in the helper will be passed to the view in exactly the same + manner as with the `view` helper. + + @method helper + @for Ember.Handlebars + @param {String} name + @param {Function|Ember.View} function or view class constructor + @param {String} dependentKeys* + */ + EmberHandlebars.helper = function(name, value) { + if (!View) { View = requireModule('ember-views/views/view')['default']; } // ES6TODO: stupid circular dep + if (!Component) { Component = requireModule('ember-views/views/component')['default']; } // ES6TODO: stupid circular dep + + + if (View.detect(value)) { + EmberHandlebars.registerHelper(name, EmberHandlebars.makeViewHelper(value)); + } else { + EmberHandlebars.registerBoundHelper.apply(null, arguments); + } + }; + + /** + Returns a helper function that renders the provided ViewClass. + + Used internally by Ember.Handlebars.helper and other methods + involving helper/component registration. + + @private + @method makeViewHelper + @for Ember.Handlebars + @param {Function} ViewClass view class constructor + @since 1.2.0 + */ + EmberHandlebars.makeViewHelper = function(ViewClass) { + return function(options) { + return EmberHandlebars.helpers.view.call(this, ViewClass, options); + }; + }; + + /** + @class helpers + @namespace Ember.Handlebars + */ + EmberHandlebars.helpers = objectCreate(Handlebars.helpers); + + /** + Override the the opcode compiler and JavaScript compiler for Handlebars. + + @class Compiler + @namespace Ember.Handlebars + @private + @constructor + */ + EmberHandlebars.Compiler = function() {}; + + // Handlebars.Compiler doesn't exist in runtime-only + if (Handlebars.Compiler) { + EmberHandlebars.Compiler.prototype = objectCreate(Handlebars.Compiler.prototype); + } + + EmberHandlebars.Compiler.prototype.compiler = EmberHandlebars.Compiler; + + /** + @class JavaScriptCompiler + @namespace Ember.Handlebars + @private + @constructor + */ + EmberHandlebars.JavaScriptCompiler = function() {}; + + // Handlebars.JavaScriptCompiler doesn't exist in runtime-only + if (Handlebars.JavaScriptCompiler) { + EmberHandlebars.JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype); + EmberHandlebars.JavaScriptCompiler.prototype.compiler = EmberHandlebars.JavaScriptCompiler; + } + + + EmberHandlebars.JavaScriptCompiler.prototype.namespace = "Ember.Handlebars"; + + EmberHandlebars.JavaScriptCompiler.prototype.initializeBuffer = function() { + return "''"; + }; + + /** + Override the default buffer for Ember Handlebars. By default, Handlebars + creates an empty String at the beginning of each invocation and appends to + it. Ember's Handlebars overrides this to append to a single shared buffer. + + @private + @method appendToBuffer + @param string {String} + */ + EmberHandlebars.JavaScriptCompiler.prototype.appendToBuffer = function(string) { + return "data.buffer.push("+string+");"; + }; + + // Hacks ahead: + // Handlebars presently has a bug where the `blockHelperMissing` hook + // doesn't get passed the name of the missing helper name, but rather + // gets passed the value of that missing helper evaluated on the current + // context, which is most likely `undefined` and totally useless. + // + // So we alter the compiled template function to pass the name of the helper + // instead, as expected. + // + // This can go away once the following is closed: + // https://github.com/wycats/handlebars.js/issues/634 + + var DOT_LOOKUP_REGEX = /helpers\.(.*?)\)/; + var BRACKET_STRING_LOOKUP_REGEX = /helpers\['(.*?)'/; + var INVOCATION_SPLITTING_REGEX = /(.*blockHelperMissing\.call\(.*)(stack[0-9]+)(,.*)/; + + EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation = function(source) { + var helperInvocation = source[source.length - 1]; + var helperName = (DOT_LOOKUP_REGEX.exec(helperInvocation) || BRACKET_STRING_LOOKUP_REGEX.exec(helperInvocation))[1]; + var matches = INVOCATION_SPLITTING_REGEX.exec(helperInvocation); + + source[source.length - 1] = matches[1] + "'" + helperName + "'" + matches[3]; + }; + + var stringifyBlockHelperMissing = EmberHandlebars.JavaScriptCompiler.stringifyLastBlockHelperMissingInvocation; + + var originalBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.blockValue; + EmberHandlebars.JavaScriptCompiler.prototype.blockValue = function() { + originalBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); + }; + + var originalAmbiguousBlockValue = EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue; + EmberHandlebars.JavaScriptCompiler.prototype.ambiguousBlockValue = function() { + originalAmbiguousBlockValue.apply(this, arguments); + stringifyBlockHelperMissing(this.source); + }; + + /** + Rewrite simple mustaches from `{{foo}}` to `{{bind "foo"}}`. This means that + all simple mustaches in Ember's Handlebars will also set up an observer to + keep the DOM up to date when the underlying property changes. + + @private + @method mustache + @for Ember.Handlebars.Compiler + @param mustache + */ + EmberHandlebars.Compiler.prototype.mustache = function(mustache) { + if (!(mustache.params.length || mustache.hash)) { + var id = new Handlebars.AST.IdNode([{ part: '_triageMustache' }]); + + // Update the mustache node to include a hash value indicating whether the original node + // was escaped. This will allow us to properly escape values when the underlying value + // changes and we need to re-render the value. + if (!mustache.escaped) { + mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]); + mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]); + } + mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped); + } + + return Handlebars.Compiler.prototype.mustache.call(this, mustache); + }; + + /** + Used for precompilation of Ember Handlebars templates. This will not be used + during normal app execution. + + @method precompile + @for Ember.Handlebars + @static + @param {String|Object} value The template to precompile or an Handlebars AST + @param {Boolean} asObject optional parameter, defaulting to true, of whether or not the + compiled template should be returned as an Object or a String + */ + EmberHandlebars.precompile = function(value, asObject) { + var ast = Handlebars.parse(value); + + var options = { + knownHelpers: { + action: true, + unbound: true, + 'bind-attr': true, + template: true, + view: true, + _triageMustache: true + }, + data: true, + stringParams: true + }; + + asObject = asObject === undefined ? true : asObject; + + var environment = new EmberHandlebars.Compiler().compile(ast, options); + return new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, asObject); + }; + + // We don't support this for Handlebars runtime-only + if (Handlebars.compile) { + /** + The entry point for Ember Handlebars. This replaces the default + `Handlebars.compile` and turns on template-local data and String + parameters. + + @method compile + @for Ember.Handlebars + @static + @param {String} string The template to compile + @return {Function} + */ + EmberHandlebars.compile = function(string) { + var ast = Handlebars.parse(string); + var options = { data: true, stringParams: true }; + var environment = new EmberHandlebars.Compiler().compile(ast, options); + var templateSpec = new EmberHandlebars.JavaScriptCompiler().compile(environment, options, undefined, true); + + var template = EmberHandlebars.template(templateSpec); + template.isMethod = false; //Make sure we don't wrap templates with ._super + + return template; + }; + } + + __exports__["default"] = EmberHandlebars; + }); +define("ember-handlebars", + ["ember-handlebars-compiler","ember-metal/core","ember-runtime/system/lazy_load","ember-handlebars/loader","ember-handlebars/ext","ember-handlebars/string","ember-handlebars/helpers/shared","ember-handlebars/helpers/binding","ember-handlebars/helpers/collection","ember-handlebars/helpers/view","ember-handlebars/helpers/unbound","ember-handlebars/helpers/debug","ember-handlebars/helpers/each","ember-handlebars/helpers/template","ember-handlebars/helpers/partial","ember-handlebars/helpers/yield","ember-handlebars/helpers/loc","ember-handlebars/controls/checkbox","ember-handlebars/controls/select","ember-handlebars/controls/text_area","ember-handlebars/controls/text_field","ember-handlebars/controls/text_support","ember-handlebars/controls","ember-handlebars/component_lookup","ember-handlebars/views/handlebars_bound_view","ember-handlebars/views/metamorph_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __dependency22__, __dependency23__, __dependency24__, __dependency25__, __dependency26__, __exports__) { + "use strict"; + var EmberHandlebars = __dependency1__["default"]; + var Ember = __dependency2__["default"]; + // to add to globals + + var runLoadHooks = __dependency3__.runLoadHooks; + var bootstrap = __dependency4__["default"]; + + var normalizePath = __dependency5__.normalizePath; + var template = __dependency5__.template; + var makeBoundHelper = __dependency5__.makeBoundHelper; + var registerBoundHelper = __dependency5__.registerBoundHelper; + var resolveHash = __dependency5__.resolveHash; + var resolveParams = __dependency5__.resolveParams; + var getEscaped = __dependency5__.getEscaped; + var handlebarsGet = __dependency5__.handlebarsGet; + var evaluateUnboundHelper = __dependency5__.evaluateUnboundHelper; + var helperMissingHelper = __dependency5__.helperMissingHelper; + var blockHelperMissingHelper = __dependency5__.blockHelperMissingHelper; + + + // side effect of extending StringUtils of htmlSafe + + var resolvePaths = __dependency7__["default"]; + var bind = __dependency8__.bind; + var _triageMustacheHelper = __dependency8__._triageMustacheHelper; + var resolveHelper = __dependency8__.resolveHelper; + var bindHelper = __dependency8__.bindHelper; + var boundIfHelper = __dependency8__.boundIfHelper; + var unboundIfHelper = __dependency8__.unboundIfHelper; + var withHelper = __dependency8__.withHelper; + var ifHelper = __dependency8__.ifHelper; + var unlessHelper = __dependency8__.unlessHelper; + var bindAttrHelper = __dependency8__.bindAttrHelper; + var bindAttrHelperDeprecated = __dependency8__.bindAttrHelperDeprecated; + var bindClasses = __dependency8__.bindClasses; + + var collectionHelper = __dependency9__["default"]; + var ViewHelper = __dependency10__.ViewHelper; + var viewHelper = __dependency10__.viewHelper; + var unboundHelper = __dependency11__["default"]; + var logHelper = __dependency12__.logHelper; + var debuggerHelper = __dependency12__.debuggerHelper; + var EachView = __dependency13__.EachView; + var GroupedEach = __dependency13__.GroupedEach; + var eachHelper = __dependency13__.eachHelper; + var templateHelper = __dependency14__["default"]; + var partialHelper = __dependency15__["default"]; + var yieldHelper = __dependency16__["default"]; + var locHelper = __dependency17__["default"]; + + + var Checkbox = __dependency18__["default"]; + var Select = __dependency19__.Select; + var SelectOption = __dependency19__.SelectOption; + var SelectOptgroup = __dependency19__.SelectOptgroup; + var TextArea = __dependency20__["default"]; + var TextField = __dependency21__["default"]; + var TextSupport = __dependency22__["default"]; + var inputHelper = __dependency23__.inputHelper; + var textareaHelper = __dependency23__.textareaHelper; + + + var ComponentLookup = __dependency24__["default"]; + var _HandlebarsBoundView = __dependency25__._HandlebarsBoundView; + var SimpleHandlebarsView = __dependency25__.SimpleHandlebarsView; + var _wrapMap = __dependency26__._wrapMap; + var _SimpleMetamorphView = __dependency26__._SimpleMetamorphView; + var _MetamorphView = __dependency26__._MetamorphView; + var _Metamorph = __dependency26__._Metamorph; + + + /** + Ember Handlebars + + @module ember + @submodule ember-handlebars + @requires ember-views + */ + + // Ember.Handlebars.Globals + EmberHandlebars.bootstrap = bootstrap; + EmberHandlebars.template = template; + EmberHandlebars.makeBoundHelper = makeBoundHelper; + EmberHandlebars.registerBoundHelper = registerBoundHelper; + EmberHandlebars.resolveHash = resolveHash; + EmberHandlebars.resolveParams = resolveParams; + EmberHandlebars.resolveHelper = resolveHelper; + EmberHandlebars.get = handlebarsGet; + EmberHandlebars.getEscaped = getEscaped; + EmberHandlebars.evaluateUnboundHelper = evaluateUnboundHelper; + EmberHandlebars.bind = bind; + EmberHandlebars.bindClasses = bindClasses; + EmberHandlebars.EachView = EachView; + EmberHandlebars.GroupedEach = GroupedEach; + EmberHandlebars.resolvePaths = resolvePaths; + EmberHandlebars.ViewHelper = ViewHelper; + EmberHandlebars.normalizePath = normalizePath; + + + // Ember Globals + Ember.Handlebars = EmberHandlebars; + Ember.ComponentLookup = ComponentLookup; + Ember._SimpleHandlebarsView = SimpleHandlebarsView; + Ember._HandlebarsBoundView = _HandlebarsBoundView; + Ember._SimpleMetamorphView = _SimpleMetamorphView; + Ember._MetamorphView = _MetamorphView; + Ember._Metamorph = _Metamorph; + Ember._metamorphWrapMap = _wrapMap; + Ember.TextSupport = TextSupport; + Ember.Checkbox = Checkbox; + Ember.Select = Select; + Ember.SelectOption = SelectOption; + Ember.SelectOptgroup = SelectOptgroup; + Ember.TextArea = TextArea; + Ember.TextField = TextField; + Ember.TextSupport = TextSupport; + + // register helpers + EmberHandlebars.registerHelper('helperMissing', helperMissingHelper); + EmberHandlebars.registerHelper('blockHelperMissing', blockHelperMissingHelper); + EmberHandlebars.registerHelper('bind', bindHelper); + EmberHandlebars.registerHelper('boundIf', boundIfHelper); + EmberHandlebars.registerHelper('_triageMustache', _triageMustacheHelper); + EmberHandlebars.registerHelper('unboundIf', unboundIfHelper); + EmberHandlebars.registerHelper('with', withHelper); + EmberHandlebars.registerHelper('if', ifHelper); + EmberHandlebars.registerHelper('unless', unlessHelper); + EmberHandlebars.registerHelper('bind-attr', bindAttrHelper); + EmberHandlebars.registerHelper('bindAttr', bindAttrHelperDeprecated); + EmberHandlebars.registerHelper('collection', collectionHelper); + EmberHandlebars.registerHelper("log", logHelper); + EmberHandlebars.registerHelper("debugger", debuggerHelper); + EmberHandlebars.registerHelper("each", eachHelper); + EmberHandlebars.registerHelper("loc", locHelper); + EmberHandlebars.registerHelper("partial", partialHelper); + EmberHandlebars.registerHelper("template", templateHelper); + EmberHandlebars.registerHelper("yield", yieldHelper); + EmberHandlebars.registerHelper("view", viewHelper); + EmberHandlebars.registerHelper("unbound", unboundHelper); + EmberHandlebars.registerHelper("input", inputHelper); + EmberHandlebars.registerHelper("textarea", textareaHelper); + + // run load hooks + runLoadHooks('Ember.Handlebars', EmberHandlebars); + + __exports__["default"] = EmberHandlebars; + }); +define("ember-handlebars/component_lookup", + ["ember-runtime/system/object","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + + var ComponentLookup = EmberObject.extend({ + lookupFactory: function(name, container) { + + container = container || this.container; + + var fullName = 'component:' + name; + var templateFullName = 'template:components/' + name; + var templateRegistered = container && container.has(templateFullName); + + if (templateRegistered) { + container.injection(fullName, 'layout', templateFullName); + } + + var Component = container.lookupFactory(fullName); + + // Only treat as a component if either the component + // or a template has been registered. + if (templateRegistered || Component) { + if (!Component) { + container.register(fullName, Ember.Component); + Component = container.lookupFactory(fullName); + } + return Component; + } + } + }); + + __exports__["default"] = ComponentLookup; + }); +define("ember-handlebars/controls", + ["ember-handlebars/controls/checkbox","ember-handlebars/controls/text_field","ember-handlebars/controls/text_area","ember-metal/core","ember-handlebars-compiler","ember-handlebars/ext","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Checkbox = __dependency1__["default"]; + var TextField = __dependency2__["default"]; + var TextArea = __dependency3__["default"]; + + var Ember = __dependency4__["default"]; + // Ember.assert + // var emberAssert = Ember.assert; + + var EmberHandlebars = __dependency5__["default"]; + var handlebarsGet = __dependency6__.handlebarsGet; + var helpers = EmberHandlebars.helpers; + /** + @module ember + @submodule ember-handlebars-compiler + */ + + function _resolveOption(context, options, key) { + if (options.hashTypes[key] === "ID") { + return handlebarsGet(context, options.hash[key], options); + } else { + return options.hash[key]; + } + } + + /** + + The `{{input}}` helper inserts an HTML `` tag into the template, + with a `type` value of either `text` or `checkbox`. If no `type` is provided, + `text` will be the default value applied. The attributes of `{{input}}` + match those of the native HTML tag as closely as possible for these two types. + + ## Use as text field + An `{{input}}` with no `type` or a `type` of `text` will render an HTML text input. + The following HTML attributes can be set via the helper: + +
    + + + + + + + + + + +
    `readonly``required``autofocus`
    `value``placeholder``disabled`
    `size``tabindex``maxlength`
    `name``min``max`
    `pattern``accept``autocomplete`
    `autosave``formaction``formenctype`
    `formmethod``formnovalidate``formtarget`
    `height``inputmode``multiple`
    `step``width``form`
    `selectionDirection``spellcheck` 
    + + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input value="http://www.facebook.com"}} + ``` + + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + firstName: "Stanley", + entryNotAllowed: true + }); + ``` + + + ```handlebars + {{input type="text" value=firstName disabled=entryNotAllowed size="50"}} + ``` + + + ```html + + ``` + + ## Actions + + The helper can send multiple actions based on user events. + + The action property defines the action which is send when + the user presses the return key. + + ```handlebars + {{input action="submit"}} + ``` + + The helper allows some user events to send actions. + + * `enter` + * `insert-newline` + * `escape-press` + * `focus-in` + * `focus-out` + * `key-press` + + For example, if you desire an action to be sent when the input is blurred, + you only need to setup the action name to the event name property. + + ```handlebars + {{input focus-in="alertMessage"}} + ``` + + See more about [Text Support Actions](/api/classes/Ember.TextField.html) + + ## Extension + + Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing + arguments from the helper to `Ember.TextField`'s `create` method. You can extend the + capabilities of text inputs in your applications by reopening this class. For example, + if you are building a Bootstrap project where `data-*` attributes are used, you + can add one to the `TextField`'s `attributeBindings` property: + + + ```javascript + Ember.TextField.reopen({ + attributeBindings: ['data-error'] + }); + ``` + + Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](/api/classes/Ember.Component.html) + + + ## Use as checkbox + + An `{{input}}` with a `type` of `checkbox` will render an HTML checkbox input. + The following HTML attributes can be set via the helper: + + * `checked` + * `disabled` + * `tabindex` + * `indeterminate` + * `name` + * `autofocus` + * `form` + + + When set to a quoted string, these values will be directly applied to the HTML + element. When left unquoted, these values will be bound to a property on the + template's current rendering context (most typically a controller instance). + + ## Unbound: + + ```handlebars + {{input type="checkbox" name="isAdmin"}} + ``` + + ```html + + ``` + + ## Bound: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + isAdmin: true + }); + ``` + + + ```handlebars + {{input type="checkbox" checked=isAdmin }} + ``` + + + ```html + + ``` + + ## Extension + + Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing + arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the + capablilties of checkbox inputs in your applications by reopening this class. For example, + if you wanted to add a css class to all checkboxes in your application: + + + ```javascript + Ember.Checkbox.reopen({ + classNames: ['my-app-checkbox'] + }); + ``` + + + @method input + @for Ember.Handlebars.helpers + @param {Hash} options + */ + function inputHelper(options) { + + var hash = options.hash; + var types = options.hashTypes; + var inputType = _resolveOption(this, options, 'type'); + var onEvent = hash.on; + + if (inputType === 'checkbox') { + delete hash.type; + delete types.type; + + + return helpers.view.call(this, Checkbox, options); + } else { + delete hash.on; + + hash.onEvent = onEvent || 'enter'; + return helpers.view.call(this, TextField, options); + } + } + + __exports__.inputHelper = inputHelper;/** + `{{textarea}}` inserts a new instance of ` + ``` + + Bound: + + In the following example, the `writtenWords` property on `App.ApplicationController` + will be updated live as the user types 'Lots of text that IS bound' into + the text area of their browser's window. + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound" + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + ``` + + Would result in the following HTML: + + ```html + + ``` + + If you wanted a one way binding between the text area and a div tag + somewhere else on your screen, you could use `Ember.computed.oneWay`: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + outputWrittenWords: Ember.computed.oneWay("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + +
    + {{outputWrittenWords}} +
    + ``` + + Would result in the following HTML: + + ```html + + + <-- the following div will be updated in real time as you type --> + +
    + Lots of text that IS bound +
    + ``` + + Finally, this example really shows the power and ease of Ember when two + properties are bound to eachother via `Ember.computed.alias`. Type into + either text area box and they'll both stay in sync. Note that + `Ember.computed.alias` costs more in terms of performance, so only use it when + your really binding in both directions: + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + writtenWords: "Lots of text that IS bound", + twoWayWrittenWords: Ember.computed.alias("writtenWords") + }); + ``` + + ```handlebars + {{textarea value=writtenWords}} + {{textarea value=twoWayWrittenWords}} + ``` + + ```html + + + <-- both updated in real time --> + + + ``` + + ## Actions + + The helper can send multiple actions based on user events. + + The action property defines the action which is send when + the user presses the return key. + + ```handlebars + {{input action="submit"}} + ``` + + The helper allows some user events to send actions. + + * `enter` + * `insert-newline` + * `escape-press` + * `focus-in` + * `focus-out` + * `key-press` + + For example, if you desire an action to be sent when the input is blurred, + you only need to setup the action name to the event name property. + + ```handlebars + {{textarea focus-in="alertMessage"}} + ``` + + See more about [Text Support Actions](/api/classes/Ember.TextArea.html) + + ## Extension + + Internally, `{{textarea}}` creates an instance of `Ember.TextArea`, passing + arguments from the helper to `Ember.TextArea`'s `create` method. You can + extend the capabilities of text areas in your application by reopening this + class. For example, if you are building a Bootstrap project where `data-*` + attributes are used, you can globally add support for a `data-*` attribute + on all `{{textarea}}`s' in your app by reopening `Ember.TextArea` or + `Ember.TextSupport` and adding it to the `attributeBindings` concatenated + property: + + ```javascript + Ember.TextArea.reopen({ + attributeBindings: ['data-error'] + }); + ``` + + Keep in mind when writing `Ember.TextArea` subclasses that `Ember.TextArea` + itself extends `Ember.Component`, meaning that it does NOT inherit + the `controller` of the parent view. + + See more about [Ember components](/api/classes/Ember.Component.html) + + @method textarea + @for Ember.Handlebars.helpers + @param {Hash} options + */ + function textareaHelper(options) { + + var hash = options.hash; + var types = options.hashTypes; + + return helpers.view.call(this, TextArea, options); + } + + __exports__.textareaHelper = textareaHelper; + }); +define("ember-handlebars/controls/checkbox", + ["ember-metal/property_get","ember-metal/property_set","ember-views/views/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var View = __dependency3__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `checkbox`. + + See [handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. + + ## Direct manipulation of `checked` + + The `checked` attribute of an `Ember.Checkbox` object should always be set + through the Ember object or by interacting with its rendered element + representation via the mouse, keyboard, or touch. Updating the value of the + checkbox via jQuery will result in the checked value of the object and its + element losing synchronization. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class Checkbox + @namespace Ember + @extends Ember.View + */ + __exports__["default"] = View.extend({ + instrumentDisplay: '{{input type="checkbox"}}', + + classNames: ['ember-checkbox'], + + tagName: 'input', + + attributeBindings: [ + 'type', + 'checked', + 'indeterminate', + 'disabled', + 'tabindex', + 'name', + 'autofocus', + 'required', + 'form' + ], + + type: 'checkbox', + checked: false, + disabled: false, + indeterminate: false, + + init: function() { + this._super(); + this.on('change', this, this._updateElementValue); + }, + + didInsertElement: function() { + this._super(); + get(this, 'element').indeterminate = !!get(this, 'indeterminate'); + }, + + _updateElementValue: function() { + set(this, 'checked', this.$().prop('checked')); + } + }); + }); +define("ember-handlebars/controls/select", + ["ember-handlebars-compiler","ember-metal/enumerable_utils","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/collection_view","ember-metal/utils","ember-metal/is_none","ember-metal/computed","ember-runtime/system/native_array","ember-metal/mixin","ember-metal/properties","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var EmberHandlebars = __dependency1__["default"]; + + var forEach = __dependency2__.forEach; + var indexOf = __dependency2__.indexOf; + var indexesOf = __dependency2__.indexesOf; + var replace = __dependency2__.replace; + + var get = __dependency3__.get; + var set = __dependency4__.set; + var View = __dependency5__["default"]; + var CollectionView = __dependency6__["default"]; + var isArray = __dependency7__.isArray; + var isNone = __dependency8__["default"]; + var computed = __dependency9__.computed; + var emberA = __dependency10__.A; + var observer = __dependency11__.observer; + var defineProperty = __dependency12__.defineProperty; + + var precompileTemplate = EmberHandlebars.compile; + + var SelectOption = View.extend({ + instrumentDisplay: 'Ember.SelectOption', + + tagName: 'option', + attributeBindings: ['value', 'selected'], + + defaultTemplate: function(context, options) { + options = { data: options.data, hash: {} }; + EmberHandlebars.helpers.bind.call(context, "view.label", options); + }, + + init: function() { + this.labelPathDidChange(); + this.valuePathDidChange(); + + this._super(); + }, + + selected: computed(function() { + var content = get(this, 'content'); + var selection = get(this, 'parentView.selection'); + if (get(this, 'parentView.multiple')) { + return selection && indexOf(selection, content.valueOf()) > -1; + } else { + // Primitives get passed through bindings as objects... since + // `new Number(4) !== 4`, we use `==` below + return content == selection; // jshint ignore:line + } + }).property('content', 'parentView.selection'), + + labelPathDidChange: observer('parentView.optionLabelPath', function() { + var labelPath = get(this, 'parentView.optionLabelPath'); + + if (!labelPath) { return; } + + defineProperty(this, 'label', computed(function() { + return get(this, labelPath); + }).property(labelPath)); + }), + + valuePathDidChange: observer('parentView.optionValuePath', function() { + var valuePath = get(this, 'parentView.optionValuePath'); + + if (!valuePath) { return; } + + defineProperty(this, 'value', computed(function() { + return get(this, valuePath); + }).property(valuePath)); + }) + }); + + var SelectOptgroup = CollectionView.extend({ + instrumentDisplay: 'Ember.SelectOptgroup', + + tagName: 'optgroup', + attributeBindings: ['label'], + + selectionBinding: 'parentView.selection', + multipleBinding: 'parentView.multiple', + optionLabelPathBinding: 'parentView.optionLabelPath', + optionValuePathBinding: 'parentView.optionValuePath', + + itemViewClassBinding: 'parentView.optionView' + }); + + /** + The `Ember.Select` view class renders a + [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element, + allowing the user to choose from a list of options. + + The text and `value` property of each ` + + + ``` + + The `value` attribute of the selected `"); + return buffer; + } + + function program3(depth0,data) { + + var stack1; + stack1 = helpers.each.call(depth0, "view.groupedContent", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(4, program4, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } + function program4(depth0,data) { + + + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {hash:{ + 'content': ("content"), + 'label': ("label") + },hashTypes:{'content': "ID",'label': "ID"},hashContexts:{'content': depth0,'label': depth0},contexts:[depth0],types:["ID"],data:data}))); + } + + function program6(depth0,data) { + + var stack1; + stack1 = helpers.each.call(depth0, "view.content", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(7, program7, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + else { data.buffer.push(''); } + } + function program7(depth0,data) { + + + data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {hash:{ + 'content': ("") + },hashTypes:{'content': "ID"},hashContexts:{'content': depth0},contexts:[depth0],types:["ID"],data:data}))); + } + + stack1 = helpers['if'].call(depth0, "view.prompt", {hash:{},hashTypes:{},hashContexts:{},inverse:self.noop,fn:self.program(1, program1, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + stack1 = helpers['if'].call(depth0, "view.optionGroupPath", {hash:{},hashTypes:{},hashContexts:{},inverse:self.program(6, program6, data),fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],data:data}); + if(stack1 || stack1 === 0) { data.buffer.push(stack1); } + return buffer; + + }), + attributeBindings: ['multiple', 'disabled', 'tabindex', 'name', 'required', 'autofocus', + 'form', 'size'], + + /** + The `multiple` attribute of the select element. Indicates whether multiple + options can be selected. + + @property multiple + @type Boolean + @default false + */ + multiple: false, + + /** + The `disabled` attribute of the select element. Indicates whether + the element is disabled from interactions. + + @property disabled + @type Boolean + @default false + */ + disabled: false, + + /** + The `required` attribute of the select element. Indicates whether + a selected option is required for form validation. + + @property required + @type Boolean + @default false + @since 1.5.0 + */ + required: false, + + /** + The list of options. + + If `optionLabelPath` and `optionValuePath` are not overridden, this should + be a list of strings, which will serve simultaneously as labels and values. + + Otherwise, this should be a list of objects. For instance: + + ```javascript + var App = Ember.Application.create(); + var App.MySelect = Ember.Select.extend({ + content: Ember.A([ + { id: 1, firstName: 'Yehuda' }, + { id: 2, firstName: 'Tom' } + ]), + optionLabelPath: 'content.firstName', + optionValuePath: 'content.id' + }); + ``` + + @property content + @type Array + @default null + */ + content: null, + + /** + When `multiple` is `false`, the element of `content` that is currently + selected, if any. + + When `multiple` is `true`, an array of such elements. + + @property selection + @type Object or Array + @default null + */ + selection: null, + + /** + In single selection mode (when `multiple` is `false`), value can be used to + get the current selection's value or set the selection by it's value. + + It is not currently supported in multiple selection mode. + + @property value + @type String + @default null + */ + value: computed(function(key, value) { + if (arguments.length === 2) { return value; } + var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); + return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection'); + }).property('selection'), + + /** + If given, a top-most dummy option will be rendered to serve as a user + prompt. + + @property prompt + @type String + @default null + */ + prompt: null, + + /** + The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionLabelPath + @type String + @default 'content' + */ + optionLabelPath: 'content', + + /** + The path of the option values. See [content](/api/classes/Ember.Select.html#property_content). + + @property optionValuePath + @type String + @default 'content' + */ + optionValuePath: 'content', + + /** + The path of the option group. + When this property is used, `content` should be sorted by `optionGroupPath`. + + @property optionGroupPath + @type String + @default null + */ + optionGroupPath: null, + + /** + The view class for optgroup. + + @property groupView + @type Ember.View + @default Ember.SelectOptgroup + */ + groupView: SelectOptgroup, + + groupedContent: computed(function() { + var groupPath = get(this, 'optionGroupPath'); + var groupedContent = emberA(); + var content = get(this, 'content') || []; + + forEach(content, function(item) { + var label = get(item, groupPath); + + if (get(groupedContent, 'lastObject.label') !== label) { + groupedContent.pushObject({ + label: label, + content: emberA() + }); + } + + get(groupedContent, 'lastObject.content').push(item); + }); + + return groupedContent; + }).property('optionGroupPath', 'content.@each'), + + /** + The view class for option. + + @property optionView + @type Ember.View + @default Ember.SelectOption + */ + optionView: SelectOption, + + _change: function() { + if (get(this, 'multiple')) { + this._changeMultiple(); + } else { + this._changeSingle(); + } + }, + + selectionDidChange: observer('selection.@each', function() { + var selection = get(this, 'selection'); + if (get(this, 'multiple')) { + if (!isArray(selection)) { + set(this, 'selection', emberA([selection])); + return; + } + this._selectionDidChangeMultiple(); + } else { + this._selectionDidChangeSingle(); + } + }), + + valueDidChange: observer('value', function() { + var content = get(this, 'content'); + var value = get(this, 'value'); + var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); + var selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')); + var selection; + + if (value !== selectedValue) { + selection = content ? content.find(function(obj) { + return value === (valuePath ? get(obj, valuePath) : obj); + }) : null; + + this.set('selection', selection); + } + }), + + + _triggerChange: function() { + var selection = get(this, 'selection'); + var value = get(this, 'value'); + + if (!isNone(selection)) { this.selectionDidChange(); } + if (!isNone(value)) { this.valueDidChange(); } + + this._change(); + }, + + _changeSingle: function() { + var selectedIndex = this.$()[0].selectedIndex; + var content = get(this, 'content'); + var prompt = get(this, 'prompt'); + + if (!content || !get(content, 'length')) { return; } + if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; } + + if (prompt) { selectedIndex -= 1; } + set(this, 'selection', content.objectAt(selectedIndex)); + }, + + + _changeMultiple: function() { + var options = this.$('option:selected'); + var prompt = get(this, 'prompt'); + var offset = prompt ? 1 : 0; + var content = get(this, 'content'); + var selection = get(this, 'selection'); + + if (!content) { return; } + if (options) { + var selectedIndexes = options.map(function() { + return this.index - offset; + }).toArray(); + var newSelection = content.objectsAt(selectedIndexes); + + if (isArray(selection)) { + replace(selection, 0, get(selection, 'length'), newSelection); + } else { + set(this, 'selection', newSelection); + } + } + }, + + _selectionDidChangeSingle: function() { + var el = this.get('element'); + if (!el) { return; } + + var content = get(this, 'content'); + var selection = get(this, 'selection'); + var selectionIndex = content ? indexOf(content, selection) : -1; + var prompt = get(this, 'prompt'); + + if (prompt) { selectionIndex += 1; } + if (el) { el.selectedIndex = selectionIndex; } + }, + + _selectionDidChangeMultiple: function() { + var content = get(this, 'content'); + var selection = get(this, 'selection'); + var selectedIndexes = content ? indexesOf(content, selection) : [-1]; + var prompt = get(this, 'prompt'); + var offset = prompt ? 1 : 0; + var options = this.$('option'); + var adjusted; + + if (options) { + options.each(function() { + adjusted = this.index > -1 ? this.index - offset : -1; + this.selected = indexOf(selectedIndexes, adjusted) > -1; + }); + } + }, + + init: function() { + this._super(); + this.on("didInsertElement", this, this._triggerChange); + this.on("change", this, this._change); + } + }); + + __exports__["default"] = Select; + __exports__.Select = Select; + __exports__.SelectOption = SelectOption; + __exports__.SelectOptgroup = SelectOptgroup; + }); +define("ember-handlebars/controls/text_area", + ["ember-metal/property_get","ember-views/views/component","ember-handlebars/controls/text_support","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-handlebars + */ + var get = __dependency1__.get; + var Component = __dependency2__["default"]; + var TextSupport = __dependency3__["default"]; + var observer = __dependency4__.observer; + + /** + The internal class used to create textarea element when the `{{textarea}}` + helper is used. + + See [handlebars.helpers.textarea](/api/classes/Ember.Handlebars.helpers.html#method_textarea) for usage details. + + ## Layout and LayoutName properties + + Because HTML `textarea` elements do not contain inner HTML the `layout` and + `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextArea + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport + */ + __exports__["default"] = Component.extend(TextSupport, { + instrumentDisplay: '{{textarea}}', + + classNames: ['ember-text-area'], + + tagName: "textarea", + attributeBindings: ['rows', 'cols', 'name', 'selectionEnd', 'selectionStart', 'wrap', 'lang', 'dir'], + rows: null, + cols: null, + + _updateElementValue: observer('value', function() { + // We do this check so cursor position doesn't get affected in IE + var value = get(this, 'value'); + var $el = this.$(); + if ($el && value !== $el.val()) { + $el.val(value); + } + }), + + init: function() { + this._super(); + this.on("didInsertElement", this, this._updateElementValue); + } + }); + }); +define("ember-handlebars/controls/text_field", + ["ember-metal/property_get","ember-metal/property_set","ember-views/views/component","ember-handlebars/controls/text_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var get = __dependency1__.get; + var set = __dependency2__.set; + var Component = __dependency3__["default"]; + var TextSupport = __dependency4__["default"]; + + /** + + The internal class used to create text inputs when the `{{input}}` + helper is used with `type` of `text`. + + See [Handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. + + ## Layout and LayoutName properties + + Because HTML `input` elements are self closing `layout` and `layoutName` + properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s + layout section for more information. + + @class TextField + @namespace Ember + @extends Ember.Component + @uses Ember.TextSupport + */ + __exports__["default"] = Component.extend(TextSupport, { + instrumentDisplay: '{{input type="text"}}', + + classNames: ['ember-text-field'], + tagName: "input", + attributeBindings: ['type', 'value', 'size', 'pattern', 'name', 'min', 'max', + 'accept', 'autocomplete', 'autosave', 'formaction', + 'formenctype', 'formmethod', 'formnovalidate', 'formtarget', + 'height', 'inputmode', 'list', 'multiple', 'step', 'lang', 'dir', + 'width'], + + /** + The `value` attribute of the input element. As the user inputs text, this + property is updated live. + + @property value + @type String + @default "" + */ + value: "", + + /** + The `type` attribute of the input element. + + @property type + @type String + @default "text" + */ + type: "text", + + /** + The `size` of the text field in characters. + + @property size + @type String + @default null + */ + size: null, + + /** + The `pattern` attribute of input element. + + @property pattern + @type String + @default null + */ + pattern: null, + + /** + The `min` attribute of input element used with `type="number"` or `type="range"`. + + @property min + @type String + @default null + @since 1.4.0 + */ + min: null, + + /** + The `max` attribute of input element used with `type="number"` or `type="range"`. + + @property max + @type String + @default null + @since 1.4.0 + */ + max: null + }); + }); +define("ember-handlebars/controls/text_support", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/target_action_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var get = __dependency1__.get; + var set = __dependency2__.set; + var Mixin = __dependency3__.Mixin; + var TargetActionSupport = __dependency4__["default"]; + + /** + Shared mixin used by `Ember.TextField` and `Ember.TextArea`. + + @class TextSupport + @namespace Ember + @uses Ember.TargetActionSupport + @extends Ember.Mixin + @private + */ + var TextSupport = Mixin.create(TargetActionSupport, { + value: "", + + attributeBindings: ['placeholder', 'disabled', 'maxlength', 'tabindex', 'readonly', + 'autofocus', 'form', 'selectionDirection', 'spellcheck', 'required', + 'title', 'autocapitalize', 'autocorrect'], + placeholder: null, + disabled: false, + maxlength: null, + + init: function() { + this._super(); + this.on("focusOut", this, this._elementValueDidChange); + this.on("change", this, this._elementValueDidChange); + this.on("paste", this, this._elementValueDidChange); + this.on("cut", this, this._elementValueDidChange); + this.on("input", this, this._elementValueDidChange); + this.on("keyUp", this, this.interpretKeyEvents); + }, + + /** + The action to be sent when the user presses the return key. + + This is similar to the `{{action}}` helper, but is fired when + the user presses the return key when editing a text field, and sends + the value of the field as the context. + + @property action + @type String + @default null + */ + action: null, + + /** + The event that should send the action. + + Options are: + + * `enter`: the user pressed enter + * `keyPress`: the user pressed a key + + @property onEvent + @type String + @default enter + */ + onEvent: 'enter', + + /** + Whether they `keyUp` event that triggers an `action` to be sent continues + propagating to other views. + + By default, when the user presses the return key on their keyboard and + the text field has an `action` set, the action will be sent to the view's + controller and the key event will stop propagating. + + If you would like parent views to receive the `keyUp` event even after an + action has been dispatched, set `bubbles` to true. + + @property bubbles + @type Boolean + @default false + */ + bubbles: false, + + interpretKeyEvents: function(event) { + var map = TextSupport.KEY_EVENTS; + var method = map[event.keyCode]; + + this._elementValueDidChange(); + if (method) { return this[method](event); } + }, + + _elementValueDidChange: function() { + set(this, 'value', this.$().val()); + }, + + /** + Called when the user inserts a new line. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13. + Uses sendAction to send the `enter` action. + + @method insertNewline + @param {Event} event + */ + insertNewline: function(event) { + sendAction('enter', this, event); + sendAction('insert-newline', this, event); + }, + + /** + Called when the user hits escape. + + Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27. + Uses sendAction to send the `escape-press` action. + + @method cancel + @param {Event} event + */ + cancel: function(event) { + sendAction('escape-press', this, event); + }, + + /** + Called when the text area is focused. + + Uses sendAction to send the `focus-in` action. + + @method focusIn + @param {Event} event + */ + focusIn: function(event) { + sendAction('focus-in', this, event); + }, + + /** + Called when the text area is blurred. + + Uses sendAction to send the `focus-out` action. + + @method focusOut + @param {Event} event + */ + focusOut: function(event) { + sendAction('focus-out', this, event); + }, + + /** + Called when the user presses a key. Enabled by setting + the `onEvent` property to `keyPress`. + + Uses sendAction to send the `key-press` action. + + @method keyPress + @param {Event} event + */ + keyPress: function(event) { + sendAction('key-press', this, event); + } + + }); + + TextSupport.KEY_EVENTS = { + 13: 'insertNewline', + 27: 'cancel' + }; + + // In principle, this shouldn't be necessary, but the legacy + // sendAction semantics for TextField are different from + // the component semantics so this method normalizes them. + function sendAction(eventName, view, event) { + var action = get(view, eventName); + var on = get(view, 'onEvent'); + var value = get(view, 'value'); + + // back-compat support for keyPress as an event name even though + // it's also a method name that consumes the event (and therefore + // incompatible with sendAction semantics). + if (on === eventName || (on === 'keyPress' && eventName === 'key-press')) { + view.sendAction('action', value); + } + + view.sendAction(eventName, value); + + if (action || on === eventName) { + if(!get(view, 'bubbles')) { + event.stopPropagation(); + } + } + } + + __exports__["default"] = TextSupport; + }); +define("ember-handlebars/ext", + ["ember-metal/core","ember-runtime/system/string","ember-handlebars-compiler","ember-metal/property_get","ember-metal/error","ember-metal/mixin","ember-views/views/view","ember-handlebars/views/metamorph_view","ember-metal/path_cache","ember-metal/is_empty","ember-metal/cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.assert, Ember.Handlebars, Ember.lookup + // var emberAssert = Ember.assert; + + var fmt = __dependency2__.fmt; + + var EmberHandlebars = __dependency3__["default"]; + var helpers = EmberHandlebars.helpers; + + var get = __dependency4__.get; + var EmberError = __dependency5__["default"]; + var IS_BINDING = __dependency6__.IS_BINDING; + + var View = __dependency7__["default"]; + var _Metamorph = __dependency8__._Metamorph; + var detectIsGlobal = __dependency9__.isGlobal; + + // late bound via requireModule because of circular dependencies. + var resolveHelper, SimpleHandlebarsView; + + var isEmpty = __dependency10__["default"]; + + var slice = [].slice; + var originalTemplate = EmberHandlebars.template; + + /** + If a path starts with a reserved keyword, returns the root + that should be used. + + @private + @method normalizePath + @for Ember + @param root {Object} + @param path {String} + @param data {Hash} + */ + + var Cache = __dependency11__["default"]; + + var FIRST_SEGMENT_CACHE = new Cache(1000, function(path){ + return path.split('.', 1)[0]; + }); + + function normalizePath(root, path, data) { + var keywords = (data && data.keywords) || {}; + var keyword, isKeyword; + + // Get the first segment of the path. For example, if the + // path is "foo.bar.baz", returns "foo". + keyword = FIRST_SEGMENT_CACHE.get(path); + + // Test to see if the first path is a keyword that has been + // passed along in the view's data hash. If so, we will treat + // that object as the new root. + if (keywords.hasOwnProperty(keyword)) { + // Look up the value in the template's data hash. + root = keywords[keyword]; + isKeyword = true; + + // Handle cases where the entire path is the reserved + // word. In that case, return the object itself. + if (path === keyword) { + path = ''; + } else { + // Strip the keyword from the path and look up + // the remainder from the newly found root. + path = path.substr(keyword.length+1); + } + } + + return { + root: root, + path: path, + isKeyword: isKeyword + }; + } + + + /** + Lookup both on root and on window. If the path starts with + a keyword, the corresponding object will be looked up in the + template's data hash and used to resolve the path. + + @method get + @for Ember.Handlebars + @param {Object} root The object to look up the property on + @param {String} path The path to be lookedup + @param {Object} options The template's option hash + */ + function handlebarsGet(root, path, options) { + var data = options && options.data; + var normalizedPath = normalizePath(root, path, data); + var value; + + // In cases where the path begins with a keyword, change the + // root to the value represented by that keyword, and ensure + // the path is relative to it. + root = normalizedPath.root; + path = normalizedPath.path; + + // Ember.get with a null root and GlobalPath will fall back to + // Ember.lookup, which is no longer allowed in templates. + // + // But when outputting a primitive, root will be the primitive + // and path a blank string. These primitives should pass through + // to `get`. + if (root || path === '') { + value = get(root, path); + } + + if (detectIsGlobal(path)) { + if (value === undefined && root !== Ember.lookup) { + root = Ember.lookup; + value = get(root, path); + } + if (root === Ember.lookup || root === null) { + } + } + + return value; + } + + /** + handlebarsGetView resolves a view based on strings passed into a template. + For example: + + ```handlebars + {{view "some-view"}} + {{view view.someView}} + {{view App.SomeView}} {{! deprecated }} + ``` + + A value is first checked to be a string- non-strings are presumed to be + an object and returned. This handles the "access a view on a context" + case (line 2 in the above examples). + + Next a string is normalized, then called on the context with `get`. If + there is still no value, a GlobalPath will be fetched from the global + context (raising a deprecation) and a localPath will be passed to the + container to be looked up. + + @private + @for Ember.Handlebars + @param {Object} context The context of the template being rendered + @param {String} path The path to be lookedup + @param {Object} container The container + @param {Object} data The template's data hash + */ + function handlebarsGetView(context, path, container, data) { + var viewClass; + if ('string' === typeof path) { + if (data) { + var normalizedPath = normalizePath(context, path, data); + context = normalizedPath.root; + path = normalizedPath.path; + } + + // Only lookup view class on context if there is a context. If not, + // the global lookup path on get may kick in. + viewClass = context && get(context, path); + var isGlobal = detectIsGlobal(path); + + if (!viewClass && !isGlobal) { + viewClass = container.lookupFactory('view:'+path); + } + if (!viewClass && isGlobal) { + var globalViewClass = get(path); + if (globalViewClass) { + viewClass = globalViewClass; + } + } + } else { + viewClass = path; + } + + // Sometimes a view's value is yet another path + if ('string' === typeof viewClass && data && data.view) { + viewClass = handlebarsGetView(data.view, viewClass, container, data); + } + + + return viewClass; + } + + /** + This method uses `Ember.Handlebars.get` to lookup a value, then ensures + that the value is escaped properly. + + If `unescaped` is a truthy value then the escaping will not be performed. + + @method getEscaped + @for Ember.Handlebars + @param {Object} root The object to look up the property on + @param {String} path The path to be lookedup + @param {Object} options The template's option hash + @since 1.4.0 + */ + function getEscaped(root, path, options) { + var result = handlebarsGet(root, path, options); + + if (result === null || result === undefined) { + result = ""; + } else if (!(result instanceof Handlebars.SafeString)) { + result = String(result); + } + if (!options.hash.unescaped){ + result = Handlebars.Utils.escapeExpression(result); + } + + return result; + } + + __exports__.getEscaped = getEscaped;function resolveParams(context, params, options) { + var resolvedParams = [], types = options.types, param, type; + + for (var i=0, l=params.length; i{{user.name}} + +
    +
    {{user.role.label}}
    + {{user.role.id}} + +

    {{user.role.description}}

    +
    + ``` + + `{{with}}` can be our best friend in these cases, + instead of writing `user.role.*` over and over, we use `{{#with user.role}}`. + Now the context within the `{{#with}} .. {{/with}}` block is `user.role` so you can do the following: + + ```handlebars +
    {{user.name}}
    + +
    + {{#with user.role}} +
    {{label}}
    + {{id}} + +

    {{description}}

    + {{/with}} +
    + ``` + + ### `as` operator + + This operator aliases the scope to a new name. It's helpful for semantic clarity and to retain + default scope or to reference from another `{{with}}` block. + + ```handlebars + // posts might not be + {{#with user.posts as blogPosts}} +
    + There are {{blogPosts.length}} blog posts written by {{user.name}}. +
    + + {{#each post in blogPosts}} +
  • {{post.title}}
  • + {{/each}} + {{/with}} + ``` + + Without the `as` operator, it would be impossible to reference `user.name` in the example above. + + NOTE: The alias should not reuse a name from the bound property path. + For example: `{{#with foo.bar as foo}}` is not supported because it attempts to alias using + the first part of the property path, `foo`. Instead, use `{{#with foo.bar as baz}}`. + + ### `controller` option + + Adding `controller='something'` instructs the `{{with}}` helper to create and use an instance of + the specified controller with the new context as its content. + + This is very similar to using an `itemController` option with the `{{each}}` helper. + + ```handlebars + {{#with users.posts controller='userBlogPosts'}} + {{!- The current context is wrapped in our controller instance }} + {{/with}} + ``` + + In the above example, the template provided to the `{{with}}` block is now wrapped in the + `userBlogPost` controller, which provides a very elegant way to decorate the context with custom + functions/properties. + + @method with + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function withHelper(context, options) { + var bindContext, preserveContext, controller; + var helperName = 'with'; + + if (arguments.length === 4) { + var keywordName, path, rootPath, normalized, contextPath; + + options = arguments[3]; + keywordName = arguments[2]; + path = arguments[0]; + + if (path) { + helperName += ' ' + path + ' as ' + keywordName; + } + + + var localizedOptions = o_create(options); + localizedOptions.data = o_create(options.data); + localizedOptions.data.keywords = o_create(options.data.keywords || {}); + + if (isGlobalPath(path)) { + contextPath = path; + } else { + normalized = normalizePath(this, path, options.data); + path = normalized.path; + rootPath = normalized.root; + + // This is a workaround for the fact that you cannot bind separate objects + // together. When we implement that functionality, we should use it here. + var contextKey = jQuery.expando + guidFor(rootPath); + localizedOptions.data.keywords[contextKey] = rootPath; + // if the path is '' ("this"), just bind directly to the current context + contextPath = path ? contextKey + '.' + path : contextKey; + } + + localizedOptions.hash.keywordName = keywordName; + localizedOptions.hash.keywordPath = contextPath; + + bindContext = this; + context = contextPath; + options = localizedOptions; + preserveContext = true; + } else { + + helperName += ' ' + context; + bindContext = options.contexts[0]; + preserveContext = false; + } + + options.helperName = helperName; + options.isWithHelper = true; + + return bind.call(bindContext, context, options, preserveContext, exists); + } + /** + See [boundIf](/api/classes/Ember.Handlebars.helpers.html#method_boundIf) + and [unboundIf](/api/classes/Ember.Handlebars.helpers.html#method_unboundIf) + + @method if + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function ifHelper(context, options) { + + options.helperName = options.helperName || ('if ' + context); + + if (options.data.isUnbound) { + return helpers.unboundIf.call(options.contexts[0], context, options); + } else { + return helpers.boundIf.call(options.contexts[0], context, options); + } + } + + /** + @method unless + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function unlessHelper(context, options) { + + var fn = options.fn; + var inverse = options.inverse; + var helperName = 'unless'; + + if (context) { + helperName += ' ' + context; + } + + options.fn = inverse; + options.inverse = fn; + + options.helperName = options.helperName || helperName; + + if (options.data.isUnbound) { + return helpers.unboundIf.call(options.contexts[0], context, options); + } else { + return helpers.boundIf.call(options.contexts[0], context, options); + } + } + + /** + `bind-attr` allows you to create a binding between DOM element attributes and + Ember objects. For example: + + ```handlebars + imageTitle + ``` + + The above handlebars template will fill the ``'s `src` attribute with + the value of the property referenced with `"imageUrl"` and its `alt` + attribute with the value of the property referenced with `"imageTitle"`. + + If the rendering context of this template is the following object: + + ```javascript + { + imageUrl: 'http://lolcats.info/haz-a-funny', + imageTitle: 'A humorous image of a cat' + } + ``` + + The resulting HTML output will be: + + ```html + A humorous image of a cat + ``` + + `bind-attr` cannot redeclare existing DOM element attributes. The use of `src` + in the following `bind-attr` example will be ignored and the hard coded value + of `src="/failwhale.gif"` will take precedence: + + ```handlebars + imageTitle + ``` + + ### `bind-attr` and the `class` attribute + + `bind-attr` supports a special syntax for handling a number of cases unique + to the `class` DOM element attribute. The `class` attribute combines + multiple discrete values into a single attribute as a space-delimited + list of strings. Each string can be: + + * a string return value of an object's property. + * a boolean return value of an object's property + * a hard-coded value + + A string return value works identically to other uses of `bind-attr`. The + return value of the property will become the value of the attribute. For + example, the following view and template: + + ```javascript + AView = View.extend({ + someProperty: function() { + return "aValue"; + }.property() + }) + ``` + + ```handlebars + + ``` + + A boolean return value will insert a specified class name if the property + returns `true` and remove the class name if the property returns `false`. + + A class name is provided via the syntax + `somePropertyName:class-name-if-true`. + + ```javascript + AView = View.extend({ + someBool: true + }) + ``` + + ```handlebars + + ``` + + Result in the following rendered output: + + ```html + + ``` + + An additional section of the binding can be provided if you want to + replace the existing class instead of removing it when the boolean + value changes: + + ```handlebars + + ``` + + A hard-coded value can be used by prepending `:` to the desired + class name: `:class-name-to-always-apply`. + + ```handlebars + + ``` + + Results in the following rendered output: + + ```html + + ``` + + All three strategies - string return value, boolean return value, and + hard-coded value – can be combined in a single declaration: + + ```handlebars + + ``` + + @method bind-attr + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string + */ + function bindAttrHelper(options) { + var attrs = options.hash; + + + var view = options.data.view; + var ret = []; + + // we relied on the behavior of calling without + // context to mean this === window, but when running + // "use strict", it's possible for this to === undefined; + var ctx = this || window; + + // Generate a unique id for this element. This will be added as a + // data attribute to the element so it can be looked up when + // the bound property changes. + var dataId = uuid(); + + // Handle classes differently, as we can bind multiple classes + var classBindings = attrs['class']; + if (classBindings != null) { + var classResults = bindClasses(ctx, classBindings, view, dataId, options); + + ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"'); + delete attrs['class']; + } + + var attrKeys = keys(attrs); + + // For each attribute passed, create an observer and emit the + // current value of the property as an attribute. + forEach.call(attrKeys, function(attr) { + var path = attrs[attr]; + var normalized; + + + normalized = normalizePath(ctx, path, options.data); + + var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options); + var type = typeOf(value); + + + var observer; + + observer = function observer() { + var result = handlebarsGet(ctx, path, options); + + + var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']"); + + // If we aren't able to find the element, it means the element + // to which we were bound has been removed from the view. + // In that case, we can assume the template has been re-rendered + // and we need to clean up the observer. + if (!elem || elem.length === 0) { + removeObserver(normalized.root, normalized.path, observer); + return; + } + + View.applyAttributeBindings(elem, attr, result); + }; + + // Add an observer to the view for when the property changes. + // When the observer fires, find the element using the + // unique data id and update the attribute to the new value. + // Note: don't add observer when path is 'this' or path + // is whole keyword e.g. {{#each x in list}} ... {{bind-attr attr="x"}} + if (path !== 'this' && !(normalized.isKeyword && normalized.path === '' )) { + view.registerObserver(normalized.root, normalized.path, observer); + } + + // if this changes, also change the logic in ember-views/lib/views/view.js + if ((type === 'string' || (type === 'number' && !isNaN(value)))) { + ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"'); + } else if (value && type === 'boolean') { + // The developer controls the attr name, so it should always be safe + ret.push(attr + '="' + attr + '"'); + } + }, this); + + // Add the unique identifier + // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG + ret.push('data-bindattr-' + dataId + '="' + dataId + '"'); + return new SafeString(ret.join(' ')); + } + + /** + See `bind-attr` + + @method bindAttr + @for Ember.Handlebars.helpers + @deprecated + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function bindAttrHelperDeprecated() { + return helpers['bind-attr'].apply(this, arguments); + } + + /** + Helper that, given a space-separated string of property paths and a context, + returns an array of class names. Calling this method also has the side + effect of setting up observers at those property paths, such that if they + change, the correct class name will be reapplied to the DOM element. + + For example, if you pass the string "fooBar", it will first look up the + "fooBar" value of the context. If that value is true, it will add the + "foo-bar" class to the current element (i.e., the dasherized form of + "fooBar"). If the value is a string, it will add that string as the class. + Otherwise, it will not add any new class name. + + @private + @method bindClasses + @for Ember.Handlebars + @param {Ember.Object} context The context from which to lookup properties + @param {String} classBindings A string, space-separated, of class bindings + to use + @param {View} view The view in which observers should look for the + element to update + @param {Srting} bindAttrId Optional bindAttr id used to lookup elements + @return {Array} An array of class names to add + */ + function bindClasses(context, classBindings, view, bindAttrId, options) { + var ret = []; + var newClass, value, elem; + + // Helper method to retrieve the property from the context and + // determine which class string to return, based on whether it is + // a Boolean or not. + var classStringForPath = function(root, parsedPath, options) { + var val; + var path = parsedPath.path; + + if (path === 'this') { + val = root; + } else if (path === '') { + val = true; + } else { + val = handlebarsGet(root, path, options); + } + + return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }; + + // For each property passed, loop through and setup + // an observer. + forEach.call(classBindings.split(' '), function(binding) { + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + var observer; + var parsedPath = View._parsePropertyPath(binding); + var path = parsedPath.path; + var pathRoot = context; + var normalized; + + if (path !== '' && path !== 'this') { + normalized = normalizePath(context, path, options.data); + + pathRoot = normalized.root; + path = normalized.path; + } + + // Set up an observer on the context. If the property changes, toggle the + // class name. + observer = function() { + // Get the current value of the property + newClass = classStringForPath(context, parsedPath, options); + elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$(); + + // If we can't find the element anymore, a parent template has been + // re-rendered and we've been nuked. Remove the observer. + if (!elem || elem.length === 0) { + removeObserver(pathRoot, path, observer); + } else { + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + } + }; + + if (path !== '' && path !== 'this') { + view.registerObserver(pathRoot, path, observer); + } + + // We've already setup the observer; now we just need to figure out the + // correct behavior right now on the first pass through. + value = classStringForPath(context, parsedPath, options); + + if (value) { + ret.push(value); + + // Make sure we save the current value so that it can be removed if the + // observer fires. + oldClass = value; + } + }); + + return ret; + } + + __exports__.bind = bind; + __exports__._triageMustacheHelper = _triageMustacheHelper; + __exports__.resolveHelper = resolveHelper; + __exports__.bindHelper = bindHelper; + __exports__.boundIfHelper = boundIfHelper; + __exports__.unboundIfHelper = unboundIfHelper; + __exports__.withHelper = withHelper; + __exports__.ifHelper = ifHelper; + __exports__.unlessHelper = unlessHelper; + __exports__.bindAttrHelper = bindAttrHelper; + __exports__.bindAttrHelperDeprecated = bindAttrHelperDeprecated; + __exports__.bindClasses = bindClasses; + }); +define("ember-handlebars/helpers/collection", + ["ember-metal/core","ember-metal/utils","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-handlebars/ext","ember-handlebars/helpers/view","ember-metal/computed","ember-views/views/collection_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.deprecate + var inspect = __dependency2__.inspect; + + // var emberAssert = Ember.assert; + // emberDeprecate = Ember.deprecate; + + var EmberHandlebars = __dependency3__["default"]; + var helpers = EmberHandlebars.helpers; + + var fmt = __dependency4__.fmt; + var get = __dependency5__.get; + var handlebarsGet = __dependency6__.handlebarsGet; + var handlebarsGetView = __dependency6__.handlebarsGetView; + var ViewHelper = __dependency7__.ViewHelper; + var computed = __dependency8__.computed; + var CollectionView = __dependency9__["default"]; + + var alias = computed.alias; + /** + `{{collection}}` is a `Ember.Handlebars` helper for adding instances of + `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html) + for additional information on how a `CollectionView` functions. + + `{{collection}}`'s primary use is as a block helper with a `contentBinding` + option pointing towards an `Ember.Array`-compatible object. An `Ember.View` + instance will be created for each item in its `content` property. Each view + will have its own `content` property set to the appropriate item in the + collection. + + The provided block will be applied as the template for each item's view. + + Given an empty `` the following template: + + ```handlebars + {{! application.hbs }} + {{#collection content=model}} + Hi {{view.content.name}} + {{/collection}} + ``` + + And the following application code + + ```javascript + App = Ember.Application.create(); + App.ApplicationRoute = Ember.Route.extend({ + model: function(){ + return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; + } + }); + ``` + + The following HTML will result: + + ```html +
    +
    Hi Yehuda
    +
    Hi Tom
    +
    Hi Peter
    +
    + ``` + + ### Non-block version of collection + + If you provide an `itemViewClass` option that has its own `template` you may + omit the block. + + The following template: + + ```handlebars + {{! application.hbs }} + {{collection content=model itemViewClass="an-item"}} + ``` + + And application code + + ```javascript + App = Ember.Application.create(); + App.ApplicationRoute = Ember.Route.extend({ + model: function(){ + return [{name: 'Yehuda'},{name: 'Tom'},{name: 'Peter'}]; + } + }); + + App.AnItemView = Ember.View.extend({ + template: Ember.Handlebars.compile("Greetings {{view.content.name}}") + }); + ``` + + Will result in the HTML structure below + + ```html +
    +
    Greetings Yehuda
    +
    Greetings Tom
    +
    Greetings Peter
    +
    + ``` + + ### Specifying a CollectionView subclass + + By default the `{{collection}}` helper will create an instance of + `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to + the helper by passing it as the first argument: + + ```handlebars + {{#collection "my-custom-collection" content=model}} + Hi {{view.content.name}} + {{/collection}} + ``` + + This example would look for the class `App.MyCustomCollection`. + + ### Forwarded `item.*`-named Options + + As with the `{{view}}`, helper options passed to the `{{collection}}` will be + set on the resulting `Ember.CollectionView` as properties. Additionally, + options prefixed with `item` will be applied to the views rendered for each + item (note the camelcasing): + + ```handlebars + {{#collection content=model + itemTagName="p" + itemClassNames="greeting"}} + Howdy {{view.content.name}} + {{/collection}} + ``` + + Will result in the following HTML structure: + + ```html +
    +

    Howdy Yehuda

    +

    Howdy Tom

    +

    Howdy Peter

    +
    + ``` + + @method collection + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + @deprecated Use `{{each}}` helper instead. + */ + function collectionHelper(path, options) { + + // If no path is provided, treat path param as options. + if (path && path.data && path.data.isRenderData) { + options = path; + path = undefined; + } else { + } + + var fn = options.fn, + data = options.data, + inverse = options.inverse, + view = options.data.view, + // This should be deterministic, and should probably come from a + // parent view and not the controller. + container = (view.controller && view.controller.container ? view.controller.container : view.container); + + // If passed a path string, convert that into an object. + // Otherwise, just default to the standard class. + var collectionClass; + if (path) { + collectionClass = handlebarsGetView(this, path, container, options.data); + } + else { + collectionClass = CollectionView; + } + + var hash = options.hash; + var itemHash = {}; + var match; + + // Extract item view class if provided else default to the standard class + var collectionPrototype = collectionClass.proto(); + var itemViewClass; + + if (hash.itemView) { + itemViewClass = handlebarsGetView(this, hash.itemView, container, options.data); + } else if (hash.itemViewClass) { + itemViewClass = handlebarsGetView(collectionPrototype, hash.itemViewClass, container, options.data); + } else { + itemViewClass = handlebarsGetView(collectionPrototype, collectionPrototype.itemViewClass, container, options.data); + } + + + delete hash.itemViewClass; + delete hash.itemView; + + // Go through options passed to the {{collection}} helper and extract options + // that configure item views instead of the collection itself. + for (var prop in hash) { + if (hash.hasOwnProperty(prop)) { + match = prop.match(/^item(.)(.*)$/); + + if (match && prop !== 'itemController') { + // Convert itemShouldFoo -> shouldFoo + itemHash[match[1].toLowerCase() + match[2]] = hash[prop]; + // Delete from hash as this will end up getting passed to the + // {{view}} helper method. + delete hash[prop]; + } + } + } + + if (fn) { + itemHash.template = fn; + delete options.fn; + } + + var emptyViewClass; + if (inverse && inverse !== EmberHandlebars.VM.noop) { + emptyViewClass = get(collectionPrototype, 'emptyViewClass'); + emptyViewClass = emptyViewClass.extend({ + template: inverse, + tagName: itemHash.tagName + }); + } else if (hash.emptyViewClass) { + emptyViewClass = handlebarsGetView(this, hash.emptyViewClass, container, options.data); + } + if (emptyViewClass) { hash.emptyView = emptyViewClass; } + + if (hash.keyword) { + itemHash._context = this; + } else { + itemHash._context = alias('content'); + } + + var viewOptions = ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this); + hash.itemViewClass = itemViewClass.extend(viewOptions); + + options.helperName = options.helperName || 'collection'; + + return helpers.view.call(this, collectionClass, options); + } + + __exports__["default"] = collectionHelper; + }); +define("ember-handlebars/helpers/debug", + ["ember-metal/core","ember-metal/utils","ember-metal/logger","ember-metal/property_get","ember-handlebars/ext","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /*jshint debug:true*/ + + /** + @module ember + @submodule ember-handlebars + */ + var Ember = __dependency1__["default"]; + // Ember.FEATURES, + var inspect = __dependency2__.inspect; + var Logger = __dependency3__["default"]; + + var get = __dependency4__.get; + var normalizePath = __dependency5__.normalizePath; + var handlebarsGet = __dependency5__.handlebarsGet; + + var a_slice = [].slice; + + /** + `log` allows you to output the value of variables in the current rendering + context. `log` also accepts primitive types such as strings or numbers. + + ```handlebars + {{log "myVariable:" myVariable }} + ``` + + @method log + @for Ember.Handlebars.helpers + @param {String} property + */ + function logHelper() { + var params = a_slice.call(arguments, 0, -1); + var options = arguments[arguments.length - 1]; + var logger = Logger.log; + var values = []; + var allowPrimitives = true; + + for (var i = 0; i < params.length; i++) { + var type = options.types[i]; + + if (type === 'ID' || !allowPrimitives) { + var context = (options.contexts && options.contexts[i]) || this; + var normalized = normalizePath(context, params[i], options.data); + + if (normalized.path === 'this') { + values.push(normalized.root); + } else { + values.push(handlebarsGet(normalized.root, normalized.path, options)); + } + } else { + values.push(params[i]); + } + } + + logger.apply(logger, values); + } + + /** + Execute the `debugger` statement in the current context. + + ```handlebars + {{debugger}} + ``` + + Before invoking the `debugger` statement, there + are a few helpful variables defined in the + body of this helper that you can inspect while + debugging that describe how and where this + helper was invoked: + + - templateContext: this is most likely a controller + from which this template looks up / displays properties + - typeOfTemplateContext: a string description of + what the templateContext is + + For example, if you're wondering why a value `{{foo}}` + isn't rendering as expected within a template, you + could place a `{{debugger}}` statement, and when + the `debugger;` breakpoint is hit, you can inspect + `templateContext`, determine if it's the object you + expect, and/or evaluate expressions in the console + to perform property lookups on the `templateContext`: + + ``` + > templateContext.get('foo') // -> "" + ``` + + @method debugger + @for Ember.Handlebars.helpers + @param {String} property + */ + function debuggerHelper(options) { + + // These are helpful values you can inspect while debugging. + var templateContext = this; + var typeOfTemplateContext = inspect(templateContext); + + debugger; + } + + __exports__.logHelper = logHelper; + __exports__.debuggerHelper = debuggerHelper; + }); +define("ember-handlebars/helpers/each", + ["ember-metal/core","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-metal/property_set","ember-views/views/collection_view","ember-metal/binding","ember-runtime/mixins/controller","ember-runtime/controllers/array_controller","ember-runtime/mixins/array","ember-runtime/copy","ember-metal/run_loop","ember-metal/events","ember-handlebars/ext","ember-metal/computed","ember-metal/observer","ember-handlebars/views/metamorph_view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __exports__) { + "use strict"; + + /** + @module ember + @submodule ember-handlebars + */ + var Ember = __dependency1__["default"]; + // Ember.assert;, Ember.K + var K = Ember.K; + + var EmberHandlebars = __dependency2__["default"]; + var helpers = EmberHandlebars.helpers; + + var fmt = __dependency3__.fmt; + var get = __dependency4__.get; + var set = __dependency5__.set; + var CollectionView = __dependency6__["default"]; + var Binding = __dependency7__.Binding; + var ControllerMixin = __dependency8__["default"]; + var ArrayController = __dependency9__["default"]; + var EmberArray = __dependency10__["default"]; + var copy = __dependency11__["default"]; + var run = __dependency12__["default"]; + var on = __dependency13__.on; + var handlebarsGet = __dependency14__.handlebarsGet; + var computed = __dependency15__.computed; + + var addObserver = __dependency16__.addObserver; + var removeObserver = __dependency16__.removeObserver; + var addBeforeObserver = __dependency16__.addBeforeObserver; + var removeBeforeObserver = __dependency16__.removeBeforeObserver; + + var _Metamorph = __dependency17__._Metamorph; + var _MetamorphView = __dependency17__._MetamorphView; + + var EachView = CollectionView.extend(_Metamorph, { + + init: function() { + var itemController = get(this, 'itemController'); + var binding; + + if (itemController) { + var controller = get(this, 'controller.container').lookupFactory('controller:array').create({ + _isVirtual: true, + parentController: get(this, 'controller'), + itemController: itemController, + target: get(this, 'controller'), + _eachView: this + }); + + this.disableContentObservers(function() { + set(this, 'content', controller); + binding = new Binding('content', '_eachView.dataSource').oneWay(); + binding.connect(controller); + }); + + set(this, '_arrayController', controller); + } else { + this.disableContentObservers(function() { + binding = new Binding('content', 'dataSource').oneWay(); + binding.connect(this); + }); + } + + return this._super(); + }, + + _assertArrayLike: function(content) { + }, + + disableContentObservers: function(callback) { + removeBeforeObserver(this, 'content', null, '_contentWillChange'); + removeObserver(this, 'content', null, '_contentDidChange'); + + callback.call(this); + + addBeforeObserver(this, 'content', null, '_contentWillChange'); + addObserver(this, 'content', null, '_contentDidChange'); + }, + + itemViewClass: _MetamorphView, + emptyViewClass: _MetamorphView, + + createChildView: function(view, attrs) { + view = this._super(view, attrs); + + // At the moment, if a container view subclass wants + // to insert keywords, it is responsible for cloning + // the keywords hash. This will be fixed momentarily. + var keyword = get(this, 'keyword'); + var content = get(view, 'content'); + + if (keyword) { + var data = get(view, 'templateData'); + + data = copy(data); + data.keywords = view.cloneKeywords(); + set(view, 'templateData', data); + + // In this case, we do not bind, because the `content` of + // a #each item cannot change. + data.keywords[keyword] = content; + } + + // If {{#each}} is looping over an array of controllers, + // point each child view at their respective controller. + if (content && content.isController) { + set(view, 'controller', content); + } + + return view; + }, + + destroy: function() { + if (!this._super()) { return; } + + var arrayController = get(this, '_arrayController'); + + if (arrayController) { + arrayController.destroy(); + } + + return this; + } + }); + + var GroupedEach = EmberHandlebars.GroupedEach = function(context, path, options) { + var self = this; + var normalized = EmberHandlebars.normalizePath(context, path, options.data); + + this.context = context; + this.path = path; + this.options = options; + this.template = options.fn; + this.containingView = options.data.view; + this.normalizedRoot = normalized.root; + this.normalizedPath = normalized.path; + this.content = this.lookupContent(); + + this.addContentObservers(); + this.addArrayObservers(); + + this.containingView.on('willClearRender', function() { + self.destroy(); + }); + }; + + GroupedEach.prototype = { + contentWillChange: function() { + this.removeArrayObservers(); + }, + + contentDidChange: function() { + this.content = this.lookupContent(); + this.addArrayObservers(); + this.rerenderContainingView(); + }, + + contentArrayWillChange: K, + + contentArrayDidChange: function() { + this.rerenderContainingView(); + }, + + lookupContent: function() { + return handlebarsGet(this.normalizedRoot, this.normalizedPath, this.options); + }, + + addArrayObservers: function() { + if (!this.content) { return; } + + this.content.addArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + removeArrayObservers: function() { + if (!this.content) { return; } + + this.content.removeArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + }, + + addContentObservers: function() { + addBeforeObserver(this.normalizedRoot, this.normalizedPath, this, this.contentWillChange); + addObserver(this.normalizedRoot, this.normalizedPath, this, this.contentDidChange); + }, + + removeContentObservers: function() { + removeBeforeObserver(this.normalizedRoot, this.normalizedPath, this.contentWillChange); + removeObserver(this.normalizedRoot, this.normalizedPath, this.contentDidChange); + }, + + render: function() { + if (!this.content) { return; } + + var content = this.content; + var contentLength = get(content, 'length'); + var options = this.options; + var data = options.data; + var template = this.template; + + data.insideEach = true; + for (var i = 0; i < contentLength; i++) { + var context = content.objectAt(i); + options.data.keywords[options.hash.keyword] = context; + template(context, { data: data }); + } + }, + + rerenderContainingView: function() { + var self = this; + run.scheduleOnce('render', this, function() { + // It's possible it's been destroyed after we enqueued a re-render call. + if (!self.destroyed) { + self.containingView.rerender(); + } + }); + }, + + destroy: function() { + this.removeContentObservers(); + if (this.content) { + this.removeArrayObservers(); + } + this.destroyed = true; + } + }; + + /** + The `{{#each}}` helper loops over elements in a collection. It is an extension + of the base Handlebars `{{#each}}` helper. + + The default behavior of `{{#each}}` is to yield its inner block once for every + item in an array. Each yield will provide the item as the context of the block. + + ```javascript + var developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}]; + ``` + + ```handlebars + {{#each developers}} + {{name}} + {{! `this` is each developer }} + {{/each}} + ``` + + `{{#each}}` supports an alternative syntax with element naming. This preserves + context of the yielded block: + + ```handlebars + {{#each person in developers}} + {{person.name}} + {{! `this` is whatever it was outside the #each }} + {{/each}} + ``` + + The same rules apply to arrays of primitives, but the items may need to be + references with `{{this}}`. + + ```javascript + var developerNames = ['Yehuda', 'Tom', 'Paul'] + ``` + + ```handlebars + {{#each developerNames}} + {{this}} + {{/each}} + ``` + + ### {{else}} condition + + `{{#each}}` can have a matching `{{else}}`. The contents of this block will render + if the collection is empty. + + ``` + {{#each person in developers}} + {{person.name}} + {{else}} +

    Sorry, nobody is available for this task.

    + {{/each}} + ``` + + ### Specifying an alternative view for each item + + `itemViewClass` can control which view will be used during the render of each + item's template. + + The following template: + + ```handlebars +
      + {{#each developers itemViewClass="person"}} + {{name}} + {{/each}} +
    + ``` + + Will use the following view for each item + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li' + }); + ``` + + Resulting in HTML output that looks like the following: + + ```html +
      +
    • Yehuda
    • +
    • Tom
    • +
    • Paul
    • +
    + ``` + + `itemViewClass` also enables a non-block form of `{{each}}`. The view + must {{#crossLink "Ember.View/toc_templates"}}provide its own template{{/crossLink}}, + and then the block should be dropped. An example that outputs the same HTML + as the previous one: + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li', + template: '{{name}}' + }); + ``` + + ```handlebars +
      + {{each developers itemViewClass="person"}} +
    + ``` + + ### Specifying an alternative view for no items (else) + + The `emptyViewClass` option provides the same flexibility to the `{{else}}` + case of the each helper. + + ```javascript + App.NoPeopleView = Ember.View.extend({ + tagName: 'li', + template: 'No person is available, sorry' + }); + ``` + + ```handlebars +
      + {{#each developers emptyViewClass="no-people"}} +
    • {{name}}
    • + {{/each}} +
    + ``` + + ### Wrapping each item in a controller + + Controllers in Ember manage state and decorate data. In many cases, + providing a controller for each item in a list can be useful. + Specifically, an {{#crossLink "Ember.ObjectController"}}Ember.ObjectController{{/crossLink}} + should probably be used. Item controllers are passed the item they + will present as a `model` property, and an object controller will + proxy property lookups to `model` for us. + + This allows state and decoration to be added to the controller + while any other property lookups are delegated to the model. An example: + + ```javascript + App.RecruitController = Ember.ObjectController.extend({ + isAvailableForHire: function() { + return !this.get('isEmployed') && this.get('isSeekingWork'); + }.property('isEmployed', 'isSeekingWork') + }) + ``` + + ```handlebars + {{#each person in developers itemController="recruit"}} + {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}} + {{/each}} + ``` + + ### (Experimental) Grouped Each + + If a list's membership often changes, but properties of items in that + group rarely change, a significant improvement in template rendering + time can be achieved by using the experimental [group helper](https://github.com/emberjs/group-helper). + + ```handlebars + {{#group}} + {{#each people}} + {{firstName}} {{lastName}} + {{/each}} + {{/group}} + ``` + + When the membership of `people` changes, or when any property changes, the entire + `{{#group}}` block will be re-rendered. + + An `{{#each}}` inside the `{{#group}}` helper can opt-out of the special group + behavior by passing the `groupedRows` option. For example: + + ```handlebars + {{#group}} + {{#each dealers}} + {{! uses group's special behavior }} + {{firstName}} {{lastName}} + {{/each}} + + {{#each car in cars groupedRows=true}} + {{! does not use group's special behavior }} + {{car.make}} {{car.model}} {{car.color}} + {{/each}} + {{/group}} + ``` + + Any change to the `dealers` collection will cause the entire group to be re-rendered. + Changes to the `cars` collection will be re-rendered individually, as they are with + normal `{{#each}}` usage. + + `{{#group}}` is implemented with an `itemViewClass`, so specifying an `itemViewClass` + on an `{{#each}}` will also disable the special re-rendering behavior. + + @method each + @for Ember.Handlebars.helpers + @param [name] {String} name for item (used with `in`) + @param [path] {String} path + @param [options] {Object} Handlebars key/value pairs of options + @param [options.itemViewClass] {String} a path to a view class used for each item + @param [options.emptyViewClass] {String} a path to a view class used for each item + @param [options.itemController] {String} name of a controller to be created for each item + @param [options.groupedRows] {boolean} enable normal item-by-item rendering when inside a `#group` helper + */ + function eachHelper(path, options) { + var ctx; + var helperName = 'each'; + + if (arguments.length === 4) { + + var keywordName = arguments[0]; + + + options = arguments[3]; + path = arguments[2]; + + helperName += ' ' + keywordName + ' in ' + path; + + if (path === '') { path = "this"; } + + options.hash.keyword = keywordName; + + } else if (arguments.length === 1) { + options = path; + path = 'this'; + } else { + helperName += ' ' + path; + } + + options.hash.dataSourceBinding = path; + // Set up emptyView as a metamorph with no tag + //options.hash.emptyViewClass = Ember._MetamorphView; + + // can't rely on this default behavior when use strict + ctx = this || window; + + options.helperName = options.helperName || helperName; + + if (options.data.insideGroup && !options.hash.groupedRows && !options.hash.itemViewClass) { + new GroupedEach(ctx, path, options).render(); + } else { + return helpers.collection.call(ctx, EmberHandlebars.EachView, options); + } + } + + __exports__.EachView = EachView; + __exports__.GroupedEach = GroupedEach; + __exports__.eachHelper = eachHelper; + }); +define("ember-handlebars/helpers/loc", + ["ember-runtime/system/string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var loc = __dependency1__.loc; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + Calls [Ember.String.loc](/api/classes/Ember.String.html#method_loc) with the + provided string. + + This is a convenient way to localize text within a template: + + ```javascript + Ember.STRINGS = { + '_welcome_': 'Bonjour' + }; + ``` + + ```handlebars +
    + {{loc '_welcome_'}} +
    + ``` + + ```html +
    + Bonjour +
    + ``` + + See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to + set up localized string references. + + @method loc + @for Ember.Handlebars.helpers + @param {String} str The string to format + @see {Ember.String#loc} + */ + __exports__["default"] = loc; + }); +define("ember-handlebars/helpers/partial", + ["ember-metal/core","ember-metal/is_none","ember-handlebars/ext","ember-handlebars/helpers/binding","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + // var emberAssert = Ember.assert; + + var isNone = __dependency2__.isNone; + var handlebarsGet = __dependency3__.handlebarsGet; + var bind = __dependency4__.bind; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + The `partial` helper renders another template without + changing the template context: + + ```handlebars + {{foo}} + {{partial "nav"}} + ``` + + The above example template will render a template named + "_nav", which has the same context as the parent template + it's rendered into, so if the "_nav" template also referenced + `{{foo}}`, it would print the same thing as the `{{foo}}` + in the above example. + + If a "_nav" template isn't found, the `partial` helper will + fall back to a template named "nav". + + ## Bound template names + + The parameter supplied to `partial` can also be a path + to a property containing a template name, e.g.: + + ```handlebars + {{partial someTemplateName}} + ``` + + The above example will look up the value of `someTemplateName` + on the template context (e.g. a controller) and use that + value as the name of the template to render. If the resolved + value is falsy, nothing will be rendered. If `someTemplateName` + changes, the partial will be re-rendered using the new template + name. + + ## Setting the partial's context with `with` + + The `partial` helper can be used in conjunction with the `with` + helper to set a context that will be used by the partial: + + ```handlebars + {{#with currentUser}} + {{partial "user_info"}} + {{/with}} + ``` + + @method partial + @for Ember.Handlebars.helpers + @param {String} partialName the name of the template to render minus the leading underscore + */ + + __exports__["default"] = function partialHelper(name, options) { + + var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; + + options.helperName = options.helperName || 'partial'; + + if (options.types[0] === "ID") { + // Helper was passed a property path; we need to + // create a binding that will re-render whenever + // this property changes. + options.fn = function(context, fnOptions) { + var partialName = handlebarsGet(context, name, fnOptions); + renderPartial(context, partialName, fnOptions); + }; + + return bind.call(context, name, options, true, exists); + } else { + // Render the partial right into parent template. + renderPartial(context, name, options); + } + } + + function exists(value) { + return !isNone(value); + } + + function renderPartial(context, name, options) { + var nameParts = name.split("/"); + var lastPart = nameParts[nameParts.length - 1]; + + nameParts[nameParts.length - 1] = "_" + lastPart; + + var view = options.data.view; + var underscoredName = nameParts.join("/"); + var template = view.templateForName(underscoredName); + var deprecatedTemplate = !template && view.templateForName(name); + + + template = template || deprecatedTemplate; + + template(context, { data: options.data }); + } + }); +define("ember-handlebars/helpers/shared", + ["ember-handlebars/ext","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var handlebarsGet = __dependency1__.handlebarsGet; + + __exports__["default"] = function resolvePaths(options) { + var ret = []; + var contexts = options.contexts; + var roots = options.roots; + var data = options.data; + + for (var i=0, l=contexts.length; i{{unbound somePropertyThatDoesntChange}} + ``` + + `unbound` can also be used in conjunction with a bound helper to + render it in its unbound form: + + ```handlebars +
    {{unbound helperName somePropertyThatDoesntChange}}
    + ``` + + @method unbound + @for Ember.Handlebars.helpers + @param {String} property + @return {String} HTML string + */ + __exports__["default"] = function unboundHelper(property, fn) { + var options = arguments[arguments.length - 1]; + var container = options.data.view.container; + var helper, context, out, ctx; + + ctx = this; + if (arguments.length > 2) { + // Unbound helper call. + options.data.isUnbound = true; + helper = resolveHelper(container, property) || helpers.helperMissing; + out = helper.apply(ctx, slice.call(arguments, 1)); + delete options.data.isUnbound; + return out; + } + + context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : ctx; + return handlebarsGet(context, property, fn); + } + }); +define("ember-handlebars/helpers/view", + ["ember-metal/core","ember-runtime/system/object","ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-views/system/jquery","ember-views/views/view","ember-metal/binding","ember-metal/keys","ember-handlebars/ext","ember-runtime/system/string","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /*globals Handlebars */ + + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // Ember.warn, Ember.assert + // var emberWarn = Ember.warn, emberAssert = Ember.assert; + + var EmberObject = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var IS_BINDING = __dependency5__.IS_BINDING; + var jQuery = __dependency6__["default"]; + var View = __dependency7__["default"]; + var isGlobalPath = __dependency8__.isGlobalPath; + var keys = __dependency9__["default"]; + var normalizePath = __dependency10__.normalizePath; + var handlebarsGet = __dependency10__.handlebarsGet; + var handlebarsGetView = __dependency10__.handlebarsGetView; + var EmberString = __dependency11__["default"]; + + + var LOWERCASE_A_Z = /^[a-z]/; + var VIEW_PREFIX = /^view\./; + + function makeBindings(thisContext, options) { + var hash = options.hash; + var hashType = options.hashTypes; + + for (var prop in hash) { + if (hashType[prop] === 'ID') { + + var value = hash[prop]; + + if (IS_BINDING.test(prop)) { + } else { + hash[prop + 'Binding'] = value; + hashType[prop + 'Binding'] = 'STRING'; + delete hash[prop]; + delete hashType[prop]; + } + } + } + + if (hash.hasOwnProperty('idBinding')) { + // id can't be bound, so just perform one-time lookup. + hash.id = handlebarsGet(thisContext, hash.idBinding, options); + hashType.id = 'STRING'; + delete hash.idBinding; + delete hashType.idBinding; + } + } + + var ViewHelper = EmberObject.create({ + propertiesFromHTMLOptions: function(options) { + var hash = options.hash; + var data = options.data; + var classes = hash['class']; + + var extensions = { + helperName: options.helperName || '' + }; + + if (hash.id) { + extensions.elementId = hash.id; + } + + if (hash.tag) { + extensions.tagName = hash.tag; + } + + if (classes) { + classes = classes.split(' '); + extensions.classNames = classes; + } + + if (hash.classBinding) { + extensions.classNameBindings = hash.classBinding.split(' '); + } + + if (hash.classNameBindings) { + if (extensions.classNameBindings === undefined) { + extensions.classNameBindings = []; + } + extensions.classNameBindings = extensions.classNameBindings.concat(hash.classNameBindings.split(' ')); + } + + if (hash.attributeBindings) { + extensions.attributeBindings = null; + } + + // Set the proper context for all bindings passed to the helper. This applies to regular attribute bindings + // as well as class name bindings. If the bindings are local, make them relative to the current context + // instead of the view. + var path; + var hashKeys = keys(hash); + + for (var i = 0, l = hashKeys.length; i < l; i++) { + var prop = hashKeys[i]; + var isBinding = IS_BINDING.test(prop); + + if (prop !== 'classNameBindings') { + extensions[prop] = hash[prop]; + } + + // Test if the property ends in "Binding" + if (isBinding && typeof extensions[prop] === 'string') { + path = this.contextualizeBindingPath(hash[prop], data); + if (path) { + extensions[prop] = path; + } + } + } + + if (extensions.classNameBindings) { + // Evaluate the context of class name bindings: + for (var j = 0, k = extensions.classNameBindings.length; j < k; j++) { + var full = extensions.classNameBindings[j]; + + if (typeof full === 'string') { + // Contextualize the path of classNameBinding so this: + // + // classNameBinding="isGreen:green" + // + // is converted to this: + // + // classNameBinding="_parentView.context.isGreen:green" + var parsedPath = View._parsePropertyPath(full); + if (parsedPath.path !== '') { + path = this.contextualizeBindingPath(parsedPath.path, data); + if (path) { + extensions.classNameBindings[j] = path + parsedPath.classNames; + } + } + } + } + } + + return extensions; + }, + + // Transform bindings from the current context to a context that can be evaluated within the view. + // Returns null if the path shouldn't be changed. + // + // TODO: consider the addition of a prefix that would allow this method to return `path`. + contextualizeBindingPath: function(path, data) { + var normalized = normalizePath(null, path, data); + if (normalized.isKeyword) { + return 'templateData.keywords.' + path; + } else if (isGlobalPath(path)) { + return null; + } else if (path === 'this' || path === '') { + return '_parentView.context'; + } else { + return '_parentView.context.' + path; + } + }, + + helper: function(thisContext, path, options) { + var data = options.data; + var fn = options.fn; + var newView; + + makeBindings(thisContext, options); + + var container = this.container || (data && data.view && data.view.container); + newView = handlebarsGetView(thisContext, path, container, options.data); + + var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); + var currentView = data.view; + viewOptions.templateData = data; + var newViewProto = newView.proto(); + + if (fn) { + viewOptions.template = fn; + } + + // We only want to override the `_context` computed property if there is + // no specified controller. See View#_context for more information. + if (!newViewProto.controller && !newViewProto.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { + viewOptions._context = thisContext; + } + + currentView.appendChild(newView, viewOptions); + }, + + instanceHelper: function(thisContext, newView, options) { + var data = options.data; + var fn = options.fn; + + makeBindings(thisContext, options); + + + var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); + var currentView = data.view; + viewOptions.templateData = data; + + if (fn) { + viewOptions.template = fn; + } + + // We only want to override the `_context` computed property if there is + // no specified controller. See View#_context for more information. + if (!newView.controller && !newView.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) { + viewOptions._context = thisContext; + } + + currentView.appendChild(newView, viewOptions); + } + }); + __exports__.ViewHelper = ViewHelper; + /** + `{{view}}` inserts a new instance of an `Ember.View` into a template passing its + options to the `Ember.View`'s `create` method and using the supplied block as + the view's own template. + + An empty `` and the following template: + + ```handlebars + A span: + {{#view tagName="span"}} + hello. + {{/view}} + ``` + + Will result in HTML structure: + + ```html + + + +
    + A span: + + Hello. + +
    + + ``` + + ### `parentView` setting + + The `parentView` property of the new `Ember.View` instance created through + `{{view}}` will be set to the `Ember.View` instance of the template where + `{{view}}` was called. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile("{{#view}} my parent: {{parentView.elementId}} {{/view}}") + }); + + aView.appendTo('body'); + ``` + + Will result in HTML structure: + + ```html +
    +
    + my parent: ember1 +
    +
    + ``` + + ### Setting CSS id and class attributes + + The HTML `id` attribute can be set on the `{{view}}`'s resulting element with + the `id` option. This option will _not_ be passed to `Ember.View.create`. + + ```handlebars + {{#view tagName="span" id="a-custom-id"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + The HTML `class` attribute can be set on the `{{view}}`'s resulting element + with the `class` or `classNameBindings` options. The `class` option will + directly set the CSS `class` attribute and will not be passed to + `Ember.View.create`. `classNameBindings` will be passed to `create` and use + `Ember.View`'s class name binding functionality: + + ```handlebars + {{#view tagName="span" class="a-custom-class"}} + hello. + {{/view}} + ``` + + Results in the following HTML structure: + + ```html +
    + + hello. + +
    + ``` + + ### Supplying a different view class + + `{{view}}` can take an optional first argument before its supplied options to + specify a path to a custom view class. + + ```handlebars + {{#view "custom"}}{{! will look up App.CustomView }} + hello. + {{/view}} + ``` + + The first argument can also be a relative path accessible from the current + context. + + ```javascript + MyApp = Ember.Application.create({}); + MyApp.OuterView = Ember.View.extend({ + innerViewClass: Ember.View.extend({ + classNames: ['a-custom-view-class-as-property'] + }), + template: Ember.Handlebars.compile('{{#view view.innerViewClass}} hi {{/view}}') + }); + + MyApp.OuterView.create().appendTo('body'); + ``` + + Will result in the following HTML: + + ```html +
    +
    + hi +
    +
    + ``` + + ### Blockless use + + If you supply a custom `Ember.View` subclass that specifies its own template + or provide a `templateName` option to `{{view}}` it can be used without + supplying a block. Attempts to use both a `templateName` option and supply a + block will throw an error. + + ```javascript + var App = Ember.Application.create(); + App.WithTemplateDefinedView = Ember.View.extend({ + templateName: 'defined-template' + }); + ``` + + ```handlebars + {{! application.hbs }} + {{view 'with-template-defined'}} + ``` + + ```handlebars + {{! defined-template.hbs }} + Some content for the defined template view. + ``` + + ### `viewName` property + + You can supply a `viewName` option to `{{view}}`. The `Ember.View` instance + will be referenced as a property of its parent view by this name. + + ```javascript + aView = Ember.View.create({ + template: Ember.Handlebars.compile('{{#view viewName="aChildByName"}} hi {{/view}}') + }); + + aView.appendTo('body'); + aView.get('aChildByName') // the instance of Ember.View created by {{view}} helper + ``` + + @method view + @for Ember.Handlebars.helpers + @param {String} path + @param {Hash} options + @return {String} HTML string + */ + function viewHelper(path, options) { + + // If no path is provided, treat path param as options + // and get an instance of the registered `view:toplevel` + if (path && path.data && path.data.isRenderData) { + options = path; + if (options.data && options.data.view && options.data.view.container) { + path = options.data.view.container.lookupFactory('view:toplevel'); + } else { + path = View; + } + } + + options.helperName = options.helperName || 'view'; + + return ViewHelper.helper(this, path, options); + } + + __exports__.viewHelper = viewHelper; + }); +define("ember-handlebars/helpers/yield", + ["ember-metal/core","ember-metal/property_get","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-handlebars + */ + + var Ember = __dependency1__["default"]; + // var emberAssert = Ember.assert; + + var get = __dependency2__.get; + + /** + `{{yield}}` denotes an area of a template that will be rendered inside + of another template. It has two main uses: + + ### Use with `layout` + When used in a Handlebars template that is assigned to an `Ember.View` + instance's `layout` property Ember will render the layout template first, + inserting the view's own rendered output at the `{{yield}}` location. + + An empty `` and the following application code: + + ```javascript + AView = Ember.View.extend({ + classNames: ['a-view-with-layout'], + layout: Ember.Handlebars.compile('
    {{yield}}
    '), + template: Ember.Handlebars.compile('I am wrapped') + }); + + aView = AView.create(); + aView.appendTo('body'); + ``` + + Will result in the following HTML output: + + ```html + +
    +
    + I am wrapped +
    +
    + + ``` + + The `yield` helper cannot be used outside of a template assigned to an + `Ember.View`'s `layout` property and will throw an error if attempted. + + ```javascript + BView = Ember.View.extend({ + classNames: ['a-view-with-layout'], + template: Ember.Handlebars.compile('{{yield}}') + }); + + bView = BView.create(); + bView.appendTo('body'); + + // throws + // Uncaught Error: assertion failed: + // You called yield in a template that was not a layout + ``` + + ### Use with Ember.Component + When designing components `{{yield}}` is used to denote where, inside the component's + template, an optional block passed to the component should render: + + ```handlebars + + {{#labeled-textfield value=someProperty}} + First name: + {{/labeled-textfield}} + ``` + + ```handlebars + + + ``` + + Result: + + ```html + + ``` + + @method yield + @for Ember.Handlebars.helpers + @param {Hash} options + @return {String} HTML string + */ + __exports__["default"] = function yieldHelper(options) { + var view = options.data.view; + + while (view && !get(view, 'layout')) { + if (view._contextView) { + view = view._contextView; + } else { + view = get(view, '_parentView'); + } + } + + + view._yield(this, options); + } + }); +define("ember-handlebars/loader", + ["ember-handlebars/component_lookup","ember-views/system/jquery","ember-metal/error","ember-runtime/system/lazy_load","ember-handlebars-compiler","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /*globals Handlebars */ + + var ComponentLookup = __dependency1__["default"]; + var jQuery = __dependency2__["default"]; + var EmberError = __dependency3__["default"]; + var onLoad = __dependency4__.onLoad; + + var EmberHandlebars = __dependency5__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + /** + Find templates stored in the head tag as script tags and make them available + to `Ember.CoreView` in the global `Ember.TEMPLATES` object. This will be run + as as jQuery DOM-ready callback. + + Script tags with `text/x-handlebars` will be compiled + with Ember's Handlebars and are suitable for use as a view's template. + Those with type `text/x-raw-handlebars` will be compiled with regular + Handlebars and are suitable for use in views' computed properties. + + @private + @method bootstrap + @for Ember.Handlebars + @static + @param ctx + */ + function bootstrap(ctx) { + var selectors = 'script[type="text/x-handlebars"], script[type="text/x-raw-handlebars"]'; + + jQuery(selectors, ctx) + .each(function() { + // Get a reference to the script tag + var script = jQuery(this); + + var compile = (script.attr('type') === 'text/x-raw-handlebars') ? + jQuery.proxy(Handlebars.compile, Handlebars) : + jQuery.proxy(EmberHandlebars.compile, EmberHandlebars); + // Get the name of the script, used by Ember.View's templateName property. + // First look for data-template-name attribute, then fall back to its + // id if no name is found. + var templateName = script.attr('data-template-name') || script.attr('id') || 'application'; + var template = compile(script.html()); + + // Check if template of same name already exists + if (Ember.TEMPLATES[templateName] !== undefined) { + throw new EmberError('Template named "' + templateName + '" already exists.'); + } + + // For templates which have a name, we save them and then remove them from the DOM + Ember.TEMPLATES[templateName] = template; + + // Remove script tag from DOM + script.remove(); + }); + } + + function _bootstrap() { + bootstrap( jQuery(document) ); + } + + function registerComponentLookup(container) { + container.register('component-lookup:main', ComponentLookup); + } + + /* + We tie this to application.load to ensure that we've at least + attempted to bootstrap at the point that the application is loaded. + + We also tie this to document ready since we're guaranteed that all + the inline templates are present at this point. + + There's no harm to running this twice, since we remove the templates + from the DOM after processing. + */ + + onLoad('Ember.Application', function(Application) { + Application.initializer({ + name: 'domTemplates', + initialize: _bootstrap + }); + + Application.initializer({ + name: 'registerComponentLookup', + after: 'domTemplates', + initialize: registerComponentLookup + }); + }); + + __exports__["default"] = bootstrap; + }); +define("ember-handlebars/string", + ["ember-runtime/system/string","exports"], + function(__dependency1__, __exports__) { + "use strict"; + // required so we can extend this object. + var EmberStringUtils = __dependency1__["default"]; + + /** + Mark a string as safe for unescaped output with Handlebars. If you + return HTML from a Handlebars helper, use this function to + ensure Handlebars does not escape the HTML. + + ```javascript + Ember.String.htmlSafe('
    someString
    ') + ``` + + @method htmlSafe + @for Ember.String + @static + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars + */ + function htmlSafe(str) { + return new Handlebars.SafeString(str); + } + + EmberStringUtils.htmlSafe = htmlSafe; + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { + + /** + Mark a string as being safe for unescaped output with Handlebars. + + ```javascript + '
    someString
    '.htmlSafe() + ``` + + See [Ember.String.htmlSafe](/api/classes/Ember.String.html#method_htmlSafe). + + @method htmlSafe + @for String + @return {Handlebars.SafeString} a string that will not be html escaped by Handlebars + */ + String.prototype.htmlSafe = function() { + return htmlSafe(this); + }; + } + + __exports__["default"] = htmlSafe; + }); +define("ember-handlebars/views/handlebars_bound_view", + ["ember-handlebars-compiler","ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-views/views/view","ember-views/views/states","ember-handlebars/views/metamorph_view","ember-handlebars/ext","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /*globals Handlebars, Metamorph:true */ + /*jshint newcap:false*/ + + + /** + @module ember + @submodule ember-handlebars + */ + + var EmberHandlebars = __dependency1__["default"]; + // EmberHandlebars.SafeString; + var SafeString = EmberHandlebars.SafeString; + + var Ember = __dependency2__["default"]; + // Ember.K + var K = Ember.K; + + var EmberError = __dependency3__["default"]; + var get = __dependency4__.get; + var set = __dependency5__.set; + var merge = __dependency6__["default"]; + var run = __dependency7__["default"]; + var computed = __dependency8__.computed; + var View = __dependency9__["default"]; + var cloneStates = __dependency10__.cloneStates; + var states = __dependency10__.states; + var viewStates = states; + + var _MetamorphView = __dependency11__["default"]; + var handlebarsGet = __dependency12__.handlebarsGet; + var uuid = __dependency13__.uuid; + + function SimpleHandlebarsView(path, pathRoot, isEscaped, templateData) { + this.path = path; + this.pathRoot = pathRoot; + this.isEscaped = isEscaped; + this.templateData = templateData; + this[Ember.GUID_KEY] = uuid(); + this._lastNormalizedValue = undefined; + this.state = 'preRender'; + this.updateId = null; + this._parentView = null; + this.buffer = null; + this._morph = null; + } + + SimpleHandlebarsView.prototype = { + isVirtual: true, + isView: true, + + destroy: function () { + if (this.updateId) { + run.cancel(this.updateId); + this.updateId = null; + } + if (this._parentView) { + this._parentView.removeChild(this); + } + this.morph = null; + this.state = 'destroyed'; + }, + + propertyWillChange: K, + + propertyDidChange: K, + + normalizedValue: function() { + var path = this.path; + var pathRoot = this.pathRoot; + var escape = this.isEscaped; + var result, templateData; + + // Use the pathRoot as the result if no path is provided. This + // happens if the path is `this`, which gets normalized into + // a `pathRoot` of the current Handlebars context and a path + // of `''`. + if (path === '') { + result = pathRoot; + } else { + templateData = this.templateData; + result = handlebarsGet(pathRoot, path, { data: templateData }); + } + + if (result === null || result === undefined) { + result = ""; + } else if (!escape && !(result instanceof SafeString)) { + result = new SafeString(result); + } + + return result; + }, + + render: function(buffer) { + var value = this.normalizedValue(); + this._lastNormalizedValue = value; + buffer._element = value; + }, + + rerender: function() { + switch(this.state) { + case 'preRender': + case 'destroyed': + break; + case 'inBuffer': + throw new EmberError("Something you did tried to replace an {{expression}} before it was inserted into the DOM."); + case 'hasElement': + case 'inDOM': + this.updateId = run.scheduleOnce('render', this, 'update'); + break; + } + return this; + }, + + update: function () { + this.updateId = null; + var value = this.normalizedValue(); + // doesn't diff SafeString instances + if (value !== this._lastNormalizedValue) { + this._lastNormalizedValue = value; + this._morph.update(value); + } + }, + + _transitionTo: function(state) { + this.state = state; + } + }; + + states = cloneStates(viewStates); + + merge(states._default, { + rerenderIfNeeded: K + }); + + merge(states.inDOM, { + rerenderIfNeeded: function(view) { + if (view.normalizedValue() !== view._lastNormalizedValue) { + view.rerender(); + } + } + }); + + /** + `Ember._HandlebarsBoundView` is a private view created by the Handlebars + `{{bind}}` helpers that is used to keep track of bound properties. + + Every time a property is bound using a `{{mustache}}`, an anonymous subclass + of `Ember._HandlebarsBoundView` is created with the appropriate sub-template + and context set up. When the associated property changes, just the template + for this view will re-render. + + @class _HandlebarsBoundView + @namespace Ember + @extends Ember._MetamorphView + @private + */ + var _HandlebarsBoundView = _MetamorphView.extend({ + instrumentName: 'boundHandlebars', + + _states: states, + + /** + The function used to determine if the `displayTemplate` or + `inverseTemplate` should be rendered. This should be a function that takes + a value and returns a Boolean. + + @property shouldDisplayFunc + @type Function + @default null + */ + shouldDisplayFunc: null, + + /** + Whether the template rendered by this view gets passed the context object + of its parent template, or gets passed the value of retrieving `path` + from the `pathRoot`. + + For example, this is true when using the `{{#if}}` helper, because the + template inside the helper should look up properties relative to the same + object as outside the block. This would be `false` when used with `{{#with + foo}}` because the template should receive the object found by evaluating + `foo`. + + @property preserveContext + @type Boolean + @default false + */ + preserveContext: false, + + /** + If `preserveContext` is true, this is the object that will be used + to render the template. + + @property previousContext + @type Object + */ + previousContext: null, + + /** + The template to render when `shouldDisplayFunc` evaluates to `true`. + + @property displayTemplate + @type Function + @default null + */ + displayTemplate: null, + + /** + The template to render when `shouldDisplayFunc` evaluates to `false`. + + @property inverseTemplate + @type Function + @default null + */ + inverseTemplate: null, + + + /** + The path to look up on `pathRoot` that is passed to + `shouldDisplayFunc` to determine which template to render. + + In addition, if `preserveContext` is `false,` the object at this path will + be passed to the template when rendering. + + @property path + @type String + @default null + */ + path: null, + + /** + The object from which the `path` will be looked up. Sometimes this is the + same as the `previousContext`, but in cases where this view has been + generated for paths that start with a keyword such as `view` or + `controller`, the path root will be that resolved object. + + @property pathRoot + @type Object + */ + pathRoot: null, + + normalizedValue: function() { + var path = get(this, 'path'); + var pathRoot = get(this, 'pathRoot'); + var valueNormalizer = get(this, 'valueNormalizerFunc'); + var result, templateData; + + // Use the pathRoot as the result if no path is provided. This + // happens if the path is `this`, which gets normalized into + // a `pathRoot` of the current Handlebars context and a path + // of `''`. + if (path === '') { + result = pathRoot; + } else { + templateData = get(this, 'templateData'); + result = handlebarsGet(pathRoot, path, { data: templateData }); + } + + return valueNormalizer ? valueNormalizer(result) : result; + }, + + rerenderIfNeeded: function() { + this.currentState.rerenderIfNeeded(this); + }, + + /** + Determines which template to invoke, sets up the correct state based on + that logic, then invokes the default `Ember.View` `render` implementation. + + This method will first look up the `path` key on `pathRoot`, + then pass that value to the `shouldDisplayFunc` function. If that returns + `true,` the `displayTemplate` function will be rendered to DOM. Otherwise, + `inverseTemplate`, if specified, will be rendered. + + For example, if this `Ember._HandlebarsBoundView` represented the `{{#with + foo}}` helper, it would look up the `foo` property of its context, and + `shouldDisplayFunc` would always return true. The object found by looking + up `foo` would be passed to `displayTemplate`. + + @method render + @param {Ember.RenderBuffer} buffer + */ + render: function(buffer) { + // If not invoked via a triple-mustache ({{{foo}}}), escape + // the content of the template. + var escape = get(this, 'isEscaped'); + + var shouldDisplay = get(this, 'shouldDisplayFunc'); + var preserveContext = get(this, 'preserveContext'); + var context = get(this, 'previousContext'); + + var inverseTemplate = get(this, 'inverseTemplate'); + var displayTemplate = get(this, 'displayTemplate'); + + var result = this.normalizedValue(); + + this._lastNormalizedValue = result; + + // First, test the conditional to see if we should + // render the template or not. + if (shouldDisplay(result)) { + set(this, 'template', displayTemplate); + + // If we are preserving the context (for example, if this + // is an #if block, call the template with the same object. + if (preserveContext) { + set(this, '_context', context); + } else { + // Otherwise, determine if this is a block bind or not. + // If so, pass the specified object to the template + if (displayTemplate) { + set(this, '_context', result); + } else { + // This is not a bind block, just push the result of the + // expression to the render context and return. + if (result === null || result === undefined) { + result = ""; + } else if (!(result instanceof SafeString)) { + result = String(result); + } + + if (escape) { result = Handlebars.Utils.escapeExpression(result); } + buffer.push(result); + return; + } + } + } else if (inverseTemplate) { + set(this, 'template', inverseTemplate); + + if (preserveContext) { + set(this, '_context', context); + } else { + set(this, '_context', result); + } + } else { + set(this, 'template', function() { return ''; }); + } + + return this._super(buffer); + } + }); + + __exports__._HandlebarsBoundView = _HandlebarsBoundView; + __exports__.SimpleHandlebarsView = SimpleHandlebarsView; + }); +define("ember-handlebars/views/metamorph_view", + ["ember-metal/core","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /* global Metamorph:true */ + + /*jshint newcap:false*/ + var Ember = __dependency1__["default"]; + // Ember.deprecate + + var CoreView = __dependency2__["default"]; + var View = __dependency3__["default"]; + var Mixin = __dependency4__.Mixin; + var run = __dependency5__["default"]; + + /** + @module ember + @submodule ember-handlebars + */ + + function notifyMutationListeners() { + run.once(View, 'notifyMutationListeners'); + } + + // The `morph` and `outerHTML` properties are internal only + // and not observable. + + /** + @class _Metamorph + @namespace Ember + @private + */ + var _Metamorph = Mixin.create({ + isVirtual: true, + tagName: '', + + instrumentName: 'metamorph', + + init: function() { + this._super(); + } + }); + __exports__._Metamorph = _Metamorph; + /** + @class _MetamorphView + @namespace Ember + @extends Ember.View + @uses Ember._Metamorph + @private + */ + var _MetamorphView = View.extend(_Metamorph); + __exports__._MetamorphView = _MetamorphView; + /** + @class _SimpleMetamorphView + @namespace Ember + @extends Ember.CoreView + @uses Ember._Metamorph + @private + */ + var _SimpleMetamorphView = CoreView.extend(_Metamorph); + __exports__._SimpleMetamorphView = _SimpleMetamorphView;__exports__["default"] = View.extend(_Metamorph); + }); +define("ember-metal-views", + ["ember-metal-views/renderer","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Renderer = __dependency1__["default"]; + __exports__.Renderer = Renderer; + }); +define("ember-metal-views/renderer", + ["morph","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var DOMHelper = __dependency1__.DOMHelper; + + function Renderer() { + this._uuid = 0; + this._views = new Array(2000); + this._queue = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + this._parents = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; + this._elements = new Array(17); + this._inserts = {}; + this._dom = new DOMHelper(); + } + + function Renderer_renderTree(_view, _parentView, _insertAt) { + var views = this._views; + views[0] = _view; + var insertAt = _insertAt === undefined ? -1 : _insertAt; + var index = 0; + var total = 1; + var levelBase = _parentView ? _parentView._level+1 : 0; + + var root = _parentView == null ? _view : _parentView._root; + + // if root view has a _morph assigned + var willInsert = !!root._morph; + + var queue = this._queue; + queue[0] = 0; + var length = 1; + + var parentIndex = -1; + var parents = this._parents; + var parent = _parentView || null; + var elements = this._elements; + var element = null; + var contextualElement = null; + var level = 0; + + var view = _view; + var children, i, l, child; + while (length) { + elements[level] = element; + if (!view._morph) { + // ensure props we add are in same order + view._morph = null; + } + view._root = root; + this.uuid(view); + view._level = levelBase + level; + if (view._elementCreated) { + this.remove(view, false, true); + } + + this.willCreateElement(view); + + contextualElement = view._morph && view._morph.contextualElement; + if (!contextualElement && parent && parent._childViewsMorph) { + contextualElement = parent._childViewsMorph.contextualElement; + } + if (!contextualElement && view._didCreateElementWithoutMorph) { + // This code path is only used by createElement and rerender when createElement + // was previously called on a view. + contextualElement = document.body; + } + element = this.createElement(view, contextualElement); + + parents[level++] = parentIndex; + parentIndex = index; + parent = view; + + // enqueue for end + queue[length++] = index; + // enqueue children + children = this.childViews(view); + if (children) { + for (i=children.length-1;i>=0;i--) { + child = children[i]; + index = total++; + views[index] = child; + queue[length++] = index; + view = child; + } + } + + index = queue[--length]; + view = views[index]; + + while (parentIndex === index) { + level--; + view._elementCreated = true; + this.didCreateElement(view); + if (willInsert) { + this.willInsertElement(view); + } + + if (level === 0) { + length--; + break; + } + + parentIndex = parents[level]; + parent = parentIndex === -1 ? _parentView : views[parentIndex]; + this.insertElement(view, parent, element, -1); + index = queue[--length]; + view = views[index]; + element = elements[level]; + elements[level] = null; + } + } + + this.insertElement(view, _parentView, element, insertAt); + + for (i=total-1;i>=0;i--) { + if (willInsert) { + views[i]._elementInserted = true; + this.didInsertElement(views[i]); + } + views[i] = null; + } + + return element; + } + + Renderer.prototype.uuid = function Renderer_uuid(view) { + if (view._uuid === undefined) { + view._uuid = ++this._uuid; + view._renderer = this; + } // else assert(view._renderer === this) + return view._uuid; + }; + + Renderer.prototype.scheduleInsert = + function Renderer_scheduleInsert(view, morph) { + if (view._morph || view._elementCreated) { + throw new Error("You cannot insert a View that has already been rendered"); + } + view._morph = morph; + var viewId = this.uuid(view); + this._inserts[viewId] = this.scheduleRender(this, function() { + this._inserts[viewId] = null; + this.renderTree(view); + }); + }; + + Renderer.prototype.appendTo = + function Renderer_appendTo(view, target) { + var morph = this._dom.appendMorph(target); + this.scheduleInsert(view, morph); + }; + + Renderer.prototype.replaceIn = + function Renderer_replaceIn(view, target) { + var morph = this._dom.createMorph(target, null, null); + this.scheduleInsert(view, morph); + }; + + function Renderer_remove(_view, shouldDestroy, reset) { + var viewId = this.uuid(_view); + + if (this._inserts[viewId]) { + this.cancelRender(this._inserts[viewId]); + this._inserts[viewId] = undefined; + } + + if (!_view._elementCreated) { + return; + } + + var removeQueue = []; + var destroyQueue = []; + var morph = _view._morph; + var idx, len, view, staticChildren, queue, + childViews, i, l, parentView; + + removeQueue.push(_view); + + for (idx=0; idx -1; + }; + + var defineNativeShim = function(nativeFunc, shim) { + if (isNativeFunc(nativeFunc)) { + return nativeFunc; + } + return shim; + }; + + // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/map + var map = defineNativeShim(ArrayPrototype.map, function(fun /*, thisp */) { + //"use strict"; + + if (this === void 0 || this === null || typeof fun !== "function") { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + var res = new Array(len); + var thisp = arguments[1]; + + for (var i = 0; i < len; i++) { + if (i in t) { + res[i] = fun.call(thisp, t[i], i, t); + } + } + + return res; + }); + + // From: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/foreach + var forEach = defineNativeShim(ArrayPrototype.forEach, function(fun /*, thisp */) { + //"use strict"; + + if (this === void 0 || this === null || typeof fun !== "function") { + throw new TypeError(); + } + + var t = Object(this); + var len = t.length >>> 0; + var thisp = arguments[1]; + + for (var i = 0; i < len; i++) { + if (i in t) { + fun.call(thisp, t[i], i, t); + } + } + }); + + var indexOf = defineNativeShim(ArrayPrototype.indexOf, function (obj, fromIndex) { + if (fromIndex === null || fromIndex === undefined) { + fromIndex = 0; + } + else if (fromIndex < 0) { + fromIndex = Math.max(0, this.length + fromIndex); + } + + for (var i = fromIndex, j = this.length; i < j; i++) { + if (this[i] === obj) { + return i; + } + } + return -1; + }); + + var lastIndexOf = defineNativeShim(ArrayPrototype.lastIndexOf, function(obj, fromIndex) { + var len = this.length; + var idx; + + if (fromIndex === undefined) fromIndex = len-1; + else fromIndex = (fromIndex < 0) ? Math.ceil(fromIndex) : Math.floor(fromIndex); + if (fromIndex < 0) fromIndex += len; + + for(idx = fromIndex;idx>=0;idx--) { + if (this[idx] === obj) return idx ; + } + return -1; + }); + + var filter = defineNativeShim(ArrayPrototype.filter, function (fn, context) { + var i, value; + var result = []; + var length = this.length; + + for (i = 0; i < length; i++) { + if (this.hasOwnProperty(i)) { + value = this[i]; + if (fn.call(context, value, i, this)) { + result.push(value); + } + } + } + return result; + }); + + if (Ember.SHIM_ES5) { + ArrayPrototype.map = ArrayPrototype.map || map; + ArrayPrototype.forEach = ArrayPrototype.forEach || forEach; + ArrayPrototype.filter = ArrayPrototype.filter || filter; + ArrayPrototype.indexOf = ArrayPrototype.indexOf || indexOf; + ArrayPrototype.lastIndexOf = ArrayPrototype.lastIndexOf || lastIndexOf; + } + + /** + Array polyfills to support ES5 features in older browsers. + + @namespace Ember + @property ArrayPolyfills + */ + __exports__.map = map; + __exports__.forEach = forEach; + __exports__.filter = filter; + __exports__.indexOf = indexOf; + __exports__.lastIndexOf = lastIndexOf; + }); +define("ember-metal/binding", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/map","ember-metal/observer","ember-metal/run_loop","ember-metal/path_cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.Logger, Ember.LOG_BINDINGS, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var trySet = __dependency3__.trySet; + var guidFor = __dependency4__.guidFor; + var Map = __dependency5__["default"]; + var addObserver = __dependency6__.addObserver; + var removeObserver = __dependency6__.removeObserver; + var _suspendObserver = __dependency6__._suspendObserver; + var run = __dependency7__["default"]; + var isGlobalPath = __dependency8__.isGlobal; + + + // ES6TODO: where is Ember.lookup defined? + /** + @module ember-metal + */ + + // .......................................................... + // CONSTANTS + // + + /** + Debug parameter you can turn on. This will log all bindings that fire to + the console. This should be disabled in production code. Note that you + can also enable this from the console or temporarily. + + @property LOG_BINDINGS + @for Ember + @type Boolean + @default false + */ + Ember.LOG_BINDINGS = false || !!Ember.ENV.LOG_BINDINGS; + + /** + Returns true if the provided path is global (e.g., `MyApp.fooController.bar`) + instead of local (`foo.bar.baz`). + + @method isGlobalPath + @for Ember + @private + @param {String} path + @return Boolean + */ + + function getWithGlobals(obj, path) { + return get(isGlobalPath(path) ? Ember.lookup : obj, path); + } + + // .......................................................... + // BINDING + // + + function Binding(toPath, fromPath) { + this._direction = 'fwd'; + this._from = fromPath; + this._to = toPath; + this._directionMap = new Map(); + this._readyToSync = undefined; + this._oneWay = undefined; + } + + /** + @class Binding + @namespace Ember + */ + + Binding.prototype = { + /** + This copies the Binding so it can be connected to another object. + + @method copy + @return {Ember.Binding} `this` + */ + copy: function () { + var copy = new Binding(this._to, this._from); + if (this._oneWay) { copy._oneWay = true; } + return copy; + }, + + // .......................................................... + // CONFIG + // + + /** + This will set `from` property path to the specified value. It will not + attempt to resolve this property path to an actual object until you + connect the binding. + + The binding will search for the property path starting at the root object + you pass when you `connect()` the binding. It follows the same rules as + `get()` - see that method for more information. + + @method from + @param {String} path the property path to connect to + @return {Ember.Binding} `this` + */ + from: function(path) { + this._from = path; + return this; + }, + + /** + This will set the `to` property path to the specified value. It will not + attempt to resolve this property path to an actual object until you + connect the binding. + + The binding will search for the property path starting at the root object + you pass when you `connect()` the binding. It follows the same rules as + `get()` - see that method for more information. + + @method to + @param {String|Tuple} path A property path or tuple + @return {Ember.Binding} `this` + */ + to: function(path) { + this._to = path; + return this; + }, + + /** + Configures the binding as one way. A one-way binding will relay changes + on the `from` side to the `to` side, but not the other way around. This + means that if you change the `to` side directly, the `from` side may have + a different value. + + @method oneWay + @return {Ember.Binding} `this` + */ + oneWay: function() { + this._oneWay = true; + return this; + }, + + /** + @method toString + @return {String} string representation of binding + */ + toString: function() { + var oneWay = this._oneWay ? '[oneWay]' : ''; + return "Ember.Binding<" + guidFor(this) + ">(" + this._from + " -> " + this._to + ")" + oneWay; + }, + + // .......................................................... + // CONNECT AND SYNC + // + + /** + Attempts to connect this binding instance so that it can receive and relay + changes. This method will raise an exception if you have not set the + from/to properties yet. + + @method connect + @param {Object} obj The root object for this binding. + @return {Ember.Binding} `this` + */ + connect: function(obj) { + + var fromPath = this._from; + var toPath = this._to; + trySet(obj, toPath, getWithGlobals(obj, fromPath)); + + // add an observer on the object to be notified when the binding should be updated + addObserver(obj, fromPath, this, this.fromDidChange); + + // if the binding is a two-way binding, also set up an observer on the target + if (!this._oneWay) { addObserver(obj, toPath, this, this.toDidChange); } + + this._readyToSync = true; + + return this; + }, + + /** + Disconnects the binding instance. Changes will no longer be relayed. You + will not usually need to call this method. + + @method disconnect + @param {Object} obj The root object you passed when connecting the binding. + @return {Ember.Binding} `this` + */ + disconnect: function(obj) { + + var twoWay = !this._oneWay; + + // remove an observer on the object so we're no longer notified of + // changes that should update bindings. + removeObserver(obj, this._from, this, this.fromDidChange); + + // if the binding is two-way, remove the observer from the target as well + if (twoWay) { removeObserver(obj, this._to, this, this.toDidChange); } + + this._readyToSync = false; // disable scheduled syncs... + return this; + }, + + // .......................................................... + // PRIVATE + // + + /* called when the from side changes */ + fromDidChange: function(target) { + this._scheduleSync(target, 'fwd'); + }, + + /* called when the to side changes */ + toDidChange: function(target) { + this._scheduleSync(target, 'back'); + }, + + _scheduleSync: function(obj, dir) { + var directionMap = this._directionMap; + var existingDir = directionMap.get(obj); + + // if we haven't scheduled the binding yet, schedule it + if (!existingDir) { + run.schedule('sync', this, this._sync, obj); + directionMap.set(obj, dir); + } + + // If both a 'back' and 'fwd' sync have been scheduled on the same object, + // default to a 'fwd' sync so that it remains deterministic. + if (existingDir === 'back' && dir === 'fwd') { + directionMap.set(obj, 'fwd'); + } + }, + + _sync: function(obj) { + var log = Ember.LOG_BINDINGS; + + // don't synchronize destroyed objects or disconnected bindings + if (obj.isDestroyed || !this._readyToSync) { return; } + + // get the direction of the binding for the object we are + // synchronizing from + var directionMap = this._directionMap; + var direction = directionMap.get(obj); + + var fromPath = this._from; + var toPath = this._to; + + directionMap["delete"](obj); + + // if we're synchronizing from the remote object... + if (direction === 'fwd') { + var fromValue = getWithGlobals(obj, this._from); + if (log) { + Ember.Logger.log(' ', this.toString(), '->', fromValue, obj); + } + if (this._oneWay) { + trySet(obj, toPath, fromValue); + } else { + _suspendObserver(obj, toPath, this, this.toDidChange, function () { + trySet(obj, toPath, fromValue); + }); + } + // if we're synchronizing *to* the remote object + } else if (direction === 'back') { + var toValue = get(obj, this._to); + if (log) { + Ember.Logger.log(' ', this.toString(), '<-', toValue, obj); + } + _suspendObserver(obj, fromPath, this, this.fromDidChange, function () { + trySet(isGlobalPath(fromPath) ? Ember.lookup : obj, fromPath, toValue); + }); + } + } + + }; + + function mixinProperties(to, from) { + for (var key in from) { + if (from.hasOwnProperty(key)) { + to[key] = from[key]; + } + } + } + + mixinProperties(Binding, { + + /* + See `Ember.Binding.from`. + + @method from + @static + */ + from: function() { + var C = this; + var binding = new C(); + return binding.from.apply(binding, arguments); + }, + + /* + See `Ember.Binding.to`. + + @method to + @static + */ + to: function() { + var C = this; + var binding = new C(); + return binding.to.apply(binding, arguments); + }, + + /** + Creates a new Binding instance and makes it apply in a single direction. + A one-way binding will relay changes on the `from` side object (supplied + as the `from` argument) the `to` side, but not the other way around. + This means that if you change the "to" side directly, the "from" side may have + a different value. + + See `Binding.oneWay`. + + @method oneWay + @param {String} from from path. + @param {Boolean} [flag] (Optional) passing nothing here will make the + binding `oneWay`. You can instead pass `false` to disable `oneWay`, making the + binding two way again. + @return {Ember.Binding} `this` + */ + oneWay: function(from, flag) { + var C = this; + var binding = new C(null, from); + return binding.oneWay(flag); + } + + }); + /** + An `Ember.Binding` connects the properties of two objects so that whenever + the value of one property changes, the other property will be changed also. + + ## Automatic Creation of Bindings with `/^*Binding/`-named Properties + + You do not usually create Binding objects directly but instead describe + bindings in your class or object definition using automatic binding + detection. + + Properties ending in a `Binding` suffix will be converted to `Ember.Binding` + instances. The value of this property should be a string representing a path + to another object or a custom binding instance created using Binding helpers + (see "One Way Bindings"): + + ``` + valueBinding: "MyApp.someController.title" + ``` + + This will create a binding from `MyApp.someController.title` to the `value` + property of your object instance automatically. Now the two values will be + kept in sync. + + ## One Way Bindings + + One especially useful binding customization you can use is the `oneWay()` + helper. This helper tells Ember that you are only interested in + receiving changes on the object you are binding from. For example, if you + are binding to a preference and you want to be notified if the preference + has changed, but your object will not be changing the preference itself, you + could do: + + ``` + bigTitlesBinding: Ember.Binding.oneWay("MyApp.preferencesController.bigTitles") + ``` + + This way if the value of `MyApp.preferencesController.bigTitles` changes the + `bigTitles` property of your object will change also. However, if you + change the value of your `bigTitles` property, it will not update the + `preferencesController`. + + One way bindings are almost twice as fast to setup and twice as fast to + execute because the binding only has to worry about changes to one side. + + You should consider using one way bindings anytime you have an object that + may be created frequently and you do not intend to change a property; only + to monitor it for changes (such as in the example above). + + ## Adding Bindings Manually + + All of the examples above show you how to configure a custom binding, but the + result of these customizations will be a binding template, not a fully active + Binding instance. The binding will actually become active only when you + instantiate the object the binding belongs to. It is useful however, to + understand what actually happens when the binding is activated. + + For a binding to function it must have at least a `from` property and a `to` + property. The `from` property path points to the object/key that you want to + bind from while the `to` path points to the object/key you want to bind to. + + When you define a custom binding, you are usually describing the property + you want to bind from (such as `MyApp.someController.value` in the examples + above). When your object is created, it will automatically assign the value + you want to bind `to` based on the name of your binding key. In the + examples above, during init, Ember objects will effectively call + something like this on your binding: + + ```javascript + binding = Ember.Binding.from("valueBinding").to("value"); + ``` + + This creates a new binding instance based on the template you provide, and + sets the to path to the `value` property of the new object. Now that the + binding is fully configured with a `from` and a `to`, it simply needs to be + connected to become active. This is done through the `connect()` method: + + ```javascript + binding.connect(this); + ``` + + Note that when you connect a binding you pass the object you want it to be + connected to. This object will be used as the root for both the from and + to side of the binding when inspecting relative paths. This allows the + binding to be automatically inherited by subclassed objects as well. + + This also allows you to bind between objects using the paths you declare in + `from` and `to`: + + ```javascript + // Example 1 + binding = Ember.Binding.from("App.someObject.value").to("value"); + binding.connect(this); + + // Example 2 + binding = Ember.Binding.from("parentView.value").to("App.someObject.value"); + binding.connect(this); + ``` + + Now that the binding is connected, it will observe both the from and to side + and relay changes. + + If you ever needed to do so (you almost never will, but it is useful to + understand this anyway), you could manually create an active binding by + using the `Ember.bind()` helper method. (This is the same method used by + to setup your bindings on objects): + + ```javascript + Ember.bind(MyApp.anotherObject, "value", "MyApp.someController.value"); + ``` + + Both of these code fragments have the same effect as doing the most friendly + form of binding creation like so: + + ```javascript + MyApp.anotherObject = Ember.Object.create({ + valueBinding: "MyApp.someController.value", + + // OTHER CODE FOR THIS OBJECT... + }); + ``` + + Ember's built in binding creation method makes it easy to automatically + create bindings for you. You should always use the highest-level APIs + available, even if you understand how it works underneath. + + @class Binding + @namespace Ember + @since Ember 0.9 + */ + // Ember.Binding = Binding; ES6TODO: where to put this? + + + /** + Global helper method to create a new binding. Just pass the root object + along with a `to` and `from` path to create and connect the binding. + + @method bind + @for Ember + @param {Object} obj The root object of the transform. + @param {String} to The path to the 'to' side of the binding. + Must be relative to obj. + @param {String} from The path to the 'from' side of the binding. + Must be relative to obj or a global path. + @return {Ember.Binding} binding instance + */ + function bind(obj, to, from) { + return new Binding(to, from).connect(obj); + } + + __exports__.bind = bind;/** + @method oneWay + @for Ember + @param {Object} obj The root object of the transform. + @param {String} to The path to the 'to' side of the binding. + Must be relative to obj. + @param {String} from The path to the 'from' side of the binding. + Must be relative to obj or a global path. + @return {Ember.Binding} binding instance + */ + function oneWay(obj, to, from) { + return new Binding(to, from).oneWay().connect(obj); + } + + __exports__.oneWay = oneWay;__exports__.Binding = Binding; + __exports__.isGlobalPath = isGlobalPath; + }); +define("ember-metal/cache", + ["ember-metal/dictionary","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var dictionary = __dependency1__["default"]; + __exports__["default"] = Cache; + + function Cache(limit, func) { + this.store = dictionary(null); + this.size = 0; + this.misses = 0; + this.hits = 0; + this.limit = limit; + this.func = func; + } + + var FALSE = function() { }; + var ZERO = function() { }; + var UNDEFINED = function() { }; + var NULL = function() { }; + + Cache.prototype = { + set: function(key, value) { + if (this.limit > this.size) { + this.size ++; + if (value === undefined) { + this.store[key] = UNDEFINED; + } else { + this.store[key] = value; + } + } + + return value; + }, + + get: function(key) { + var value = this.store[key]; + + if (value === undefined) { + this.misses ++; + value = this.set(key, this.func(key)); + } else if (value === UNDEFINED) { + this.hits ++; + value = undefined; + } else { + this.hits ++; + // nothing to translate + } + + return value; + }, + + purge: function() { + this.store = dictionary(null); + this.size = 0; + this.hits = 0; + this.misses = 0; + } + }; + }); +define("ember-metal/chains", + ["ember-metal/core","ember-metal/property_get","ember-metal/utils","ember-metal/array","ember-metal/watch_key","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // warn, assert, etc; + var get = __dependency2__.get; + var normalizeTuple = __dependency2__.normalizeTuple; + var meta = __dependency3__.meta; + var forEach = __dependency4__.forEach; + var watchKey = __dependency5__.watchKey; + var unwatchKey = __dependency5__.unwatchKey; + + var metaFor = meta; + var warn = Ember.warn; + var FIRST_KEY = /^([^\.]+)/; + + function firstKey(path) { + return path.match(FIRST_KEY)[0]; + } + + var pendingQueue = []; + + // attempts to add the pendingQueue chains again. If some of them end up + // back in the queue and reschedule is true, schedules a timeout to try + // again. + function flushPendingChains() { + if (pendingQueue.length === 0) { return; } // nothing to do + + var queue = pendingQueue; + pendingQueue = []; + + forEach.call(queue, function(q) { q[0].add(q[1]); }); + + warn('Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos', pendingQueue.length === 0); + } + + __exports__.flushPendingChains = flushPendingChains;function addChainWatcher(obj, keyName, node) { + if (!obj || ('object' !== typeof obj)) { return; } // nothing to do + + var m = metaFor(obj); + var nodes = m.chainWatchers; + + if (!m.hasOwnProperty('chainWatchers')) { + nodes = m.chainWatchers = {}; + } + + if (!nodes[keyName]) { nodes[keyName] = []; } + nodes[keyName].push(node); + watchKey(obj, keyName, m); + } + + function removeChainWatcher(obj, keyName, node) { + if (!obj || 'object' !== typeof obj) { return; } // nothing to do + + var m = obj['__ember_meta__']; + if (m && !m.hasOwnProperty('chainWatchers')) { return; } // nothing to do + + var nodes = m && m.chainWatchers; + + if (nodes && nodes[keyName]) { + nodes = nodes[keyName]; + for (var i = 0, l = nodes.length; i < l; i++) { + if (nodes[i] === node) { + nodes.splice(i, 1); + break; + } + } + } + unwatchKey(obj, keyName, m); + } + + // A ChainNode watches a single key on an object. If you provide a starting + // value for the key then the node won't actually watch it. For a root node + // pass null for parent and key and object for value. + function ChainNode(parent, key, value) { + this._parent = parent; + this._key = key; + + // _watching is true when calling get(this._parent, this._key) will + // return the value of this node. + // + // It is false for the root of a chain (because we have no parent) + // and for global paths (because the parent node is the object with + // the observer on it) + this._watching = value===undefined; + + this._value = value; + this._paths = {}; + if (this._watching) { + this._object = parent.value(); + if (this._object) { addChainWatcher(this._object, this._key, this); } + } + + // Special-case: the EachProxy relies on immediate evaluation to + // establish its observers. + // + // TODO: Replace this with an efficient callback that the EachProxy + // can implement. + if (this._parent && this._parent._key === '@each') { + this.value(); + } + } + + var ChainNodePrototype = ChainNode.prototype; + + function lazyGet(obj, key) { + if (!obj) return undefined; + + var meta = obj['__ember_meta__']; + // check if object meant only to be a prototype + if (meta && meta.proto === obj) return undefined; + + if (key === "@each") return get(obj, key); + + // if a CP only return cached value + var desc = meta && meta.descs[key]; + if (desc && desc._cacheable) { + if (key in meta.cache) { + return meta.cache[key]; + } else { + return undefined; + } + } + + return get(obj, key); + } + + ChainNodePrototype.value = function() { + if (this._value === undefined && this._watching) { + var obj = this._parent.value(); + this._value = lazyGet(obj, this._key); + } + return this._value; + }; + + ChainNodePrototype.destroy = function() { + if (this._watching) { + var obj = this._object; + if (obj) { removeChainWatcher(obj, this._key, this); } + this._watching = false; // so future calls do nothing + } + }; + + // copies a top level object only + ChainNodePrototype.copy = function(obj) { + var ret = new ChainNode(null, null, obj); + var paths = this._paths; + var path; + + for (path in paths) { + if (paths[path] <= 0) { continue; } // this check will also catch non-number vals. + ret.add(path); + } + return ret; + }; + + // called on the root node of a chain to setup watchers on the specified + // path. + ChainNodePrototype.add = function(path) { + var obj, tuple, key, src, paths; + + paths = this._paths; + paths[path] = (paths[path] || 0) + 1; + + obj = this.value(); + tuple = normalizeTuple(obj, path); + + // the path was a local path + if (tuple[0] && tuple[0] === obj) { + path = tuple[1]; + key = firstKey(path); + path = path.slice(key.length+1); + + // global path, but object does not exist yet. + // put into a queue and try to connect later. + } else if (!tuple[0]) { + pendingQueue.push([this, path]); + tuple.length = 0; + return; + + // global path, and object already exists + } else { + src = tuple[0]; + key = path.slice(0, 0-(tuple[1].length+1)); + path = tuple[1]; + } + + tuple.length = 0; + this.chain(key, path, src); + }; + + // called on the root node of a chain to teardown watcher on the specified + // path + ChainNodePrototype.remove = function(path) { + var obj, tuple, key, src, paths; + + paths = this._paths; + if (paths[path] > 0) { paths[path]--; } + + obj = this.value(); + tuple = normalizeTuple(obj, path); + if (tuple[0] === obj) { + path = tuple[1]; + key = firstKey(path); + path = path.slice(key.length+1); + } else { + src = tuple[0]; + key = path.slice(0, 0-(tuple[1].length+1)); + path = tuple[1]; + } + + tuple.length = 0; + this.unchain(key, path); + }; + + ChainNodePrototype.count = 0; + + ChainNodePrototype.chain = function(key, path, src) { + var chains = this._chains; + var node; + if (!chains) { chains = this._chains = {}; } + + node = chains[key]; + if (!node) { node = chains[key] = new ChainNode(this, key, src); } + node.count++; // count chains... + + // chain rest of path if there is one + if (path) { + key = firstKey(path); + path = path.slice(key.length+1); + node.chain(key, path); // NOTE: no src means it will observe changes... + } + }; + + ChainNodePrototype.unchain = function(key, path) { + var chains = this._chains; + var node = chains[key]; + + // unchain rest of path first... + if (path && path.length>1) { + key = firstKey(path); + path = path.slice(key.length+1); + node.unchain(key, path); + } + + // delete node if needed. + node.count--; + if (node.count<=0) { + delete chains[node._key]; + node.destroy(); + } + + }; + + ChainNodePrototype.willChange = function(events) { + var chains = this._chains; + if (chains) { + for(var key in chains) { + if (!chains.hasOwnProperty(key)) { continue; } + chains[key].willChange(events); + } + } + + if (this._parent) { this._parent.chainWillChange(this, this._key, 1, events); } + }; + + ChainNodePrototype.chainWillChange = function(chain, path, depth, events) { + if (this._key) { path = this._key + '.' + path; } + + if (this._parent) { + this._parent.chainWillChange(this, path, depth+1, events); + } else { + if (depth > 1) { + events.push(this.value(), path); + } + path = 'this.' + path; + if (this._paths[path] > 0) { + events.push(this.value(), path); + } + } + }; + + ChainNodePrototype.chainDidChange = function(chain, path, depth, events) { + if (this._key) { path = this._key + '.' + path; } + if (this._parent) { + this._parent.chainDidChange(this, path, depth+1, events); + } else { + if (depth > 1) { + events.push(this.value(), path); + } + path = 'this.' + path; + if (this._paths[path] > 0) { + events.push(this.value(), path); + } + } + }; + + ChainNodePrototype.didChange = function(events) { + // invalidate my own value first. + if (this._watching) { + var obj = this._parent.value(); + if (obj !== this._object) { + removeChainWatcher(this._object, this._key, this); + this._object = obj; + addChainWatcher(obj, this._key, this); + } + this._value = undefined; + + // Special-case: the EachProxy relies on immediate evaluation to + // establish its observers. + if (this._parent && this._parent._key === '@each') + this.value(); + } + + // then notify chains... + var chains = this._chains; + if (chains) { + for(var key in chains) { + if (!chains.hasOwnProperty(key)) { continue; } + chains[key].didChange(events); + } + } + + // if no events are passed in then we only care about the above wiring update + if (events === null) { return; } + + // and finally tell parent about my path changing... + if (this._parent) { this._parent.chainDidChange(this, this._key, 1, events); } + }; + + function finishChains(obj) { + // We only create meta if we really have to + var m = obj['__ember_meta__'], + chains, chainWatchers, chainNodes; + if (m) { + // finish any current chains node watchers that reference obj + chainWatchers = m.chainWatchers; + if (chainWatchers) { + for(var key in chainWatchers) { + if (!chainWatchers.hasOwnProperty(key)) { continue; } + chainNodes = chainWatchers[key]; + if (chainNodes) { + for (var i=0,l=chainNodes.length;i 1) { + args = a_slice.call(arguments); + func = args.pop(); + } + + if (typeof func !== "function") { + throw new EmberError("Computed Property declared without a property function"); + } + + var cp = new ComputedProperty(func); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + /** + Returns the cached value for a property, if one exists. + This can be useful for peeking at the value of a computed + property that is generated lazily, without accidentally causing + it to be created. + + @method cacheFor + @for Ember + @param {Object} obj the object whose property you want to check + @param {String} key the name of the property whose cached value you want + to return + @return {Object} the cached value + */ + function cacheFor(obj, key) { + var meta = obj['__ember_meta__']; + var cache = meta && meta.cache; + var ret = cache && cache[key]; + + if (ret === UNDEFINED) { return undefined; } + return ret; + } + + cacheFor.set = function(cache, key, value) { + if (value === undefined) { + cache[key] = UNDEFINED; + } else { + cache[key] = value; + } + }; + + cacheFor.get = function(cache, key) { + var ret = cache[key]; + if (ret === UNDEFINED) { return undefined; } + return ret; + }; + + cacheFor.remove = function(cache, key) { + cache[key] = undefined; + }; + + __exports__.ComputedProperty = ComputedProperty; + __exports__.computed = computed; + __exports__.cacheFor = cacheFor; + }); +define("ember-metal/computed_macros", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/is_empty","ember-metal/is_none","ember-metal/alias"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__) { + "use strict"; + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var computed = __dependency4__.computed; + var isEmpty = __dependency5__["default"]; + var isNone = __dependency6__.isNone; + var alias = __dependency7__.alias; + + /** + @module ember-metal + */ + + var a_slice = [].slice; + + function getProperties(self, propertyNames) { + var ret = {}; + for(var i = 0; i < propertyNames.length; i++) { + ret[propertyNames[i]] = get(self, propertyNames[i]); + } + return ret; + } + + function registerComputed(name, macro) { + computed[name] = function(dependentKey) { + var args = a_slice.call(arguments); + return computed(dependentKey, function() { + return macro.apply(this, args); + }); + }; + } + + function registerComputedWithProperties(name, macro) { + computed[name] = function() { + var properties = a_slice.call(arguments); + + var computedFunc = computed(function() { + return macro.apply(this, [getProperties(this, properties)]); + }); + + return computedFunc.property.apply(computedFunc, properties); + }; + } + + /** + A computed property that returns true if the value of the dependent + property is null, an empty string, empty array, or empty function. + + Example + + ```javascript + var ToDoList = Ember.Object.extend({ + done: Ember.computed.empty('todos') + }); + + var todoList = ToDoList.create({ + todos: ['Unit Test', 'Documentation', 'Release'] + }); + + todoList.get('done'); // false + todoList.get('todos').clear(); + todoList.get('done'); // true + ``` + + @since 1.6.0 + @method computed.empty + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which negate + the original value for property + */ + computed.empty = function (dependentKey) { + return computed(dependentKey + '.length', function () { + return isEmpty(get(this, dependentKey)); + }); + }; + + /** + A computed property that returns true if the value of the dependent + property is NOT null, an empty string, empty array, or empty function. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasStuff: Ember.computed.notEmpty('backpack') + }); + + var hamster = Hamster.create({ backpack: ['Food', 'Sleeping Bag', 'Tent'] }); + + hamster.get('hasStuff'); // true + hamster.get('backpack').clear(); // [] + hamster.get('hasStuff'); // false + ``` + + @method computed.notEmpty + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which returns true if + original value for property is not empty. + */ + computed.notEmpty = function(dependentKey) { + return computed(dependentKey + '.length', function () { + return !isEmpty(get(this, dependentKey)); + }); + }; + + /** + A computed property that returns true if the value of the dependent + property is null or undefined. This avoids errors from JSLint complaining + about use of ==, which can be technically confusing. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + isHungry: Ember.computed.none('food') + }); + + var hamster = Hamster.create(); + + hamster.get('isHungry'); // true + hamster.set('food', 'Banana'); + hamster.get('isHungry'); // false + hamster.set('food', null); + hamster.get('isHungry'); // true + ``` + + @method computed.none + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which + returns true if original value for property is null or undefined. + */ + registerComputed('none', function(dependentKey) { + return isNone(get(this, dependentKey)); + }); + + /** + A computed property that returns the inverse boolean value + of the original value for the dependent property. + + Example + + ```javascript + var User = Ember.Object.extend({ + isAnonymous: Ember.computed.not('loggedIn') + }); + + var user = User.create({loggedIn: false}); + + user.get('isAnonymous'); // true + user.set('loggedIn', true); + user.get('isAnonymous'); // false + ``` + + @method computed.not + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which returns + inverse of the original value for property + */ + registerComputed('not', function(dependentKey) { + return !get(this, dependentKey); + }); + + /** + A computed property that converts the provided dependent property + into a boolean value. + + ```javascript + var Hamster = Ember.Object.extend({ + hasBananas: Ember.computed.bool('numBananas') + }); + + var hamster = Hamster.create(); + + hamster.get('hasBananas'); // false + hamster.set('numBananas', 0); + hamster.get('hasBananas'); // false + hamster.set('numBananas', 1); + hamster.get('hasBananas'); // true + hamster.set('numBananas', null); + hamster.get('hasBananas'); // false + ``` + + @method computed.bool + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which converts + to boolean the original value for property + */ + registerComputed('bool', function(dependentKey) { + return !!get(this, dependentKey); + }); + + /** + A computed property which matches the original value for the + dependent property against a given RegExp, returning `true` + if they values matches the RegExp and `false` if it does not. + + Example + + ```javascript + var User = Ember.Object.extend({ + hasValidEmail: Ember.computed.match('email', /^.+@.+\..+$/) + }); + + var user = User.create({loggedIn: false}); + + user.get('hasValidEmail'); // false + user.set('email', ''); + user.get('hasValidEmail'); // false + user.set('email', 'ember_hamster@example.com'); + user.get('hasValidEmail'); // true + ``` + + @method computed.match + @for Ember + @param {String} dependentKey + @param {RegExp} regexp + @return {Ember.ComputedProperty} computed property which match + the original value for property against a given RegExp + */ + registerComputed('match', function(dependentKey, regexp) { + var value = get(this, dependentKey); + return typeof value === 'string' ? regexp.test(value) : false; + }); + + /** + A computed property that returns true if the provided dependent property + is equal to the given value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + napTime: Ember.computed.equal('state', 'sleepy') + }); + + var hamster = Hamster.create(); + + hamster.get('napTime'); // false + hamster.set('state', 'sleepy'); + hamster.get('napTime'); // true + hamster.set('state', 'hungry'); + hamster.get('napTime'); // false + ``` + + @method computed.equal + @for Ember + @param {String} dependentKey + @param {String|Number|Object} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is equal to the given value. + */ + registerComputed('equal', function(dependentKey, value) { + return get(this, dependentKey) === value; + }); + + /** + A computed property that returns true if the provided dependent property + is greater than the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasTooManyBananas: Ember.computed.gt('numBananas', 10) + }); + + var hamster = Hamster.create(); + + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 3); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 11); + hamster.get('hasTooManyBananas'); // true + ``` + + @method computed.gt + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is greater than given value. + */ + registerComputed('gt', function(dependentKey, value) { + return get(this, dependentKey) > value; + }); + + /** + A computed property that returns true if the provided dependent property + is greater than or equal to the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasTooManyBananas: Ember.computed.gte('numBananas', 10) + }); + + var hamster = Hamster.create(); + + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 3); + hamster.get('hasTooManyBananas'); // false + hamster.set('numBananas', 10); + hamster.get('hasTooManyBananas'); // true + ``` + + @method computed.gte + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is greater or equal then given value. + */ + registerComputed('gte', function(dependentKey, value) { + return get(this, dependentKey) >= value; + }); + + /** + A computed property that returns true if the provided dependent property + is less than the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + needsMoreBananas: Ember.computed.lt('numBananas', 3) + }); + + var hamster = Hamster.create(); + + hamster.get('needsMoreBananas'); // true + hamster.set('numBananas', 3); + hamster.get('needsMoreBananas'); // false + hamster.set('numBananas', 2); + hamster.get('needsMoreBananas'); // true + ``` + + @method computed.lt + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is less then given value. + */ + registerComputed('lt', function(dependentKey, value) { + return get(this, dependentKey) < value; + }); + + /** + A computed property that returns true if the provided dependent property + is less than or equal to the provided value. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + needsMoreBananas: Ember.computed.lte('numBananas', 3) + }); + + var hamster = Hamster.create(); + + hamster.get('needsMoreBananas'); // true + hamster.set('numBananas', 5); + hamster.get('needsMoreBananas'); // false + hamster.set('numBananas', 3); + hamster.get('needsMoreBananas'); // true + ``` + + @method computed.lte + @for Ember + @param {String} dependentKey + @param {Number} value + @return {Ember.ComputedProperty} computed property which returns true if + the original value for property is less or equal than given value. + */ + registerComputed('lte', function(dependentKey, value) { + return get(this, dependentKey) <= value; + }); + + /** + A computed property that performs a logical `and` on the + original values for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + readyForCamp: Ember.computed.and('hasTent', 'hasBackpack') + }); + + var hamster = Hamster.create(); + + hamster.get('readyForCamp'); // false + hamster.set('hasTent', true); + hamster.get('readyForCamp'); // false + hamster.set('hasBackpack', true); + hamster.get('readyForCamp'); // true + ``` + + @method computed.and + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which performs + a logical `and` on the values of all the original values for properties. + */ + registerComputedWithProperties('and', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && !properties[key]) { + return false; + } + } + return true; + }); + + /** + A computed property which performs a logical `or` on the + original values for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + readyForRain: Ember.computed.or('hasJacket', 'hasUmbrella') + }); + + var hamster = Hamster.create(); + + hamster.get('readyForRain'); // false + hamster.set('hasJacket', true); + hamster.get('readyForRain'); // true + ``` + + @method computed.or + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which performs + a logical `or` on the values of all the original values for properties. + */ + registerComputedWithProperties('or', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && properties[key]) { + return true; + } + } + return false; + }); + + /** + A computed property that returns the first truthy value + from a list of dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + hasClothes: Ember.computed.any('hat', 'shirt') + }); + + var hamster = Hamster.create(); + + hamster.get('hasClothes'); // null + hamster.set('shirt', 'Hawaiian Shirt'); + hamster.get('hasClothes'); // 'Hawaiian Shirt' + ``` + + @method computed.any + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which returns + the first truthy value of given list of properties. + */ + registerComputedWithProperties('any', function(properties) { + for (var key in properties) { + if (properties.hasOwnProperty(key) && properties[key]) { + return properties[key]; + } + } + return null; + }); + + /** + A computed property that returns the array of values + for the provided dependent properties. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + clothes: Ember.computed.collect('hat', 'shirt') + }); + + var hamster = Hamster.create(); + + hamster.get('clothes'); // [null, null] + hamster.set('hat', 'Camp Hat'); + hamster.set('shirt', 'Camp Shirt'); + hamster.get('clothes'); // ['Camp Hat', 'Camp Shirt'] + ``` + + @method computed.collect + @for Ember + @param {String} dependentKey* + @return {Ember.ComputedProperty} computed property which maps + values of all passed in properties to an array. + */ + registerComputedWithProperties('collect', function(properties) { + var res = []; + for (var key in properties) { + if (properties.hasOwnProperty(key)) { + if (isNone(properties[key])) { + res.push(null); + } else { + res.push(properties[key]); + } + } + } + return res; + }); + + /** + Creates a new property that is an alias for another property + on an object. Calls to `get` or `set` this property behave as + though they were called on the original property. + + ```javascript + var Person = Ember.Object.extend({ + name: 'Alex Matchneer', + nomen: Ember.computed.alias('name') + }); + + var alex = Person.create(); + + alex.get('nomen'); // 'Alex Matchneer' + alex.get('name'); // 'Alex Matchneer' + + alex.set('nomen', '@machty'); + alex.get('name'); // '@machty' + ``` + + @method computed.alias + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates an + alias to the original value for property. + */ + computed.alias = alias; + + /** + Where `computed.alias` aliases `get` and `set`, and allows for bidirectional + data flow, `computed.oneWay` only provides an aliased `get`. The `set` will + not mutate the upstream property, rather causes the current property to + become the value set. This causes the downstream property to permanently + diverge from the upstream property. + + Example + + ```javascript + var User = Ember.Object.extend({ + firstName: null, + lastName: null, + nickName: Ember.computed.oneWay('firstName') + }); + + var teddy = User.create({ + firstName: 'Teddy', + lastName: 'Zeenny' + }); + + teddy.get('nickName'); // 'Teddy' + teddy.set('nickName', 'TeddyBear'); // 'TeddyBear' + teddy.get('firstName'); // 'Teddy' + ``` + + @method computed.oneWay + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + */ + computed.oneWay = function(dependentKey) { + return alias(dependentKey).oneWay(); + }; + + /** + This is a more semantically meaningful alias of `computed.oneWay`, + whose name is somewhat ambiguous as to which direction the data flows. + + @method computed.reads + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + */ + computed.reads = computed.oneWay; + + /** + Where `computed.oneWay` provides oneWay bindings, `computed.readOnly` provides + a readOnly one way binding. Very often when using `computed.oneWay` one does + not also want changes to propogate back up, as they will replace the value. + + This prevents the reverse flow, and also throws an exception when it occurs. + + Example + + ```javascript + var User = Ember.Object.extend({ + firstName: null, + lastName: null, + nickName: Ember.computed.readOnly('firstName') + }); + + var teddy = User.create({ + firstName: 'Teddy', + lastName: 'Zeenny' + }); + + teddy.get('nickName'); // 'Teddy' + teddy.set('nickName', 'TeddyBear'); // throws Exception + // throw new Ember.Error('Cannot Set: nickName on: ' );` + teddy.get('firstName'); // 'Teddy' + ``` + + @method computed.readOnly + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates a + one way computed property to the original value for property. + @since 1.5.0 + */ + computed.readOnly = function(dependentKey) { + return alias(dependentKey).readOnly(); + }; + /** + A computed property that acts like a standard getter and setter, + but returns the value at the provided `defaultPath` if the + property itself has not been set to a value + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + wishList: Ember.computed.defaultTo('favoriteFood') + }); + + var hamster = Hamster.create({ favoriteFood: 'Banana' }); + + hamster.get('wishList'); // 'Banana' + hamster.set('wishList', 'More Unit Tests'); + hamster.get('wishList'); // 'More Unit Tests' + hamster.get('favoriteFood'); // 'Banana' + ``` + + @method computed.defaultTo + @for Ember + @param {String} defaultPath + @return {Ember.ComputedProperty} computed property which acts like + a standard getter and setter, but defaults to the value from `defaultPath`. + @deprecated Use `Ember.computed.oneWay` or custom CP with default instead. + */ + // ES6TODO: computed should have its own export path so you can do import {defaultTo} from computed + computed.defaultTo = function(defaultPath) { + return computed(function(key, newValue, cachedValue) { + + if (arguments.length === 1) { + return get(this, defaultPath); + } + return newValue != null ? newValue : get(this, defaultPath); + }); + }; + + /** + Creates a new property that is an alias for another property + on an object. Calls to `get` or `set` this property behave as + though they were called on the original property, but also + print a deprecation warning. + + @method computed.deprecatingAlias + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computed property which creates an + alias with a deprecation to the original value for property. + @since 1.7.0 + */ + computed.deprecatingAlias = function(dependentKey) { + return computed(dependentKey, function(key, value) { + + if (arguments.length > 1) { + set(this, dependentKey, value); + return value; + } else { + return get(this, dependentKey); + } + }); + }; + }); +define("ember-metal/core", + ["exports"], + function(__exports__) { + "use strict"; + /*globals Ember:true,Em:true,ENV,EmberENV,MetamorphENV:true */ + + /** + @module ember + @submodule ember-metal + */ + + /** + All Ember methods and functions are defined inside of this namespace. You + generally should not add new properties to this namespace as it may be + overwritten by future versions of Ember. + + You can also use the shorthand `Em` instead of `Ember`. + + Ember-Runtime is a framework that provides core functions for Ember including + cross-platform functions, support for property observing and objects. Its + focus is on small size and performance. You can use this in place of or + along-side other cross-platform libraries such as jQuery. + + The core Runtime framework is based on the jQuery API with a number of + performance optimizations. + + @class Ember + @static + @version 1.8.0-beta.4 + */ + + if ('undefined' === typeof Ember) { + // Create core object. Make it act like an instance of Ember.Namespace so that + // objects assigned to it are given a sane string representation. + Ember = {}; + } + + // Default imports, exports and lookup to the global object; + var imports = Ember.imports = Ember.imports || this; + var exports = Ember.exports = Ember.exports || this; + var lookup = Ember.lookup = Ember.lookup || this; + + // aliases needed to keep minifiers from removing the global context + exports.Em = exports.Ember = Ember; + + // Make sure these are set whether Ember was already defined or not + + Ember.isNamespace = true; + + Ember.toString = function() { return "Ember"; }; + + + /** + @property VERSION + @type String + @default '1.8.0-beta.4' + @static + */ + Ember.VERSION = '1.8.0-beta.4'; + + /** + Standard environmental variables. You can define these in a global `EmberENV` + variable before loading Ember to control various configuration settings. + + For backwards compatibility with earlier versions of Ember the global `ENV` + variable will be used if `EmberENV` is not defined. + + @property ENV + @type Hash + */ + + if (Ember.ENV) { + // do nothing if Ember.ENV is already setup + } else if ('undefined' !== typeof EmberENV) { + Ember.ENV = EmberENV; + } else if('undefined' !== typeof ENV) { + Ember.ENV = ENV; + } else { + Ember.ENV = {}; + } + + Ember.config = Ember.config || {}; + + // We disable the RANGE API by default for performance reasons + if ('undefined' === typeof Ember.ENV.DISABLE_RANGE_API) { + Ember.ENV.DISABLE_RANGE_API = true; + } + + if ("undefined" === typeof MetamorphENV) { + exports.MetamorphENV = {}; + } + + MetamorphENV.DISABLE_RANGE_API = Ember.ENV.DISABLE_RANGE_API; + + /** + Hash of enabled Canary features. Add to this before creating your application. + + You can also define `ENV.FEATURES` if you need to enable features flagged at runtime. + + @class FEATURES + @namespace Ember + @static + @since 1.1.0 + */ + + Ember.FEATURES = Ember.ENV.FEATURES || {}; + + /** + Test that a feature is enabled. Parsed by Ember's build tools to leave + experimental features out of beta/stable builds. + + You can define the following configuration options: + + * `ENV.ENABLE_ALL_FEATURES` - force all features to be enabled. + * `ENV.ENABLE_OPTIONAL_FEATURES` - enable any features that have not been explicitly + enabled/disabled. + + @method isEnabled + @param {String} feature + @return {Boolean} + @for Ember.FEATURES + @since 1.1.0 + */ + + Ember.FEATURES.isEnabled = function(feature) { + var featureValue = Ember.FEATURES[feature]; + + if (Ember.ENV.ENABLE_ALL_FEATURES) { + return true; + } else if (featureValue === true || featureValue === false || featureValue === undefined) { + return featureValue; + } else if (Ember.ENV.ENABLE_OPTIONAL_FEATURES) { + return true; + } else { + return false; + } + }; + + // .......................................................... + // BOOTSTRAP + // + + /** + Determines whether Ember should enhance some built-in object prototypes to + provide a more friendly API. If enabled, a few methods will be added to + `Function`, `String`, and `Array`. `Object.prototype` will not be enhanced, + which is the one that causes most trouble for people. + + In general we recommend leaving this option set to true since it rarely + conflicts with other code. If you need to turn it off however, you can + define an `ENV.EXTEND_PROTOTYPES` config to disable it. + + @property EXTEND_PROTOTYPES + @type Boolean + @default true + @for Ember + */ + Ember.EXTEND_PROTOTYPES = Ember.ENV.EXTEND_PROTOTYPES; + + if (typeof Ember.EXTEND_PROTOTYPES === 'undefined') { + Ember.EXTEND_PROTOTYPES = true; + } + + /** + Determines whether Ember logs a full stack trace during deprecation warnings + + @property LOG_STACKTRACE_ON_DEPRECATION + @type Boolean + @default true + */ + Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !== false); + + /** + Determines whether Ember should add ECMAScript 5 shims to older browsers. + + @property SHIM_ES5 + @type Boolean + @default Ember.EXTEND_PROTOTYPES + */ + Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : Ember.EXTEND_PROTOTYPES; + + /** + Determines whether Ember logs info about version of used libraries + + @property LOG_VERSION + @type Boolean + @default true + */ + Ember.LOG_VERSION = (Ember.ENV.LOG_VERSION === false) ? false : true; + + /** + Empty function. Useful for some operations. Always returns `this`. + + @method K + @private + @return {Object} + */ + var K = function() { return this; }; + var K = K; + __exports__.K = K;Ember.K = K; + //TODO: ES6 GLOBL TODO + + // Stub out the methods defined by the ember-debug package in case it's not loaded + + if ('undefined' === typeof Ember.assert) { Ember.assert = Ember.K; } + if ('undefined' === typeof Ember.warn) { Ember.warn = Ember.K; } + if ('undefined' === typeof Ember.debug) { Ember.debug = Ember.K; } + if ('undefined' === typeof Ember.runInDebug) { Ember.runInDebug = Ember.K; } + if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = Ember.K; } + if ('undefined' === typeof Ember.deprecateFunc) { + Ember.deprecateFunc = function(_, func) { return func; }; + } + + __exports__["default"] = Ember; + }); +define("ember-metal/dependent_keys", + ["ember-metal/platform","ember-metal/watching","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var create = __dependency1__.create; + var watch = __dependency2__.watch; + var unwatch = __dependency2__.unwatch; + + /** + @module ember-metal + */ + + var o_create = create; + + // .......................................................... + // DEPENDENT KEYS + // + + // data structure: + // meta.deps = { + // 'depKey': { + // 'keyName': count, + // } + // } + + /* + This function returns a map of unique dependencies for a + given object and key. + */ + function keysForDep(depsMeta, depKey) { + var keys = depsMeta[depKey]; + if (!keys) { + // if there are no dependencies yet for a the given key + // create a new empty list of dependencies for the key + keys = depsMeta[depKey] = {}; + } else if (!depsMeta.hasOwnProperty(depKey)) { + // otherwise if the dependency list is inherited from + // a superclass, clone the hash + keys = depsMeta[depKey] = o_create(keys); + } + return keys; + } + + function metaForDeps(meta) { + return keysForDep(meta, 'deps'); + } + + function addDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // add all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Increment the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) + 1; + // Watch the depKey + watch(obj, depKey, meta); + } + } + + __exports__.addDependentKeys = addDependentKeys;function removeDependentKeys(desc, obj, keyName, meta) { + // the descriptor has a list of dependent keys, so + // remove all of its dependent keys. + var depKeys = desc._dependentKeys, depsMeta, idx, len, depKey, keys; + if (!depKeys) return; + + depsMeta = metaForDeps(meta); + + for(idx = 0, len = depKeys.length; idx < len; idx++) { + depKey = depKeys[idx]; + // Lookup keys meta for depKey + keys = keysForDep(depsMeta, depKey); + // Decrement the number of times depKey depends on keyName. + keys[keyName] = (keys[keyName] || 0) - 1; + // Unwatch the depKey + unwatch(obj, depKey, meta); + } + } + + __exports__.removeDependentKeys = removeDependentKeys; + }); +define("ember-metal/deprecate_property", + ["ember-metal/core","ember-metal/platform","ember-metal/properties","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var Ember = __dependency1__["default"]; + var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; + var defineProperty = __dependency3__.defineProperty; + var get = __dependency4__.get; + var set = __dependency5__.set; + + + /** + Used internally to allow changing properties in a backwards compatible way, and print a helpful + deprecation warning. + + @method deprecateProperty + @param {Object} object The object to add the deprecated property to. + @param {String} deprecatedKey The property to add (and print deprecation warnings upon accessing). + @param {String} newKey The property that will be aliased. + @private + @since 1.7.0 + */ + + function deprecateProperty(object, deprecatedKey, newKey) { + function deprecate() { + } + + if (hasPropertyAccessors) { + defineProperty(object, deprecatedKey, { + configurable: true, + enumerable: false, + set: function(value) { deprecate(); set(this, newKey, value); }, + get: function() { deprecate(); return get(this, newKey); } + }); + } + } + + __exports__.deprecateProperty = deprecateProperty; + }); +define("ember-metal/dictionary", + ["exports"], + function(__exports__) { + "use strict"; + // the delete is meant to hint at runtimes that this object should remain in + // dictionary mode. This is clearly a runtime specific hack, but currently it + // appears worthwile in some usecases. Please note, these deletes do increase + // the cost of creation dramatically over a plain Object.create. And as this + // only makes sense for long-lived dictionaries that aren't instantiated often. + __exports__["default"] = function makeDictionary(parent) { + var dict = Object.create(parent); + dict['_dict'] = null; + delete dict['_dict']; + return dict; + } + }); +define("ember-metal/enumerable_utils", + ["ember-metal/array","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var _filter = __dependency1__.filter; + var a_forEach = __dependency1__.forEach; + var _indexOf = __dependency1__.indexOf; + var _map = __dependency1__.map; + + var splice = Array.prototype.splice; + + /** + * Defines some convenience methods for working with Enumerables. + * `Ember.EnumerableUtils` uses `Ember.ArrayPolyfills` when necessary. + * + * @class EnumerableUtils + * @namespace Ember + * @static + * */ + + /** + * Calls the map function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-map method when necessary. + * + * @method map + * @param {Object} obj The object that should be mapped + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + * @return {Array} An array of mapped values. + */ + function map(obj, callback, thisArg) { + return obj.map ? obj.map.call(obj, callback, thisArg) : _map.call(obj, callback, thisArg); + } + + __exports__.map = map;/** + * Calls the forEach function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-forEach method when necessary. + * + * @method forEach + * @param {Object} obj The object to call forEach on + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + */ + function forEach(obj, callback, thisArg) { + return obj.forEach ? obj.forEach.call(obj, callback, thisArg) : a_forEach.call(obj, callback, thisArg); + } + + __exports__.forEach = forEach;/** + * Calls the filter function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-filter method when necessary. + * + * @method filter + * @param {Object} obj The object to call filter on + * @param {Function} callback The callback to execute + * @param {Object} thisArg Value to use as this when executing *callback* + * + * @return {Array} An array containing the filtered values + * @since 1.4.0 + */ + function filter(obj, callback, thisArg) { + return obj.filter ? obj.filter.call(obj, callback, thisArg) : _filter.call(obj, callback, thisArg); + } + + __exports__.filter = filter;/** + * Calls the indexOf function on the passed object with a specified callback. This + * uses `Ember.ArrayPolyfill`'s-indexOf method when necessary. + * + * @method indexOf + * @param {Object} obj The object to call indexOn on + * @param {Function} callback The callback to execute + * @param {Object} index The index to start searching from + * + */ + function indexOf(obj, element, index) { + return obj.indexOf ? obj.indexOf.call(obj, element, index) : _indexOf.call(obj, element, index); + } + + __exports__.indexOf = indexOf;/** + * Returns an array of indexes of the first occurrences of the passed elements + * on the passed object. + * + * ```javascript + * var array = [1, 2, 3, 4, 5]; + * Ember.EnumerableUtils.indexesOf(array, [2, 5]); // [1, 4] + * + * var fubar = "Fubarr"; + * Ember.EnumerableUtils.indexesOf(fubar, ['b', 'r']); // [2, 4] + * ``` + * + * @method indexesOf + * @param {Object} obj The object to check for element indexes + * @param {Array} elements The elements to search for on *obj* + * + * @return {Array} An array of indexes. + * + */ + function indexesOf(obj, elements) { + return elements === undefined ? [] : map(elements, function(item) { + return indexOf(obj, item); + }); + } + + __exports__.indexesOf = indexesOf;/** + * Adds an object to an array. If the array already includes the object this + * method has no effect. + * + * @method addObject + * @param {Array} array The array the passed item should be added to + * @param {Object} item The item to add to the passed array + * + * @return 'undefined' + */ + function addObject(array, item) { + var index = indexOf(array, item); + if (index === -1) { array.push(item); } + } + + __exports__.addObject = addObject;/** + * Removes an object from an array. If the array does not contain the passed + * object this method has no effect. + * + * @method removeObject + * @param {Array} array The array to remove the item from. + * @param {Object} item The item to remove from the passed array. + * + * @return 'undefined' + */ + function removeObject(array, item) { + var index = indexOf(array, item); + if (index !== -1) { array.splice(index, 1); } + } + + __exports__.removeObject = removeObject;function _replace(array, idx, amt, objects) { + var args = [].concat(objects); + var ret = []; + // https://code.google.com/p/chromium/issues/detail?id=56588 + var size = 60000; + var start = idx; + var ends = amt; + var count, chunk; + + while (args.length) { + count = ends > size ? size : ends; + if (count <= 0) { count = 0; } + + chunk = args.splice(0, size); + chunk = [start, count].concat(chunk); + + start += size; + ends -= count; + + ret = ret.concat(splice.apply(array, chunk)); + } + return ret; + } + + __exports__._replace = _replace;/** + * Replaces objects in an array with the passed objects. + * + * ```javascript + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 1, 2, [4, 5]); // [1, 4, 5] + * + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 1, 1, [4, 5]); // [1, 4, 5, 3] + * + * var array = [1,2,3]; + * Ember.EnumerableUtils.replace(array, 10, 1, [4, 5]); // [1, 2, 3, 4, 5] + * ``` + * + * @method replace + * @param {Array} array The array the objects should be inserted into. + * @param {Number} idx Starting index in the array to replace. If *idx* >= + * length, then append to the end of the array. + * @param {Number} amt Number of elements that should be removed from the array, + * starting at *idx* + * @param {Array} objects An array of zero or more objects that should be + * inserted into the array at *idx* + * + * @return {Array} The modified array. + */ + function replace(array, idx, amt, objects) { + if (array.replace) { + return array.replace(idx, amt, objects); + } else { + return _replace(array, idx, amt, objects); + } + } + + __exports__.replace = replace;/** + * Calculates the intersection of two arrays. This method returns a new array + * filled with the records that the two passed arrays share with each other. + * If there is no intersection, an empty array will be returned. + * + * ```javascript + * var array1 = [1, 2, 3, 4, 5]; + * var array2 = [1, 3, 5, 6, 7]; + * + * Ember.EnumerableUtils.intersection(array1, array2); // [1, 3, 5] + * + * var array1 = [1, 2, 3]; + * var array2 = [4, 5, 6]; + * + * Ember.EnumerableUtils.intersection(array1, array2); // [] + * ``` + * + * @method intersection + * @param {Array} array1 The first array + * @param {Array} array2 The second array + * + * @return {Array} The intersection of the two passed arrays. + */ + function intersection(array1, array2) { + var result = []; + forEach(array1, function(element) { + if (indexOf(array2, element) >= 0) { + result.push(element); + } + }); + + return result; + } + + __exports__.intersection = intersection;// TODO: this only exists to maintain the existing api, as we move forward it + // should only be part of the "global build" via some shim + __exports__["default"] = { + _replace: _replace, + addObject: addObject, + filter: filter, + forEach: forEach, + indexOf: indexOf, + indexesOf: indexesOf, + intersection: intersection, + map: map, + removeObject: removeObject, + replace: replace + }; + }); +define("ember-metal/error", + ["ember-metal/platform","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var create = __dependency1__.create; + + var errorProps = [ + 'description', + 'fileName', + 'lineNumber', + 'message', + 'name', + 'number', + 'stack' + ]; + + /** + A subclass of the JavaScript Error object for use in Ember. + + @class Error + @namespace Ember + @extends Error + @constructor + */ + function EmberError() { + var tmp = Error.apply(this, arguments); + + // Adds a `stack` property to the given error object that will yield the + // stack trace at the time captureStackTrace was called. + // When collecting the stack trace all frames above the topmost call + // to this function, including that call, will be left out of the + // stack trace. + // This is useful because we can hide Ember implementation details + // that are not very helpful for the user. + if (Error.captureStackTrace) { + Error.captureStackTrace(this, Ember.Error); + } + // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work. + for (var idx = 0; idx < errorProps.length; idx++) { + this[errorProps[idx]] = tmp[errorProps[idx]]; + } + } + + EmberError.prototype = create(Error.prototype); + + __exports__["default"] = EmberError; + }); +define("ember-metal/events", + ["ember-metal/core","ember-metal/utils","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + var Ember = __dependency1__["default"]; + var meta = __dependency2__.meta; + var tryFinally = __dependency2__.tryFinally; + var apply = __dependency2__.apply; + var applyStr = __dependency2__.applyStr; + var create = __dependency3__.create; + + var a_slice = [].slice; + var metaFor = meta; + + /* listener flags */ + var ONCE = 1; + var SUSPENDED = 2; + + + /* + The event system uses a series of nested hashes to store listeners on an + object. When a listener is registered, or when an event arrives, these + hashes are consulted to determine which target and action pair to invoke. + + The hashes are stored in the object's meta hash, and look like this: + + // Object's meta hash + { + listeners: { // variable name: `listenerSet` + "foo:changed": [ // variable name: `actions` + target, method, flags + ] + } + } + + */ + + function indexOf(array, target, method) { + var index = -1; + // hashes are added to the end of the event array + // so it makes sense to start searching at the end + // of the array and search in reverse + for (var i = array.length - 3 ; i >=0; i -= 3) { + if (target === array[i] && method === array[i + 1]) { + index = i; break; + } + } + return index; + } + + function actionsFor(obj, eventName) { + var meta = metaFor(obj, true); + var actions; + + if (!meta.listeners) { meta.listeners = {}; } + + if (!meta.hasOwnProperty('listeners')) { + // setup inherited copy of the listeners object + meta.listeners = create(meta.listeners); + } + + actions = meta.listeners[eventName]; + + // if there are actions, but the eventName doesn't exist in our listeners, then copy them from the prototype + if (actions && !meta.listeners.hasOwnProperty(eventName)) { + actions = meta.listeners[eventName] = meta.listeners[eventName].slice(); + } else if (!actions) { + actions = meta.listeners[eventName] = []; + } + + return actions; + } + + function listenersUnion(obj, eventName, otherActions) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + var target = actions[i]; + var method = actions[i+1]; + var flags = actions[i+2]; + var actionIndex = indexOf(otherActions, target, method); + + if (actionIndex === -1) { + otherActions.push(target, method, flags); + } + } + } + + __exports__.listenersUnion = listenersUnion;function listenersDiff(obj, eventName, otherActions) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + var diffActions = []; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + var target = actions[i]; + var method = actions[i+1]; + var flags = actions[i+2]; + var actionIndex = indexOf(otherActions, target, method); + + if (actionIndex !== -1) { continue; } + + otherActions.push(target, method, flags); + diffActions.push(target, method, flags); + } + + return diffActions; + } + + __exports__.listenersDiff = listenersDiff;/** + Add an event listener + + @method addListener + @for Ember + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Boolean} once A flag whether a function should only be called once + */ + function addListener(obj, eventName, target, method, once) { + + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + var flags = 0; + + if (once) flags |= ONCE; + + if (actionIndex !== -1) { return; } + + actions.push(target, method, flags); + + if ('function' === typeof obj.didAddListener) { + obj.didAddListener(eventName, target, method); + } + } + + __exports__.addListener = addListener;/** + Remove an event listener + + Arguments should match those passed to `Ember.addListener`. + + @method removeListener + @for Ember + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + */ + function removeListener(obj, eventName, target, method) { + + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + function _removeListener(target, method) { + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + + // action doesn't exist, give up silently + if (actionIndex === -1) { return; } + + actions.splice(actionIndex, 3); + + if ('function' === typeof obj.didRemoveListener) { + obj.didRemoveListener(eventName, target, method); + } + } + + if (method) { + _removeListener(target, method); + } else { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return; } + for (var i = actions.length - 3; i >= 0; i -= 3) { + _removeListener(actions[i], actions[i+1]); + } + } + } + + /** + Suspend listener during callback. + + This should only be used by the target of the event listener + when it is taking an action that would cause the event, e.g. + an object might suspend its property change listener while it is + setting that property. + + @method suspendListener + @for Ember + + @private + @param obj + @param {String} eventName + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Function} callback + */ + function suspendListener(obj, eventName, target, method, callback) { + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var actions = actionsFor(obj, eventName); + var actionIndex = indexOf(actions, target, method); + + if (actionIndex !== -1) { + actions[actionIndex+2] |= SUSPENDED; // mark the action as suspended + } + + function tryable() { return callback.call(target); } + function finalizer() { if (actionIndex !== -1) { actions[actionIndex+2] &= ~SUSPENDED; } } + + return tryFinally(tryable, finalizer); + } + + __exports__.suspendListener = suspendListener;/** + Suspends multiple listeners during a callback. + + @method suspendListeners + @for Ember + + @private + @param obj + @param {Array} eventName Array of event names + @param {Object|Function} targetOrMethod A target object or a function + @param {Function|String} method A function or the name of a function to be called on `target` + @param {Function} callback + */ + function suspendListeners(obj, eventNames, target, method, callback) { + if (!method && 'function' === typeof target) { + method = target; + target = null; + } + + var suspendedActions = []; + var actionsList = []; + var eventName, actions, i, l; + + for (i=0, l=eventNames.length; i= 0; i -= 3) { // looping in reverse for once listeners + var target = actions[i], method = actions[i+1], flags = actions[i+2]; + if (!method) { continue; } + if (flags & SUSPENDED) { continue; } + if (flags & ONCE) { removeListener(obj, eventName, target, method); } + if (!target) { target = obj; } + if ('string' === typeof method) { + if (params) { + applyStr(target, method, params); + } else { + target[method](); + } + } else { + if (params) { + apply(target, method, params); + } else { + method.call(target); + } + } + } + return true; + } + + __exports__.sendEvent = sendEvent;/** + @private + @method hasListeners + @for Ember + @param obj + @param {String} eventName + */ + function hasListeners(obj, eventName) { + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + return !!(actions && actions.length); + } + + __exports__.hasListeners = hasListeners;/** + @private + @method listenersFor + @for Ember + @param obj + @param {String} eventName + */ + function listenersFor(obj, eventName) { + var ret = []; + var meta = obj['__ember_meta__']; + var actions = meta && meta.listeners && meta.listeners[eventName]; + + if (!actions) { return ret; } + + for (var i = 0, l = actions.length; i < l; i += 3) { + var target = actions[i]; + var method = actions[i+1]; + ret.push([target, method]); + } + + return ret; + } + + __exports__.listenersFor = listenersFor;/** + Define a property as a function that should be executed when + a specified event or events are triggered. + + + ``` javascript + var Job = Ember.Object.extend({ + logCompleted: Ember.on('completed', function() { + console.log('Job completed!'); + }) + }); + + var job = Job.create(); + + Ember.sendEvent(job, 'completed'); // Logs 'Job completed!' + ``` + + @method on + @for Ember + @param {String} eventNames* + @param {Function} func + @return func + */ + function on(){ + var func = a_slice.call(arguments, -1)[0]; + var events = a_slice.call(arguments, 0, -1); + func.__ember_listens__ = events; + return func; + } + + __exports__.on = on;__exports__.removeListener = removeListener; + }); +define("ember-metal/expand_properties", + ["ember-metal/core","ember-metal/error","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var EmberError = __dependency2__["default"]; + var forEach = __dependency3__.forEach; + + /** + @module ember-metal + */ + + var BRACE_EXPANSION = /^((?:[^\.]*\.)*)\{(.*)\}$/; + var SPLIT_REGEX = /\{|\}/; + + /** + Expands `pattern`, invoking `callback` for each expansion. + + The only pattern supported is brace-expansion, anything else will be passed + once to `callback` directly. + + Example + + ```js + function echo(arg){ console.log(arg); } + + Ember.expandProperties('foo.bar', echo); //=> 'foo.bar' + Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar' + Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.bar', 'foo.baz' + Ember.expandProperties('{foo,bar}.baz', echo); //=> '{foo,bar}.baz' + Ember.expandProperties('foo.{bar,baz}.@each', echo) //=> 'foo.bar.@each', 'foo.baz.@each' + Ember.expandProperties('{foo,bar}.{spam,eggs}', echo) //=> 'foo.spam', 'foo.eggs', 'bar.spam', 'bar.eggs' + Ember.expandProperties('{foo}.bar.{baz}') //=> 'foo.bar.baz' + ``` + + @method + @private + @param {String} pattern The property pattern to expand. + @param {Function} callback The callback to invoke. It is invoked once per + expansion, and is passed the expansion. + */ + __exports__["default"] = function expandProperties(pattern, callback) { + if (pattern.indexOf(' ') > -1) { + throw new EmberError('Brace expanded properties cannot contain spaces, ' + + 'e.g. `user.{firstName, lastName}` should be `user.{firstName,lastName}`'); + } + + + return newExpandProperties(pattern, callback); + } + + function oldExpandProperties(pattern, callback) { + var match, prefix, list; + + if (match = BRACE_EXPANSION.exec(pattern)) { + prefix = match[1]; + list = match[2]; + + forEach(list.split(','), function (suffix) { + callback(prefix + suffix); + }); + } else { + callback(pattern); + } + } + + function newExpandProperties(pattern, callback) { + if ('string' === Ember.typeOf(pattern)) { + var parts = pattern.split(SPLIT_REGEX); + var properties = [parts]; + + forEach(parts, function(part, index) { + if (part.indexOf(',') >= 0) { + properties = duplicateAndReplace(properties, part.split(','), index); + } + }); + + forEach(properties, function(property) { + callback(property.join('')); + }); + } else { + callback(pattern); + } + } + + function duplicateAndReplace(properties, currentParts, index) { + var all = []; + + forEach(properties, function(property) { + forEach(currentParts, function(part) { + var current = property.slice(0); + current[index] = part; + all.push(current); + }); + }); + + return all; + } + }); +define("ember-metal/get_properties", + ["ember-metal/property_get","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var typeOf = __dependency2__.typeOf; + + /** + To get multiple properties at once, call `Ember.getProperties` + with an object followed by a list of strings or an array: + + ```javascript + Ember.getProperties(record, 'firstName', 'lastName', 'zipCode'); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + is equivalent to: + + ```javascript + Ember.getProperties(record, ['firstName', 'lastName', 'zipCode']); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + @method getProperties + @param obj + @param {String...|Array} list of keys to get + @return {Hash} + */ + __exports__["default"] = function getProperties(obj) { + var ret = {}; + var propertyNames = arguments; + var i = 1; + + if (arguments.length === 2 && typeOf(arguments[1]) === 'array') { + i = 0; + propertyNames = arguments[1]; + } + for(var len = propertyNames.length; i < len; i++) { + ret[propertyNames[i]] = get(obj, propertyNames[i]); + } + return ret; + } + }); +define("ember-metal/instrumentation", + ["ember-metal/core","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var tryCatchFinally = __dependency2__.tryCatchFinally; + + /** + The purpose of the Ember Instrumentation module is + to provide efficient, general-purpose instrumentation + for Ember. + + Subscribe to a listener by using `Ember.subscribe`: + + ```javascript + Ember.subscribe("render", { + before: function(name, timestamp, payload) { + + }, + + after: function(name, timestamp, payload) { + + } + }); + ``` + + If you return a value from the `before` callback, that same + value will be passed as a fourth parameter to the `after` + callback. + + Instrument a block of code by using `Ember.instrument`: + + ```javascript + Ember.instrument("render.handlebars", payload, function() { + // rendering logic + }, binding); + ``` + + Event names passed to `Ember.instrument` are namespaced + by periods, from more general to more specific. Subscribers + can listen for events by whatever level of granularity they + are interested in. + + In the above example, the event is `render.handlebars`, + and the subscriber listened for all events beginning with + `render`. It would receive callbacks for events named + `render`, `render.handlebars`, `render.container`, or + even `render.handlebars.layout`. + + @class Instrumentation + @namespace Ember + @static + */ + var subscribers = []; + __exports__.subscribers = subscribers;var cache = {}; + + var populateListeners = function(name) { + var listeners = []; + var subscriber; + + for (var i=0, l=subscribers.length; i -1) { + list.splice(index, 1); + } + this.size--; + return true; + } else { + return false; + } + }, + + /** + @method isEmpty + @return {Boolean} + */ + isEmpty: function() { + return this.size === 0; + }, + + /** + @method has + @param obj + @return {Boolean} + */ + has: function(obj) { + if (this.size === 0) { return false; } + + var guid = guidFor(obj); + var presenceSet = this.presenceSet; + + return !!presenceSet[guid]; + }, + + /** + @method forEach + @param {Function} fn + @param self + */ + forEach: function(fn /*, thisArg*/) { + if (typeof fn !== 'function') { + missingFunction(fn); + } + + if (this.size === 0) { return; } + + var list = this.list; + var length = arguments.length; + var i; + + if (length === 2) { + for (i = 0; i < list.length; i++) { + fn.call(arguments[1], list[i]); + } + } else { + for (i = 0; i < list.length; i++) { + fn(list[i]); + } + } + }, + + /** + @method toArray + @return {Array} + */ + toArray: function() { + return this.list.slice(); + }, + + /** + @method copy + @return {Ember.OrderedSet} + */ + copy: function() { + var Constructor = this.constructor; + var set = new Constructor(); + + set._silenceRemoveDeprecation = this._silenceRemoveDeprecation; + set.presenceSet = copyNull(this.presenceSet); + set.list = this.toArray(); + set.size = this.size; + + return set; + } + }; + + deprecateProperty(OrderedSet.prototype, 'length', 'size'); + + /** + A Map stores values indexed by keys. Unlike JavaScript's + default Objects, the keys of a Map can be any JavaScript + object. + + Internally, a Map has two data structures: + + 1. `keys`: an OrderedSet of all of the existing keys + 2. `values`: a JavaScript Object indexed by the `Ember.guidFor(key)` + + When a key/value pair is added for the first time, we + add the key to the `keys` OrderedSet, and create or + replace an entry in `values`. When an entry is deleted, + we delete its entry in `keys` and `values`. + + @class Map + @namespace Ember + @private + @constructor + */ + function Map() { + if (this instanceof this.constructor) { + this.keys = OrderedSet.create(); + this.keys._silenceRemoveDeprecation = true; + this.values = Object.create(null); + this.size = 0; + } else { + missingNew("OrderedSet"); + } + } + + Ember.Map = Map; + + /** + @method create + @static + */ + Map.create = function() { + var Constructor = this; + return new Constructor(); + }; + + Map.prototype = { + constructor: Map, + + /** + This property will change as the number of objects in the map changes. + + @property size + @type number + @default 0 + */ + size: 0, + + /** + Retrieve the value associated with a given key. + + @method get + @param {*} key + @return {*} the value associated with the key, or `undefined` + */ + get: function(key) { + if (this.size === 0) { return; } + + var values = this.values; + var guid = guidFor(key); + + return values[guid]; + }, + + /** + Adds a value to the map. If a value for the given key has already been + provided, the new value will replace the old value. + + @method set + @param {*} key + @param {*} value + @return {Ember.Map} + */ + set: function(key, value) { + var keys = this.keys; + var values = this.values; + var guid = guidFor(key); + + // ensure we don't store -0 + var k = key === -0 ? 0 : key; + + keys.add(k, guid); + + values[guid] = value; + + this.size = keys.size; + + return this; + }, + + /** + @deprecated see delete + Removes a value from the map for an associated key. + + @method remove + @param {*} key + @return {Boolean} true if an item was removed, false otherwise + */ + remove: function(key) { + + return this["delete"](key); + }, + + /** + Removes a value from the map for an associated key. + + @method delete + @param {*} key + @return {Boolean} true if an item was removed, false otherwise + */ + "delete": function(key) { + if (this.size === 0) { return false; } + // don't use ES6 "delete" because it will be annoying + // to use in browsers that are not ES6 friendly; + var keys = this.keys; + var values = this.values; + var guid = guidFor(key); + + if (values[guid]) { + keys["delete"](key, guid); + delete values[guid]; + this.size = keys.size; + return true; + } else { + return false; + } + }, + + /** + Check whether a key is present. + + @method has + @param {*} key + @return {Boolean} true if the item was present, false otherwise + */ + has: function(key) { + if (this.size === 0) { return false; } + return this.keys.has(key); + }, + + /** + Iterate over all the keys and values. Calls the function once + for each key, passing in the key and value, in that order. + + The keys are guaranteed to be iterated over in insertion order. + + @method forEach + @param {Function} callback + @param {*} self if passed, the `this` value inside the + callback. By default, `this` is the map. + */ + forEach: function(callback /*, thisArg*/) { + if (typeof callback !== 'function') { + missingFunction(callback); + } + + if (this.size === 0) { return; } + + var length = arguments.length; + var map = this; + var cb, thisArg; + + if (length === 2) { + thisArg = arguments[1]; + cb = function(key) { + callback.call(thisArg, map.get(key), key); + }; + } else { + cb = function(key) { + callback(map.get(key), key); + }; + } + + this.keys.forEach(cb); + }, + + /** + @method clear + */ + clear: function() { + this.keys.clear(); + this.values = Object.create(null); + this.size = 0; + }, + + /** + @method copy + @return {Ember.Map} + */ + copy: function() { + return copyMap(this, new Map()); + } + }; + + deprecateProperty(Map.prototype, 'length', 'size'); + + /** + @class MapWithDefault + @namespace Ember + @extends Ember.Map + @private + @constructor + @param [options] + @param {*} [options.defaultValue] + */ + function MapWithDefault(options) { + this._super$constructor(); + this.defaultValue = options.defaultValue; + } + + /** + @method create + @static + @param [options] + @param {*} [options.defaultValue] + @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns + `Ember.MapWithDefault` otherwise returns `Ember.Map` + */ + MapWithDefault.create = function(options) { + if (options) { + return new MapWithDefault(options); + } else { + return new Map(); + } + }; + + MapWithDefault.prototype = create(Map.prototype); + MapWithDefault.prototype.constructor = MapWithDefault; + MapWithDefault.prototype._super$constructor = Map; + MapWithDefault.prototype._super$get = Map.prototype.get; + + /** + Retrieve the value associated with a given key. + + @method get + @param {*} key + @return {*} the value associated with the key, or the default value + */ + MapWithDefault.prototype.get = function(key) { + var hasValue = this.has(key); + + if (hasValue) { + return this._super$get(key); + } else { + var defaultValue = this.defaultValue(key); + this.set(key, defaultValue); + return defaultValue; + } + }; + + /** + @method copy + @return {Ember.MapWithDefault} + */ + MapWithDefault.prototype.copy = function() { + var Constructor = this.constructor; + return copyMap(this, new Constructor({ + defaultValue: this.defaultValue + })); + }; + + __exports__["default"] = Map; + + __exports__.OrderedSet = OrderedSet; + __exports__.Map = Map; + __exports__.MapWithDefault = MapWithDefault; + }); +define("ember-metal/merge", + ["ember-metal/keys","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var keys = __dependency1__["default"]; + + /** + Merge the contents of two objects together into the first object. + + ```javascript + Ember.merge({first: 'Tom'}, {last: 'Dale'}); // {first: 'Tom', last: 'Dale'} + var a = {first: 'Yehuda'}, b = {last: 'Katz'}; + Ember.merge(a, b); // a == {first: 'Yehuda', last: 'Katz'}, b == {last: 'Katz'} + ``` + + @method merge + @for Ember + @param {Object} original The object to merge into + @param {Object} updates The object to copy properties from + @return {Object} + */ + __exports__["default"] = function merge(original, updates) { + if (!updates || typeof updates !== 'object') { + return original; + } + + var props = keys(updates); + var prop; + var length = props.length; + + for (var i = 0; i < length; i++) { + prop = props[i]; + original[prop] = updates[prop]; + } + + return original; + } + }); +define("ember-metal/mixin", + ["ember-metal/core","ember-metal/merge","ember-metal/array","ember-metal/platform","ember-metal/utils","ember-metal/expand_properties","ember-metal/properties","ember-metal/computed","ember-metal/binding","ember-metal/observer","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-metal + */ + + var Ember = __dependency1__["default"]; + // warn, assert, wrap, et; + var merge = __dependency2__["default"]; + var map = __dependency3__.map; + var indexOf = __dependency3__.indexOf; + var forEach = __dependency3__.forEach; + var create = __dependency4__.create; + var guidFor = __dependency5__.guidFor; + var meta = __dependency5__.meta; + var wrap = __dependency5__.wrap; + var makeArray = __dependency5__.makeArray; + var apply = __dependency5__.apply; + var expandProperties = __dependency6__["default"]; + var Descriptor = __dependency7__.Descriptor; + var defineProperty = __dependency7__.defineProperty; + var ComputedProperty = __dependency8__.ComputedProperty; + var Binding = __dependency9__.Binding; + var addObserver = __dependency10__.addObserver; + var removeObserver = __dependency10__.removeObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeBeforeObserver = __dependency10__.removeBeforeObserver; + var addListener = __dependency11__.addListener; + var removeListener = __dependency11__.removeListener; + + var REQUIRED; + var a_map = map; + var a_indexOf = indexOf; + var a_forEach = forEach; + var a_slice = [].slice; + var o_create = create; + var metaFor = meta; + + function superFunction(){ + var func = this.__nextSuper; + var ret; + if (func) { + var args = new Array(arguments.length); + for (var i = 0, l = args.length; i < l; i++) { + args[i] = arguments[i]; + } + this.__nextSuper = null; + ret = apply(this, func, args); + this.__nextSuper = func; + } + return ret; + } + + function mixinsMeta(obj) { + var m = metaFor(obj, true); + var ret = m.mixins; + if (!ret) { + ret = m.mixins = {}; + } else if (!m.hasOwnProperty('mixins')) { + ret = m.mixins = o_create(ret); + } + return ret; + } + + function initMixin(mixin, args) { + if (args && args.length > 0) { + mixin.mixins = a_map.call(args, function(x) { + if (x instanceof Mixin) { return x; } + + // Note: Manually setup a primitive mixin here. This is the only + // way to actually get a primitive mixin. This way normal creation + // of mixins will give you combined mixins... + var mixin = new Mixin(); + mixin.properties = x; + return mixin; + }); + } + return mixin; + } + + function isMethod(obj) { + return 'function' === typeof obj && + obj.isMethod !== false && + obj !== Boolean && obj !== Object && obj !== Number && obj !== Array && obj !== Date && obj !== String; + } + + var CONTINUE = {}; + + function mixinProperties(mixinsMeta, mixin) { + var guid; + + if (mixin instanceof Mixin) { + guid = guidFor(mixin); + if (mixinsMeta[guid]) { return CONTINUE; } + mixinsMeta[guid] = mixin; + return mixin.properties; + } else { + return mixin; // apply anonymous mixin properties + } + } + + function concatenatedMixinProperties(concatProp, props, values, base) { + var concats; + + // reset before adding each new mixin to pickup concats from previous + concats = values[concatProp] || base[concatProp]; + if (props[concatProp]) { + concats = concats ? concats.concat(props[concatProp]) : props[concatProp]; + } + + return concats; + } + + function giveDescriptorSuper(meta, key, property, values, descs) { + var superProperty; + + // Computed properties override methods, and do not call super to them + if (values[key] === undefined) { + // Find the original descriptor in a parent mixin + superProperty = descs[key]; + } + + // If we didn't find the original descriptor in a parent mixin, find + // it on the original object. + superProperty = superProperty || meta.descs[key]; + + if (superProperty === undefined || !(superProperty instanceof ComputedProperty)) { + return property; + } + + // Since multiple mixins may inherit from the same parent, we need + // to clone the computed property so that other mixins do not receive + // the wrapped version. + property = o_create(property); + property.func = wrap(property.func, superProperty.func); + + return property; + } + + function giveMethodSuper(obj, key, method, values, descs) { + var superMethod; + + // Methods overwrite computed properties, and do not call super to them. + if (descs[key] === undefined) { + // Find the original method in a parent mixin + superMethod = values[key]; + } + + // If we didn't find the original value in a parent mixin, find it in + // the original object + superMethod = superMethod || obj[key]; + + // Only wrap the new method if the original method was a function + if (superMethod === undefined || 'function' !== typeof superMethod) { + return method; + } + + return wrap(method, superMethod); + } + + function applyConcatenatedProperties(obj, key, value, values) { + var baseValue = values[key] || obj[key]; + + if (baseValue) { + if ('function' === typeof baseValue.concat) { + return baseValue.concat(value); + } else { + return makeArray(baseValue).concat(value); + } + } else { + return makeArray(value); + } + } + + function applyMergedProperties(obj, key, value, values) { + var baseValue = values[key] || obj[key]; + + if (!baseValue) { return value; } + + var newBase = merge({}, baseValue); + var hasFunction = false; + + for (var prop in value) { + if (!value.hasOwnProperty(prop)) { continue; } + + var propValue = value[prop]; + if (isMethod(propValue)) { + // TODO: support for Computed Properties, etc? + hasFunction = true; + newBase[prop] = giveMethodSuper(obj, prop, propValue, baseValue, {}); + } else { + newBase[prop] = propValue; + } + } + + if (hasFunction) { + newBase._super = superFunction; + } + + return newBase; + } + + function addNormalizedProperty(base, key, value, meta, descs, values, concats, mergings) { + if (value instanceof Descriptor) { + if (value === REQUIRED && descs[key]) { return CONTINUE; } + + // Wrap descriptor function to implement + // __nextSuper() if needed + if (value.func) { + value = giveDescriptorSuper(meta, key, value, values, descs); + } + + descs[key] = value; + values[key] = undefined; + } else { + if ((concats && a_indexOf.call(concats, key) >= 0) || + key === 'concatenatedProperties' || + key === 'mergedProperties') { + value = applyConcatenatedProperties(base, key, value, values); + } else if ((mergings && a_indexOf.call(mergings, key) >= 0)) { + value = applyMergedProperties(base, key, value, values); + } else if (isMethod(value)) { + value = giveMethodSuper(base, key, value, values, descs); + } + + descs[key] = undefined; + values[key] = value; + } + } + + function mergeMixins(mixins, m, descs, values, base, keys) { + var mixin, props, key, concats, mergings, meta; + + function removeKeys(keyName) { + delete descs[keyName]; + delete values[keyName]; + } + + for(var i=0, l=mixins.length; i= 0) { + if (_detect(mixins[loc], targetMixin, seen)) { return true; } + } + return false; + } + + /** + @method detect + @param obj + @return {Boolean} + */ + MixinPrototype.detect = function(obj) { + if (!obj) { return false; } + if (obj instanceof Mixin) { return _detect(obj, this, {}); } + var m = obj['__ember_meta__']; + var mixins = m && m.mixins; + if (mixins) { + return !!mixins[guidFor(this)]; + } + return false; + }; + + MixinPrototype.without = function() { + var ret = new Mixin(this); + ret._without = a_slice.call(arguments); + return ret; + }; + + function _keys(ret, mixin, seen) { + if (seen[guidFor(mixin)]) { return; } + seen[guidFor(mixin)] = true; + + if (mixin.properties) { + var props = mixin.properties; + for (var key in props) { + if (props.hasOwnProperty(key)) { ret[key] = true; } + } + } else if (mixin.mixins) { + a_forEach.call(mixin.mixins, function(x) { _keys(ret, x, seen); }); + } + } + + MixinPrototype.keys = function() { + var keys = {}; + var seen = {}; + var ret = []; + _keys(keys, this, seen); + for(var key in keys) { + if (keys.hasOwnProperty(key)) { ret.push(key); } + } + return ret; + }; + + // returns the mixins currently applied to the specified object + // TODO: Make Ember.mixin + Mixin.mixins = function(obj) { + var m = obj['__ember_meta__']; + var mixins = m && m.mixins; + var ret = []; + + if (!mixins) { return ret; } + + for (var key in mixins) { + var mixin = mixins[key]; + + // skip primitive mixins since these are always anonymous + if (!mixin.properties) { ret.push(mixin); } + } + + return ret; + }; + + REQUIRED = new Descriptor(); + REQUIRED.toString = function() { return '(Required Property)'; }; + + /** + Denotes a required property for a mixin + + @method required + @for Ember + */ + function required() { + return REQUIRED; + } + + __exports__.required = required;function Alias(methodName) { + this.methodName = methodName; + } + + Alias.prototype = new Descriptor(); + + /** + Makes a method available via an additional name. + + ```javascript + App.Person = Ember.Object.extend({ + name: function() { + return 'Tomhuda Katzdale'; + }, + moniker: Ember.aliasMethod('name') + }); + + var goodGuy = App.Person.create(); + + goodGuy.name(); // 'Tomhuda Katzdale' + goodGuy.moniker(); // 'Tomhuda Katzdale' + ``` + + @method aliasMethod + @for Ember + @param {String} methodName name of the method to alias + @return {Ember.Descriptor} + */ + function aliasMethod(methodName) { + return new Alias(methodName); + } + + __exports__.aliasMethod = aliasMethod;// .......................................................... + // OBSERVER HELPER + // + + /** + Specify a method that observes property changes. + + ```javascript + Ember.Object.extend({ + valueObserver: Ember.observer('value', function() { + // Executes whenever the "value" property changes + }) + }); + ``` + + In the future this method may become asynchronous. If you want to ensure + synchronous behavior, use `immediateObserver`. + + Also available as `Function.prototype.observes` if prototype extensions are + enabled. + + @method observer + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function observer() { + var func = a_slice.call(arguments, -1)[0]; + var paths; + + var addWatchedProperty = function (path) { paths.push(path); }; + var _paths = a_slice.call(arguments, 0, -1); + + if (typeof func !== "function") { + // revert to old, soft-deprecated argument ordering + + func = arguments[0]; + _paths = a_slice.call(arguments, 1); + } + + paths = []; + + for (var i=0; i<_paths.length; ++i) { + expandProperties(_paths[i], addWatchedProperty); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.observer called without a function"); + } + + func.__ember_observes__ = paths; + return func; + } + + __exports__.observer = observer;/** + Specify a method that observes property changes. + + ```javascript + Ember.Object.extend({ + valueObserver: Ember.immediateObserver('value', function() { + // Executes whenever the "value" property changes + }) + }); + ``` + + In the future, `Ember.observer` may become asynchronous. In this event, + `Ember.immediateObserver` will maintain the synchronous behavior. + + Also available as `Function.prototype.observesImmediately` if prototype extensions are + enabled. + + @method immediateObserver + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function immediateObserver() { + for (var i=0, l=arguments.length; i this.changingFrom ? 'green' : 'red'; + // logic + } + }), + + friendsDidChange: Ember.observer('friends.@each.name', function(obj, keyName) { + // some logic + // obj.get(keyName) returns friends array + }) + }); + ``` + + Also available as `Function.prototype.observesBefore` if prototype extensions are + enabled. + + @method beforeObserver + @for Ember + @param {String} propertyNames* + @param {Function} func + @return func + */ + function beforeObserver() { + var func = a_slice.call(arguments, -1)[0]; + var paths; + + var addWatchedProperty = function(path) { paths.push(path); }; + + var _paths = a_slice.call(arguments, 0, -1); + + if (typeof func !== "function") { + // revert to old, soft-deprecated argument ordering + + func = arguments[0]; + _paths = a_slice.call(arguments, 1); + } + + paths = []; + + for (var i=0; i<_paths.length; ++i) { + expandProperties(_paths[i], addWatchedProperty); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.beforeObserver called without a function"); + } + + func.__ember_observesBefore__ = paths; + return func; + } + + __exports__.beforeObserver = beforeObserver;__exports__.IS_BINDING = IS_BINDING; + __exports__.Mixin = Mixin; + }); +define("ember-metal/observer", + ["ember-metal/watching","ember-metal/array","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var watch = __dependency1__.watch; + var unwatch = __dependency1__.unwatch; + var map = __dependency2__.map; + var listenersFor = __dependency3__.listenersFor; + var addListener = __dependency3__.addListener; + var removeListener = __dependency3__.removeListener; + var suspendListeners = __dependency3__.suspendListeners; + var suspendListener = __dependency3__.suspendListener; + /** + @module ember-metal + */ + + var AFTER_OBSERVERS = ':change'; + var BEFORE_OBSERVERS = ':before'; + + function changeEvent(keyName) { + return keyName + AFTER_OBSERVERS; + } + + function beforeEvent(keyName) { + return keyName + BEFORE_OBSERVERS; + } + + /** + @method addObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function addObserver(obj, _path, target, method) { + addListener(obj, changeEvent(_path), target, method); + watch(obj, _path); + + return this; + } + + __exports__.addObserver = addObserver;function observersFor(obj, path) { + return listenersFor(obj, changeEvent(path)); + } + + __exports__.observersFor = observersFor;/** + @method removeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function removeObserver(obj, _path, target, method) { + unwatch(obj, _path); + removeListener(obj, changeEvent(_path), target, method); + + return this; + } + + __exports__.removeObserver = removeObserver;/** + @method addBeforeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function addBeforeObserver(obj, _path, target, method) { + addListener(obj, beforeEvent(_path), target, method); + watch(obj, _path); + + return this; + } + + __exports__.addBeforeObserver = addBeforeObserver;// Suspend observer during callback. + // + // This should only be used by the target of the observer + // while it is setting the observed path. + function _suspendBeforeObserver(obj, path, target, method, callback) { + return suspendListener(obj, beforeEvent(path), target, method, callback); + } + + __exports__._suspendBeforeObserver = _suspendBeforeObserver;function _suspendObserver(obj, path, target, method, callback) { + return suspendListener(obj, changeEvent(path), target, method, callback); + } + + __exports__._suspendObserver = _suspendObserver;function _suspendBeforeObservers(obj, paths, target, method, callback) { + var events = map.call(paths, beforeEvent); + return suspendListeners(obj, events, target, method, callback); + } + + __exports__._suspendBeforeObservers = _suspendBeforeObservers;function _suspendObservers(obj, paths, target, method, callback) { + var events = map.call(paths, changeEvent); + return suspendListeners(obj, events, target, method, callback); + } + + __exports__._suspendObservers = _suspendObservers;function beforeObserversFor(obj, path) { + return listenersFor(obj, beforeEvent(path)); + } + + __exports__.beforeObserversFor = beforeObserversFor;/** + @method removeBeforeObserver + @for Ember + @param obj + @param {String} path + @param {Object|Function} targetOrMethod + @param {Function|String} [method] + */ + function removeBeforeObserver(obj, _path, target, method) { + unwatch(obj, _path); + removeListener(obj, beforeEvent(_path), target, method); + + return this; + } + + __exports__.removeBeforeObserver = removeBeforeObserver; + }); +define("ember-metal/observer_set", + ["ember-metal/utils","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var guidFor = __dependency1__.guidFor; + var sendEvent = __dependency2__.sendEvent; + + /* + this.observerSet = { + [senderGuid]: { // variable name: `keySet` + [keyName]: listIndex + } + }, + this.observers = [ + { + sender: obj, + keyName: keyName, + eventName: eventName, + listeners: [ + [target, method, flags] + ] + }, + ... + ] + */ + __exports__["default"] = ObserverSet; + function ObserverSet() { + this.clear(); + } + + + ObserverSet.prototype.add = function(sender, keyName, eventName) { + var observerSet = this.observerSet; + var observers = this.observers; + var senderGuid = guidFor(sender); + var keySet = observerSet[senderGuid]; + var index; + + if (!keySet) { + observerSet[senderGuid] = keySet = {}; + } + index = keySet[keyName]; + if (index === undefined) { + index = observers.push({ + sender: sender, + keyName: keyName, + eventName: eventName, + listeners: [] + }) - 1; + keySet[keyName] = index; + } + return observers[index].listeners; + }; + + ObserverSet.prototype.flush = function() { + var observers = this.observers; + var i, len, observer, sender; + this.clear(); + for (i=0, len=observers.length; i < len; ++i) { + observer = observers[i]; + sender = observer.sender; + if (sender.isDestroying || sender.isDestroyed) { continue; } + sendEvent(sender, observer.eventName, [sender, observer.keyName], observer.listeners); + } + }; + + ObserverSet.prototype.clear = function() { + this.observerSet = {}; + this.observers = []; + }; + }); +define("ember-metal/path_cache", + ["ember-metal/cache","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Cache = __dependency1__["default"]; + + var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; + var IS_GLOBAL_PATH = /^([A-Z$]|([0-9][A-Z$])).*[\.]/; + var HAS_THIS = 'this.'; + + var isGlobalCache = new Cache(1000, function(key) { return IS_GLOBAL.test(key); }); + var isGlobalPathCache = new Cache(1000, function(key) { return IS_GLOBAL_PATH.test(key); }); + var hasThisCache = new Cache(1000, function(key) { return key.indexOf(HAS_THIS) !== -1; }); + var isPathCache = new Cache(1000, function(key) { return key.indexOf('.') !== -1; }); + + var caches = { + isGlobalCache: isGlobalCache, + isGlobalPathCache: isGlobalPathCache, + hasThisCache: hasThisCache, + isPathCache: isPathCache + }; + __exports__.caches = caches; + function isGlobal(path) { + return isGlobalCache.get(path); + } + + __exports__.isGlobal = isGlobal;function isGlobalPath(path) { + return isGlobalPathCache.get(path); + } + + __exports__.isGlobalPath = isGlobalPath;function hasThis(path) { + return hasThisCache.get(path); + } + + __exports__.hasThis = hasThis;function isPath(path) { + return isPathCache.get(path); + } + + __exports__.isPath = isPath; + }); +define("ember-metal/platform", + ["exports"], + function(__exports__) { + "use strict"; + /*globals Node */ + + /** + @module ember-metal + */ + var defineProperty = (function checkCompliance(defineProperty) { + if (!defineProperty) return; + try { + var a = 5; + var obj = {}; + defineProperty(obj, 'a', { + configurable: true, + enumerable: true, + get: function () { + return a; + }, + set: function (v) { + a = v; + } + }); + if (obj.a !== 5) return; + obj.a = 10; + if (a !== 10) return; + + // check non-enumerability + defineProperty(obj, 'a', { + configurable: true, + enumerable: false, + writable: true, + value: true + }); + for (var key in obj) { + if (key === 'a') return; + } + + // Detects a bug in Android <3.2 where you cannot redefine a property using + // Object.defineProperty once accessors have already been set. + if (obj.a !== true) return; + + // defineProperty is compliant + return defineProperty; + } catch (e) { + // IE8 defines Object.defineProperty but calling it on an Object throws + return; + } + })(Object.defineProperty); + + var hasES5CompliantDefineProperty = !!defineProperty; + + if (hasES5CompliantDefineProperty && typeof document !== 'undefined') { + // This is for Safari 5.0, which supports Object.defineProperty, but not + // on DOM nodes. + var canDefinePropertyOnDOM = (function() { + try { + defineProperty(document.createElement('div'), 'definePropertyOnDOM', {}); + return true; + } catch(e) { } + + return false; + })(); + + if (!canDefinePropertyOnDOM) { + defineProperty = function(obj, keyName, desc) { + var isNode; + + if (typeof Node === "object") { + isNode = obj instanceof Node; + } else { + isNode = typeof obj === "object" && typeof obj.nodeType === "number" && typeof obj.nodeName === "string"; + } + + if (isNode) { + // TODO: Should we have a warning here? + return (obj[keyName] = desc.value); + } else { + return Object.defineProperty(obj, keyName, desc); + } + }; + } + } + + if (!hasES5CompliantDefineProperty) { + defineProperty = function defineProperty(obj, keyName, desc) { + if (!desc.get) { obj[keyName] = desc.value; } + }; + } + + // ES5 15.2.3.7 + // http://es5.github.com/#x15.2.3.7 + if (!Object.defineProperties) { + Object.defineProperties = function defineProperties(object, properties) { + for (var property in properties) { + if (properties.hasOwnProperty(property) && property !== "__proto__") { + defineProperty(object, property, properties[property]); + } + } + return object; + }; + } + + /** + Identical to `Object.create()`. Implements if not available natively. + + @method create + @for Ember + */ + var create; + // ES5 15.2.3.5 + // http://es5.github.com/#x15.2.3.5 + if (!(Object.create && !Object.create(null).hasOwnProperty)) { + /* jshint scripturl:true, proto:true */ + // Contributed by Brandon Benvie, October, 2012 + var createEmpty; + var supportsProto = !({'__proto__':null} instanceof Object); + // the following produces false positives + // in Opera Mini => not a reliable check + // Object.prototype.__proto__ === null + if (supportsProto || typeof document === 'undefined') { + createEmpty = function () { + return { "__proto__": null }; + }; + } else { + // In old IE __proto__ can't be used to manually set `null`, nor does + // any other method exist to make an object that inherits from nothing, + // aside from Object.prototype itself. Instead, create a new global + // object and *steal* its Object.prototype and strip it bare. This is + // used as the prototype to create nullary objects. + createEmpty = function () { + var iframe = document.createElement('iframe'); + var parent = document.body || document.documentElement; + iframe.style.display = 'none'; + parent.appendChild(iframe); + iframe.src = 'javascript:'; + var empty = iframe.contentWindow.Object.prototype; + parent.removeChild(iframe); + iframe = null; + delete empty.constructor; + delete empty.hasOwnProperty; + delete empty.propertyIsEnumerable; + delete empty.isPrototypeOf; + delete empty.toLocaleString; + delete empty.toString; + delete empty.valueOf; + + function Empty() {} + Empty.prototype = empty; + // short-circuit future calls + createEmpty = function () { + return new Empty(); + }; + return new Empty(); + }; + } + + create = Object.create = function create(prototype, properties) { + + var object; + function Type() {} // An empty constructor. + + if (prototype === null) { + object = createEmpty(); + } else { + if (typeof prototype !== "object" && typeof prototype !== "function") { + // In the native implementation `parent` can be `null` + // OR *any* `instanceof Object` (Object|Function|Array|RegExp|etc) + // Use `typeof` tho, b/c in old IE, DOM elements are not `instanceof Object` + // like they are in modern browsers. Using `Object.create` on DOM elements + // is...err...probably inappropriate, but the native version allows for it. + throw new TypeError("Object prototype may only be an Object or null"); // same msg as Chrome + } + + Type.prototype = prototype; + + object = new Type(); + } + + if (properties !== undefined) { + Object.defineProperties(object, properties); + } + + return object; + }; + } else { + create = Object.create; + } + + var hasPropertyAccessors = hasES5CompliantDefineProperty; + var canDefineNonEnumerableProperties = hasES5CompliantDefineProperty; + + /** + @class platform + @namespace Ember + */ + + /** + Platform specific methods and feature detectors needed by the framework. + + @class platform + @namespace Ember + @static + */ + // TODO remove this + var platform = {}; + + /** + Identical to `Object.defineProperty()`. Implements as much functionality + as possible if not available natively. + + @method defineProperty + @param {Object} obj The object to modify + @param {String} keyName property name to modify + @param {Object} desc descriptor hash + @return {void} + */ + platform.defineProperty = defineProperty; + + /** + Set to true if the platform supports native getters and setters. + + @property hasPropertyAccessors + @final + */ + platform.hasPropertyAccessors = hasPropertyAccessors; + + __exports__.create = create; + __exports__.defineProperty = defineProperty; + __exports__.hasPropertyAccessors = hasPropertyAccessors; + __exports__.canDefineNonEnumerableProperties = canDefineNonEnumerableProperties; + __exports__.platform = platform; + }); +define("ember-metal/properties", + ["ember-metal/core","ember-metal/utils","ember-metal/platform","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var Ember = __dependency1__["default"]; + var metaFor = __dependency2__.meta; + var objectDefineProperty = __dependency3__.defineProperty; + var hasPropertyAccessors = __dependency3__.hasPropertyAccessors; + var overrideChains = __dependency4__.overrideChains; + // .......................................................... + // DESCRIPTOR + // + + /** + Objects of this type can implement an interface to respond to requests to + get and set. The default implementation handles simple properties. + + You generally won't need to create or subclass this directly. + + @class Descriptor + @namespace Ember + @private + @constructor + */ + function Descriptor() {} + + __exports__.Descriptor = Descriptor;// .......................................................... + // DEFINING PROPERTIES API + // + + function MANDATORY_SETTER_FUNCTION(value) { + } + + __exports__.MANDATORY_SETTER_FUNCTION = MANDATORY_SETTER_FUNCTION;function DEFAULT_GETTER_FUNCTION(name) { + return function GETTER_FUNCTION() { + var meta = this['__ember_meta__']; + return meta && meta.values[name]; + }; + } + + __exports__.DEFAULT_GETTER_FUNCTION = DEFAULT_GETTER_FUNCTION;/** + NOTE: This is a low-level method used by other parts of the API. You almost + never want to call this method directly. Instead you should use + `Ember.mixin()` to define new properties. + + Defines a property on an object. This method works much like the ES5 + `Object.defineProperty()` method except that it can also accept computed + properties and other special descriptors. + + Normally this method takes only three parameters. However if you pass an + instance of `Ember.Descriptor` as the third param then you can pass an + optional value as the fourth parameter. This is often more efficient than + creating new descriptor hashes for each property. + + ## Examples + + ```javascript + // ES5 compatible mode + Ember.defineProperty(contact, 'firstName', { + writable: true, + configurable: false, + enumerable: true, + value: 'Charles' + }); + + // define a simple property + Ember.defineProperty(contact, 'lastName', undefined, 'Jolley'); + + // define a computed property + Ember.defineProperty(contact, 'fullName', Ember.computed(function() { + return this.firstName+' '+this.lastName; + }).property('firstName', 'lastName')); + ``` + + @private + @method defineProperty + @for Ember + @param {Object} obj the object to define this property on. This may be a prototype. + @param {String} keyName the name of the property + @param {Ember.Descriptor} [desc] an instance of `Ember.Descriptor` (typically a + computed property) or an ES5 descriptor. + You must provide this or `data` but not both. + @param {*} [data] something other than a descriptor, that will + become the explicit value of this property. + */ + function defineProperty(obj, keyName, desc, data, meta) { + var descs, existingDesc, watching, value; + + if (!meta) meta = metaFor(obj); + descs = meta.descs; + existingDesc = meta.descs[keyName]; + var watchEntry = meta.watching[keyName]; + + watching = watchEntry !== undefined && watchEntry > 0; + + if (existingDesc instanceof Descriptor) { + existingDesc.teardown(obj, keyName); + } + + if (desc instanceof Descriptor) { + value = desc; + + descs[keyName] = desc; + + obj[keyName] = undefined; // make enumerable + + if (desc.setup) { desc.setup(obj, keyName); } + } else { + descs[keyName] = undefined; // shadow descriptor in proto + if (desc == null) { + value = data; + + + obj[keyName] = data; + + } else { + value = desc; + + // compatibility with ES5 + objectDefineProperty(obj, keyName, desc); + } + } + + // if key is being watched, override chains that + // were initialized with the prototype + if (watching) { overrideChains(obj, keyName, meta); } + + // The `value` passed to the `didDefineProperty` hook is + // either the descriptor or data, whichever was passed. + if (obj.didDefineProperty) { obj.didDefineProperty(obj, keyName, value); } + + return this; + } + __exports__.defineProperty = defineProperty; + }); +define("ember-metal/property_events", + ["ember-metal/utils","ember-metal/events","ember-metal/observer_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var guidFor = __dependency1__.guidFor; + var tryFinally = __dependency1__.tryFinally; + var sendEvent = __dependency2__.sendEvent; + var listenersUnion = __dependency2__.listenersUnion; + var listenersDiff = __dependency2__.listenersDiff; + var ObserverSet = __dependency3__["default"]; + + var beforeObserverSet = new ObserverSet(); + var observerSet = new ObserverSet(); + var deferred = 0; + + // .......................................................... + // PROPERTY CHANGES + // + + /** + This function is called just before an object property is about to change. + It will notify any before observers and prepare caches among other things. + + Normally you will not need to call this method directly but if for some + reason you can't directly watch a property you can invoke this method + manually along with `Ember.propertyDidChange()` which you should call just + after the property value changes. + + @method propertyWillChange + @for Ember + @param {Object} obj The object with the property that will change + @param {String} keyName The property key (or path) that will change. + @return {void} + */ + function propertyWillChange(obj, keyName) { + var m = obj['__ember_meta__']; + var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; + var proto = m && m.proto; + var desc = m && m.descs[keyName]; + + if (!watching) { return; } + if (proto === obj) { return; } + if (desc && desc.willChange) { desc.willChange(obj, keyName); } + dependentKeysWillChange(obj, keyName, m); + chainsWillChange(obj, keyName, m); + notifyBeforeObservers(obj, keyName); + } + + /** + This function is called just after an object property has changed. + It will notify any observers and clear caches among other things. + + Normally you will not need to call this method directly but if for some + reason you can't directly watch a property you can invoke this method + manually along with `Ember.propertyWillChange()` which you should call just + before the property value changes. + + @method propertyDidChange + @for Ember + @param {Object} obj The object with the property that will change + @param {String} keyName The property key (or path) that will change. + @return {void} + */ + function propertyDidChange(obj, keyName) { + var m = obj['__ember_meta__']; + var watching = (m && m.watching[keyName] > 0) || keyName === 'length'; + var proto = m && m.proto; + var desc = m && m.descs[keyName]; + + if (proto === obj) { return; } + + // shouldn't this mean that we're watching this key? + if (desc && desc.didChange) { desc.didChange(obj, keyName); } + if (!watching && keyName !== 'length') { return; } + + if (m && m.deps && m.deps[keyName]) { + dependentKeysDidChange(obj, keyName, m); + } + + chainsDidChange(obj, keyName, m, false); + notifyObservers(obj, keyName); + } + + var WILL_SEEN, DID_SEEN; + // called whenever a property is about to change to clear the cache of any dependent keys (and notify those properties of changes, etc...) + function dependentKeysWillChange(obj, depKey, meta) { + if (obj.isDestroying) { return; } + + var deps; + if (meta && meta.deps && (deps = meta.deps[depKey])) { + var seen = WILL_SEEN; + var top = !seen; + if (top) { seen = WILL_SEEN = {}; } + iterDeps(propertyWillChange, obj, deps, depKey, seen, meta); + if (top) { WILL_SEEN = null; } + } + } + + // called whenever a property has just changed to update dependent keys + function dependentKeysDidChange(obj, depKey, meta) { + if (obj.isDestroying) { return; } + + var deps; + if (meta && meta.deps && (deps = meta.deps[depKey])) { + var seen = DID_SEEN; + var top = !seen; + if (top) { seen = DID_SEEN = {}; } + iterDeps(propertyDidChange, obj, deps, depKey, seen, meta); + if (top) { DID_SEEN = null; } + } + } + + function keysOf(obj) { + var keys = []; + for (var key in obj) keys.push(key); + return keys; + } + + function iterDeps(method, obj, deps, depKey, seen, meta) { + var keys, key, i, desc; + var guid = guidFor(obj); + var current = seen[guid]; + if (!current) current = seen[guid] = {}; + if (current[depKey]) return; + current[depKey] = true; + + if (deps) { + keys = keysOf(deps); + var descs = meta.descs; + for (i=0; i Ember + if (root === null && !isPath(path)) { + return get(Ember.lookup, path); + } + + // detect complicated paths and normalize them + hasThis = pathHasThis(path); + + if (!root || hasThis) { + tuple = normalizeTuple(root, path); + root = tuple[0]; + path = tuple[1]; + tuple.length = 0; + } + + parts = path.split("."); + len = parts.length; + for (idx = 0; root != null && idx < len; idx++) { + root = get(root, parts[idx], true); + if (root && root.isDestroyed) { return undefined; } + } + return root; + } + + function getWithDefault(root, key, defaultValue) { + var value = get(root, key); + + if (value === undefined) { return defaultValue; } + return value; + } + + __exports__.getWithDefault = getWithDefault;__exports__["default"] = get; + __exports__.get = get; + __exports__.normalizeTuple = normalizeTuple; + __exports__._getPath = _getPath; + }); +define("ember-metal/property_set", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_events","ember-metal/properties","ember-metal/error","ember-metal/path_cache","ember-metal/platform","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var getPath = __dependency2__._getPath; + var propertyWillChange = __dependency3__.propertyWillChange; + var propertyDidChange = __dependency3__.propertyDidChange; + var defineProperty = __dependency4__.defineProperty; + var EmberError = __dependency5__["default"]; + var isPath = __dependency6__.isPath; + var hasPropertyAccessors = __dependency7__.hasPropertyAccessors; + + var IS_GLOBAL = /^([A-Z$]|([0-9][A-Z$]))/; + + /** + Sets the value of a property on an object, respecting computed properties + and notifying observers and other listeners of the change. If the + property is not defined but the object implements the `setUnknownProperty` + method then that will be invoked as well. + + @method set + @for Ember + @param {Object} obj The object to modify. + @param {String} keyName The property key to set + @param {Object} value The value to set + @return {Object} the passed value. + */ + var set = function set(obj, keyName, value, tolerant) { + if (typeof obj === 'string') { + value = keyName; + keyName = obj; + obj = null; + } + + + if (!obj) { + return setPath(obj, keyName, value, tolerant); + } + + var meta = obj['__ember_meta__']; + var desc = meta && meta.descs[keyName]; + var isUnknown, currentValue; + + if (desc === undefined && isPath(keyName)) { + return setPath(obj, keyName, value, tolerant); + } + + + if (desc !== undefined) { + desc.set(obj, keyName, value); + } else { + + if (typeof obj === 'object' && obj !== null && value !== undefined && obj[keyName] === value) { + return value; + } + + isUnknown = 'object' === typeof obj && !(keyName in obj); + + // setUnknownProperty is called if `obj` is an object, + // the property does not already exist, and the + // `setUnknownProperty` method exists on the object + if (isUnknown && 'function' === typeof obj.setUnknownProperty) { + obj.setUnknownProperty(keyName, value); + } else if (meta && meta.watching[keyName] > 0) { + + currentValue = obj[keyName]; + + // only trigger a change if the value has changed + if (value !== currentValue) { + propertyWillChange(obj, keyName); + + obj[keyName] = value; + + propertyDidChange(obj, keyName); + } + } else { + obj[keyName] = value; + } + } + return value; + }; + + // Currently used only by Ember Data tests + // ES6TODO: Verify still true + if (Ember.config.overrideAccessors) { + Ember.set = set; + Ember.config.overrideAccessors(); + set = Ember.set; + } + + function setPath(root, path, value, tolerant) { + var keyName; + + // get the last part of the path + keyName = path.slice(path.lastIndexOf('.') + 1); + + // get the first part of the part + path = (path === keyName) ? keyName : path.slice(0, path.length-(keyName.length+1)); + + // unless the path is this, look up the first part to + // get the root + if (path !== 'this') { + root = getPath(root, path); + } + + if (!keyName || keyName.length === 0) { + throw new EmberError('Property set failed: You passed an empty path'); + } + + if (!root) { + if (tolerant) { return; } + else { throw new EmberError('Property set failed: object in path "'+path+'" could not be found or was destroyed.'); } + } + + return set(root, keyName, value); + } + + /** + Error-tolerant form of `Ember.set`. Will not blow up if any part of the + chain is `undefined`, `null`, or destroyed. + + This is primarily used when syncing bindings, which may try to update after + an object has been destroyed. + + @method trySet + @for Ember + @param {Object} obj The object to modify. + @param {String} path The property path to set + @param {Object} value The value to set + */ + function trySet(root, path, value) { + return set(root, path, value, true); + } + + __exports__.trySet = trySet;__exports__.set = set; + }); +define("ember-metal/run_loop", + ["ember-metal/core","ember-metal/utils","ember-metal/array","ember-metal/property_events","backburner","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var apply = __dependency2__.apply; + var GUID_KEY = __dependency2__.GUID_KEY; + var indexOf = __dependency3__.indexOf; + var beginPropertyChanges = __dependency4__.beginPropertyChanges; + var endPropertyChanges = __dependency4__.endPropertyChanges; + var Backburner = __dependency5__["default"]; + + function onBegin(current) { + run.currentRunLoop = current; + } + + function onEnd(current, next) { + run.currentRunLoop = next; + } + + // ES6TODO: should Backburner become es6? + var backburner = new Backburner(['sync', 'actions', 'destroy'], { + GUID_KEY: GUID_KEY, + sync: { + before: beginPropertyChanges, + after: endPropertyChanges + }, + defaultQueue: 'actions', + onBegin: onBegin, + onEnd: onEnd, + onErrorTarget: Ember, + onErrorMethod: 'onerror' + }); + var slice = [].slice; + var concat = [].concat; + + // .......................................................... + // run - this is ideally the only public API the dev sees + // + + /** + Runs the passed target and method inside of a RunLoop, ensuring any + deferred actions including bindings and views updates are flushed at the + end. + + Normally you should not need to invoke this method yourself. However if + you are implementing raw event handlers when interfacing with other + libraries or plugins, you should probably wrap all of your code inside this + call. + + ```javascript + run(function() { + // code to be execute within a RunLoop + }); + ``` + + @class run + @namespace Ember + @static + @constructor + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} return value from invoking the passed function. + */ + __exports__["default"] = run; + function run() { + return apply(backburner, backburner.run, arguments); + } + + /** + If no run-loop is present, it creates a new one. If a run loop is + present it will queue itself to run on the existing run-loops action + queue. + + Please note: This is not for normal usage, and should be used sparingly. + + If invoked when not within a run loop: + + ```javascript + run.join(function() { + // creates a new run-loop + }); + ``` + + Alternatively, if called within an existing run loop: + + ```javascript + run(function() { + // creates a new run-loop + run.join(function() { + // joins with the existing run-loop, and queues for invocation on + // the existing run-loops action queue. + }); + }); + ``` + + @method join + @namespace Ember + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} Return value from invoking the passed function. Please note, + when called within an existing loop, no return value is possible. + */ + run.join = function(target, method /* args */) { + if (!run.currentRunLoop) { + return apply(Ember, run, arguments); + } + + var args = slice.call(arguments); + args.unshift('actions'); + apply(run, run.schedule, args); + }; + + /** + Provides a useful utility for when integrating with non-Ember libraries + that provide asynchronous callbacks. + + Ember utilizes a run-loop to batch and coalesce changes. This works by + marking the start and end of Ember-related Javascript execution. + + When using events such as a View's click handler, Ember wraps the event + handler in a run-loop, but when integrating with non-Ember libraries this + can be tedious. + + For example, the following is rather verbose but is the correct way to combine + third-party events and Ember code. + + ```javascript + var that = this; + jQuery(window).on('resize', function(){ + run(function(){ + that.handleResize(); + }); + }); + ``` + + To reduce the boilerplate, the following can be used to construct a + run-loop-wrapped callback handler. + + ```javascript + jQuery(window).on('resize', run.bind(this, this.handleResize)); + ``` + + @method bind + @namespace Ember + @param {Object} [target] target of method to call + @param {Function|String} method Method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Any additional arguments you wish to pass to the method. + @return {Object} return value from invoking the passed function. Please note, + when called within an existing loop, no return value is possible. + @since 1.4.0 + */ + run.bind = function(target, method /* args*/) { + var args = slice.call(arguments); + return function() { + return apply(run, run.join, args.concat(slice.call(arguments))); + }; + }; + + run.backburner = backburner; + run.currentRunLoop = null; + run.queues = backburner.queueNames; + + /** + Begins a new RunLoop. Any deferred actions invoked after the begin will + be buffered until you invoke a matching call to `run.end()`. This is + a lower-level way to use a RunLoop instead of using `run()`. + + ```javascript + run.begin(); + // code to be execute within a RunLoop + run.end(); + ``` + + @method begin + @return {void} + */ + run.begin = function() { + backburner.begin(); + }; + + /** + Ends a RunLoop. This must be called sometime after you call + `run.begin()` to flush any deferred actions. This is a lower-level way + to use a RunLoop instead of using `run()`. + + ```javascript + run.begin(); + // code to be execute within a RunLoop + run.end(); + ``` + + @method end + @return {void} + */ + run.end = function() { + backburner.end(); + }; + + /** + Array of named queues. This array determines the order in which queues + are flushed at the end of the RunLoop. You can define your own queues by + simply adding the queue name to this array. Normally you should not need + to inspect or modify this property. + + @property queues + @type Array + @default ['sync', 'actions', 'destroy'] + */ + + /** + Adds the passed target/method and any optional arguments to the named + queue to be executed at the end of the RunLoop. If you have not already + started a RunLoop when calling this method one will be started for you + automatically. + + At the end of a RunLoop, any methods scheduled in this way will be invoked. + Methods will be invoked in an order matching the named queues defined in + the `run.queues` property. + + ```javascript + run.schedule('sync', this, function() { + // this will be executed in the first RunLoop queue, when bindings are synced + console.log("scheduled on sync queue"); + }); + + run.schedule('actions', this, function() { + // this will be executed in the 'actions' queue, after bindings have synced. + console.log("scheduled on actions queue"); + }); + + // Note the functions will be run in order based on the run queues order. + // Output would be: + // scheduled on sync queue + // scheduled on actions queue + ``` + + @method schedule + @param {String} queue The name of the queue to schedule against. + Default queues are 'sync' and 'actions' + @param {Object} [target] target object to use as the context when invoking a method. + @param {String|Function} method The method to invoke. If you pass a string it + will be resolved on the target object at the time the scheduled item is + invoked allowing you to change the target function. + @param {Object} [arguments*] Optional arguments to be passed to the queued method. + @return {void} + */ + run.schedule = function(queue, target, method) { + checkAutoRun(); + apply(backburner, backburner.schedule, arguments); + }; + + // Used by global test teardown + run.hasScheduledTimers = function() { + return backburner.hasTimers(); + }; + + // Used by global test teardown + run.cancelTimers = function () { + backburner.cancelTimers(); + }; + + /** + Immediately flushes any events scheduled in the 'sync' queue. Bindings + use this queue so this method is a useful way to immediately force all + bindings in the application to sync. + + You should call this method anytime you need any changed state to propagate + throughout the app immediately without repainting the UI (which happens + in the later 'render' queue added by the `ember-views` package). + + ```javascript + run.sync(); + ``` + + @method sync + @return {void} + */ + run.sync = function() { + if (backburner.currentInstance) { + backburner.currentInstance.queues.sync.flush(); + } + }; + + /** + Invokes the passed target/method and optional arguments after a specified + period of time. The last parameter of this method must always be a number + of milliseconds. + + You should use this method whenever you need to run some action after a + period of time instead of using `setTimeout()`. This method will ensure that + items that expire during the same script execution cycle all execute + together, which is often more efficient than using a real setTimeout. + + ```javascript + run.later(myContext, function() { + // code here will execute within a RunLoop in about 500ms with this == myContext + }, 500); + ``` + + @method later + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} wait Number of milliseconds to wait. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.later = function(target, method) { + return apply(backburner, backburner.later, arguments); + }; + + /** + Schedule a function to run one time during the current RunLoop. This is equivalent + to calling `scheduleOnce` with the "actions" queue. + + @method once + @param {Object} [target] The target of the method to invoke. + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.once = function(target, method) { + checkAutoRun(); + var args = slice.call(arguments); + args.unshift('actions'); + return apply(backburner, backburner.scheduleOnce, args); + }; + + /** + Schedules a function to run one time in a given queue of the current RunLoop. + Calling this method with the same queue/target/method combination will have + no effect (past the initial call). + + Note that although you can pass optional arguments these will not be + considered when looking for duplicates. New arguments will replace previous + calls. + + ```javascript + run(function() { + var sayHi = function() { console.log('hi'); } + run.scheduleOnce('afterRender', myContext, sayHi); + run.scheduleOnce('afterRender', myContext, sayHi); + // sayHi will only be executed once, in the afterRender queue of the RunLoop + }); + ``` + + Also note that passing an anonymous function to `run.scheduleOnce` will + not prevent additional calls with an identical anonymous function from + scheduling the items multiple times, e.g.: + + ```javascript + function scheduleIt() { + run.scheduleOnce('actions', myContext, function() { console.log("Closure"); }); + } + scheduleIt(); + scheduleIt(); + // "Closure" will print twice, even though we're using `run.scheduleOnce`, + // because the function we pass to it is anonymous and won't match the + // previously scheduled operation. + ``` + + Available queues, and their order, can be found at `run.queues` + + @method scheduleOnce + @param {String} [queue] The name of the queue to schedule against. Default queues are 'sync' and 'actions'. + @param {Object} [target] The target of the method to invoke. + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.scheduleOnce = function(queue, target, method) { + checkAutoRun(); + return apply(backburner, backburner.scheduleOnce, arguments); + }; + + /** + Schedules an item to run from within a separate run loop, after + control has been returned to the system. This is equivalent to calling + `run.later` with a wait time of 1ms. + + ```javascript + run.next(myContext, function() { + // code to be executed in the next run loop, + // which will be scheduled after the current one + }); + ``` + + Multiple operations scheduled with `run.next` will coalesce + into the same later run loop, along with any other operations + scheduled by `run.later` that expire right around the same + time that `run.next` operations will fire. + + Note that there are often alternatives to using `run.next`. + For instance, if you'd like to schedule an operation to happen + after all DOM element operations have completed within the current + run loop, you can make use of the `afterRender` run loop queue (added + by the `ember-views` package, along with the preceding `render` queue + where all the DOM element operations happen). Example: + + ```javascript + App.MyCollectionView = Ember.CollectionView.extend({ + didInsertElement: function() { + run.scheduleOnce('afterRender', this, 'processChildElements'); + }, + processChildElements: function() { + // ... do something with collectionView's child view + // elements after they've finished rendering, which + // can't be done within the CollectionView's + // `didInsertElement` hook because that gets run + // before the child elements have been added to the DOM. + } + }); + ``` + + One benefit of the above approach compared to using `run.next` is + that you will be able to perform DOM/CSS operations before unprocessed + elements are rendered to the screen, which may prevent flickering or + other artifacts caused by delaying processing until after rendering. + + The other major benefit to the above approach is that `run.next` + introduces an element of non-determinism, which can make things much + harder to test, due to its reliance on `setTimeout`; it's much harder + to guarantee the order of scheduled operations when they are scheduled + outside of the current run loop, i.e. with `run.next`. + + @method next + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + If you pass a string it will be resolved on the + target at the time the method is invoked. + @param {Object} [args*] Optional arguments to pass to the timeout. + @return {Object} Timer information for use in cancelling, see `run.cancel`. + */ + run.next = function() { + var args = slice.call(arguments); + args.push(1); + return apply(backburner, backburner.later, args); + }; + + /** + Cancels a scheduled item. Must be a value returned by `run.later()`, + `run.once()`, `run.next()`, `run.debounce()`, or + `run.throttle()`. + + ```javascript + var runNext = run.next(myContext, function() { + // will not be executed + }); + run.cancel(runNext); + + var runLater = run.later(myContext, function() { + // will not be executed + }, 500); + run.cancel(runLater); + + var runOnce = run.once(myContext, function() { + // will not be executed + }); + run.cancel(runOnce); + + var throttle = run.throttle(myContext, function() { + // will not be executed + }, 1, false); + run.cancel(throttle); + + var debounce = run.debounce(myContext, function() { + // will not be executed + }, 1); + run.cancel(debounce); + + var debounceImmediate = run.debounce(myContext, function() { + // will be executed since we passed in true (immediate) + }, 100, true); + // the 100ms delay until this method can be called again will be cancelled + run.cancel(debounceImmediate); + ``` + + @method cancel + @param {Object} timer Timer object to cancel + @return {Boolean} true if cancelled or false/undefined if it wasn't found + */ + run.cancel = function(timer) { + return backburner.cancel(timer); + }; + + /** + Delay calling the target method until the debounce period has elapsed + with no additional debounce calls. If `debounce` is called again before + the specified time has elapsed, the timer is reset and the entire period + must pass again before the target method is called. + + This method should be used when an event may be called multiple times + but the action should only be called once when the event is done firing. + A common example is for scroll events where you only want updates to + happen once scrolling has ceased. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'debounce'}; + + run.debounce(myContext, myFunc, 150); + + // less than 150ms passes + + run.debounce(myContext, myFunc, 150); + + // 150ms passes + // myFunc is invoked with context myContext + // console logs 'debounce ran.' one time. + ``` + + Immediate allows you to run the function immediately, but debounce + other calls for this function until the wait time has elapsed. If + `debounce` is called again before the specified time has elapsed, + the timer is reset and the entire period must pass again before + the method can be called again. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'debounce'}; + + run.debounce(myContext, myFunc, 150, true); + + // console logs 'debounce ran.' one time immediately. + // 100ms passes + + run.debounce(myContext, myFunc, 150, true); + + // 150ms passes and nothing else is logged to the console and + // the debouncee is no longer being watched + + run.debounce(myContext, myFunc, 150, true); + + // console logs 'debounce ran.' one time immediately. + // 150ms passes and nothing else is logged to the console and + // the debouncee is no longer being watched + + ``` + + @method debounce + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} wait Number of milliseconds to wait. + @param {Boolean} immediate Trigger the function on the leading instead + of the trailing edge of the wait interval. Defaults to false. + @return {Array} Timer information for use in cancelling, see `run.cancel`. + */ + run.debounce = function() { + return apply(backburner, backburner.debounce, arguments); + }; + + /** + Ensure that the target method is never called more frequently than + the specified spacing period. The target method is called immediately. + + ```javascript + var myFunc = function() { console.log(this.name + ' ran.'); }; + var myContext = {name: 'throttle'}; + + run.throttle(myContext, myFunc, 150); + // myFunc is invoked with context myContext + // console logs 'throttle ran.' + + // 50ms passes + run.throttle(myContext, myFunc, 150); + + // 50ms passes + run.throttle(myContext, myFunc, 150); + + // 150ms passes + run.throttle(myContext, myFunc, 150); + // myFunc is invoked with context myContext + // console logs 'throttle ran.' + ``` + + @method throttle + @param {Object} [target] target of method to invoke + @param {Function|String} method The method to invoke. + May be a function or a string. If you pass a string + then it will be looked up on the passed target. + @param {Object} [args*] Optional arguments to pass to the timeout. + @param {Number} spacing Number of milliseconds to space out requests. + @param {Boolean} immediate Trigger the function on the leading instead + of the trailing edge of the wait interval. Defaults to true. + @return {Array} Timer information for use in cancelling, see `run.cancel`. + */ + run.throttle = function() { + return apply(backburner, backburner.throttle, arguments); + }; + + // Make sure it's not an autorun during testing + function checkAutoRun() { + if (!run.currentRunLoop) { + } + } + + /** + Add a new named queue after the specified queue. + + The queue to add will only be added once. + + @method _addQueue + @param {String} name the name of the queue to add. + @param {String} after the name of the queue to add after. + @private + */ + run._addQueue = function(name, after) { + if (indexOf.call(run.queues, name) === -1) { + run.queues.splice(indexOf.call(run.queues, after)+1, 0, name); + } + }; + }); +define("ember-metal/set_properties", + ["ember-metal/property_events","ember-metal/property_set","ember-metal/keys","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var changeProperties = __dependency1__.changeProperties; + var set = __dependency2__.set; + var keys = __dependency3__["default"]; + + /** + Set a list of properties on an object. These properties are set inside + a single `beginPropertyChanges` and `endPropertyChanges` batch, so + observers will be buffered. + + ```javascript + var anObject = Ember.Object.create(); + + anObject.setProperties({ + firstName: 'Stanley', + lastName: 'Stuart', + age: 21 + }); + ``` + + @method setProperties + @param self + @param {Object} hash + @return self + */ + __exports__["default"] = function setProperties(self, hash) { + changeProperties(function() { + var props = keys(hash); + var prop; + + for (var i = 0, l = props.length; i < l; i++) { + prop = props[i]; + + set(self, prop, hash[prop]); + } + }); + return self; + } + }); +define("ember-metal/utils", + ["ember-metal/core","ember-metal/platform","ember-metal/array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var o_defineProperty = __dependency2__.defineProperty; + var canDefineNonEnumerableProperties = __dependency2__.canDefineNonEnumerableProperties; + var hasPropertyAccessors = __dependency2__.hasPropertyAccessors; + var create = __dependency2__.create; + + var forEach = __dependency3__.forEach; + + /** + @module ember-metal + */ + + /** + Previously we used `Ember.$.uuid`, however `$.uuid` has been removed from + jQuery master. We'll just bootstrap our own uuid now. + + @private + @return {Number} the uuid + */ + var _uuid = 0; + + /** + Generates a universally unique identifier. This method + is used internally by Ember for assisting with + the generation of GUID's and other unique identifiers + such as `bind-attr` data attributes. + + @public + @return {Number} [description] + */ + function uuid() { + return ++_uuid; + } + + __exports__.uuid = uuid;/** + Prefix used for guids through out Ember. + @private + @property GUID_PREFIX + @for Ember + @type String + @final + */ + var GUID_PREFIX = 'ember'; + + var o_create = create; + // Used for guid generation... + var numberCache = []; + var stringCache = {}; + + /** + Strongly hint runtimes to intern the provided string. + + When do I need to use this function? + + For the most part, never. Pre-mature optimization is bad, and often the + runtime does exactly what you need it to, and more often the trade-off isn't + worth it. + + Why? + + Runtimes store strings in at least 2 different representations: + Ropes and Symbols (interned strings). The Rope provides a memory efficient + data-structure for strings created from concatenation or some other string + manipulation like splitting. + + Unfortunately checking equality of different ropes can be quite costly as + runtimes must resort to clever string comparison algorithims. These + algorithims typically cost in proportion to the length of the string. + Luckily, this is where the Symbols (interned strings) shine. As Symbols are + unique by their string content, equality checks can be done by pointer + comparision. + + How do I know if my string is a rope or symbol? + + Typically (warning general sweeping statement, but truthy in runtimes at + present) static strings created as part of the JS source are interned. + Strings often used for comparisions can be interned at runtime if some + criteria are met. One of these criteria can be the size of the entire rope. + For example, in chrome 38 a rope longer then 12 characters will not + intern, nor will segments of that rope. + + Some numbers: http://jsperf.com/eval-vs-keys/8 + + Known Trick™ + + @private + @return {String} interned version of the provided string + */ + function intern(str) { + var obj = {}; + obj[str] = 1; + for (var key in obj) { + if (key === str) return key; + } + return str; + } + + /** + A unique key used to assign guids and other private metadata to objects. + If you inspect an object in your browser debugger you will often see these. + They can be safely ignored. + + On browsers that support it, these properties are added with enumeration + disabled so they won't show up when you iterate over your properties. + + @private + @property GUID_KEY + @for Ember + @type String + @final + */ + var GUID_KEY = intern('__ember' + (+ new Date())); + + var GUID_DESC = { + writable: false, + configurable: false, + enumerable: false, + value: null + }; + + /** + Generates a new guid, optionally saving the guid to the object that you + pass in. You will rarely need to use this method. Instead you should + call `Ember.guidFor(obj)`, which return an existing guid if available. + + @private + @method generateGuid + @for Ember + @param {Object} [obj] Object the guid will be used for. If passed in, the guid will + be saved on the object and reused whenever you pass the same object + again. + + If no object is passed, just generate a new guid. + @param {String} [prefix] Prefix to place in front of the guid. Useful when you want to + separate the guid into separate namespaces. + @return {String} the guid + */ + function generateGuid(obj, prefix) { + if (!prefix) prefix = GUID_PREFIX; + var ret = (prefix + uuid()); + if (obj) { + if (obj[GUID_KEY] === null) { + obj[GUID_KEY] = ret; + } else { + GUID_DESC.value = ret; + o_defineProperty(obj, GUID_KEY, GUID_DESC); + } + } + return ret; + } + + __exports__.generateGuid = generateGuid;/** + Returns a unique id for the object. If the object does not yet have a guid, + one will be assigned to it. You can call this on any object, + `Ember.Object`-based or not, but be aware that it will add a `_guid` + property. + + You can also use this method on DOM Element objects. + + @private + @method guidFor + @for Ember + @param {Object} obj any object, string, number, Element, or primitive + @return {String} the unique guid for this instance. + */ + function guidFor(obj) { + + // special cases where we don't want to add a key to object + if (obj === undefined) return "(undefined)"; + if (obj === null) return "(null)"; + + var ret; + var type = typeof obj; + + // Don't allow prototype changes to String etc. to change the guidFor + switch(type) { + case 'number': + ret = numberCache[obj]; + if (!ret) ret = numberCache[obj] = 'nu'+obj; + return ret; + + case 'string': + ret = stringCache[obj]; + if (!ret) ret = stringCache[obj] = 'st' + uuid(); + return ret; + + case 'boolean': + return obj ? '(true)' : '(false)'; + + default: + if (obj[GUID_KEY]) return obj[GUID_KEY]; + if (obj === Object) return '(Object)'; + if (obj === Array) return '(Array)'; + ret = GUID_PREFIX + uuid(); + + if (obj[GUID_KEY] === null) { + obj[GUID_KEY] = ret; + } else { + GUID_DESC.value = ret; + o_defineProperty(obj, GUID_KEY, GUID_DESC); + } + return ret; + } + } + + __exports__.guidFor = guidFor;// .......................................................... + // META + // + + var META_DESC = { + writable: true, + configurable: false, + enumerable: false, + value: null + }; + + function Meta(obj) { + this.descs = {}; + this.watching = {}; + this.cache = {}; + this.cacheMeta = {}; + this.source = obj; + } + + Meta.prototype = { + descs: null, + deps: null, + watching: null, + listeners: null, + cache: null, + cacheMeta: null, + source: null, + mixins: null, + bindings: null, + chains: null, + chainWatchers: null, + values: null, + proto: null + }; + + if (!canDefineNonEnumerableProperties) { + // on platforms that don't support enumerable false + // make meta fail jQuery.isPlainObject() to hide from + // jQuery.extend() by having a property that fails + // hasOwnProperty check. + Meta.prototype.__preventPlainObject__ = true; + + // Without non-enumerable properties, meta objects will be output in JSON + // unless explicitly suppressed + Meta.prototype.toJSON = function () { }; + } + + // Placeholder for non-writable metas. + var EMPTY_META = new Meta(null); + + + /** + Retrieves the meta hash for an object. If `writable` is true ensures the + hash is writable for this object as well. + + The meta object contains information about computed property descriptors as + well as any watched properties and other information. You generally will + not access this information directly but instead work with higher level + methods that manipulate this hash indirectly. + + @method meta + @for Ember + @private + + @param {Object} obj The object to retrieve meta for + @param {Boolean} [writable=true] Pass `false` if you do not intend to modify + the meta hash, allowing the method to avoid making an unnecessary copy. + @return {Object} the meta hash for an object + */ + function meta(obj, writable) { + + var ret = obj['__ember_meta__']; + if (writable===false) return ret || EMPTY_META; + + if (!ret) { + if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); + + ret = new Meta(obj); + + + obj['__ember_meta__'] = ret; + + // make sure we don't accidentally try to create constructor like desc + ret.descs.constructor = null; + + } else if (ret.source !== obj) { + if (canDefineNonEnumerableProperties) o_defineProperty(obj, '__ember_meta__', META_DESC); + + ret = o_create(ret); + ret.descs = o_create(ret.descs); + ret.watching = o_create(ret.watching); + ret.cache = {}; + ret.cacheMeta = {}; + ret.source = obj; + + + obj['__ember_meta__'] = ret; + } + return ret; + } + + function getMeta(obj, property) { + var _meta = meta(obj, false); + return _meta[property]; + } + + __exports__.getMeta = getMeta;function setMeta(obj, property, value) { + var _meta = meta(obj, true); + _meta[property] = value; + return value; + } + + __exports__.setMeta = setMeta;/** + @deprecated + @private + + In order to store defaults for a class, a prototype may need to create + a default meta object, which will be inherited by any objects instantiated + from the class's constructor. + + However, the properties of that meta object are only shallow-cloned, + so if a property is a hash (like the event system's `listeners` hash), + it will by default be shared across all instances of that class. + + This method allows extensions to deeply clone a series of nested hashes or + other complex objects. For instance, the event system might pass + `['listeners', 'foo:change', 'ember157']` to `prepareMetaPath`, which will + walk down the keys provided. + + For each key, if the key does not exist, it is created. If it already + exists and it was inherited from its constructor, the constructor's + key is cloned. + + You can also pass false for `writable`, which will simply return + undefined if `prepareMetaPath` discovers any part of the path that + shared or undefined. + + @method metaPath + @for Ember + @param {Object} obj The object whose meta we are examining + @param {Array} path An array of keys to walk down + @param {Boolean} writable whether or not to create a new meta + (or meta property) if one does not already exist or if it's + shared with its constructor + */ + function metaPath(obj, path, writable) { + var _meta = meta(obj, writable); + var keyName, value; + + for (var i=0, l=path.length; i 1) { + watching[keyName]--; + } + } + + __exports__.unwatchKey = unwatchKey; + }); +define("ember-metal/watch_path", + ["ember-metal/utils","ember-metal/chains","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var meta = __dependency1__.meta; + var typeOf = __dependency1__.typeOf; + var ChainNode = __dependency2__.ChainNode; + + var metaFor = meta; + + // get the chains for the current object. If the current object has + // chains inherited from the proto they will be cloned and reconfigured for + // the current object. + function chainsFor(obj, meta) { + var m = meta || metaFor(obj); + var ret = m.chains; + if (!ret) { + ret = m.chains = new ChainNode(null, null, obj); + } else if (ret.value() !== obj) { + ret = m.chains = ret.copy(obj); + } + return ret; + } + + function watchPath(obj, keyPath, meta) { + // can't watch length on Array - it is special... + if (keyPath === 'length' && typeOf(obj) === 'array') { return; } + + var m = meta || metaFor(obj); + var watching = m.watching; + + if (!watching[keyPath]) { // activate watching first time + watching[keyPath] = 1; + chainsFor(obj, m).add(keyPath); + } else { + watching[keyPath] = (watching[keyPath] || 0) + 1; + } + } + + __exports__.watchPath = watchPath;function unwatchPath(obj, keyPath, meta) { + var m = meta || metaFor(obj); + var watching = m.watching; + + if (watching[keyPath] === 1) { + watching[keyPath] = 0; + chainsFor(obj, m).remove(keyPath); + } else if (watching[keyPath] > 1) { + watching[keyPath]--; + } + } + + __exports__.unwatchPath = unwatchPath; + }); +define("ember-metal/watching", + ["ember-metal/utils","ember-metal/chains","ember-metal/watch_key","ember-metal/watch_path","ember-metal/path_cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + /** + @module ember-metal + */ + + var meta = __dependency1__.meta; + var GUID_KEY = __dependency1__.GUID_KEY; + var typeOf = __dependency1__.typeOf; + var generateGuid = __dependency1__.generateGuid; + var removeChainWatcher = __dependency2__.removeChainWatcher; + var flushPendingChains = __dependency2__.flushPendingChains; + var watchKey = __dependency3__.watchKey; + var unwatchKey = __dependency3__.unwatchKey; + var watchPath = __dependency4__.watchPath; + var unwatchPath = __dependency4__.unwatchPath; + + var metaFor = meta; // utils.js + var isPath = __dependency5__.isPath; + + /** + Starts watching a property on an object. Whenever the property changes, + invokes `Ember.propertyWillChange` and `Ember.propertyDidChange`. This is the + primitive used by observers and dependent keys; usually you will never call + this method directly but instead use higher level methods like + `Ember.addObserver()` + + @private + @method watch + @for Ember + @param obj + @param {String} keyName + */ + function watch(obj, _keyPath, m) { + // can't watch length on Array - it is special... + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } + + if (!isPath(_keyPath)) { + watchKey(obj, _keyPath, m); + } else { + watchPath(obj, _keyPath, m); + } + } + + __exports__.watch = watch; + + function isWatching(obj, key) { + var meta = obj['__ember_meta__']; + return (meta && meta.watching[key]) > 0; + } + + __exports__.isWatching = isWatching;watch.flushPending = flushPendingChains; + + function unwatch(obj, _keyPath, m) { + // can't watch length on Array - it is special... + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } + + if (!isPath(_keyPath)) { + unwatchKey(obj, _keyPath, m); + } else { + unwatchPath(obj, _keyPath, m); + } + } + + __exports__.unwatch = unwatch;/** + Call on an object when you first beget it from another object. This will + setup any chained watchers on the object instance as needed. This method is + safe to call multiple times. + + @private + @method rewatch + @for Ember + @param obj + */ + function rewatch(obj) { + var m = obj['__ember_meta__'], chains = m && m.chains; + + // make sure the object has its own guid. + if (GUID_KEY in obj && !obj.hasOwnProperty(GUID_KEY)) { + generateGuid(obj); + } + + // make sure any chained watchers update. + if (chains && chains.value() !== obj) { + m.chains = chains.copy(obj); + } + } + + __exports__.rewatch = rewatch;var NODE_STACK = []; + + /** + Tears down the meta on an object so that it can be garbage collected. + Multiple calls will have no effect. + + @method destroy + @for Ember + @param {Object} obj the object to destroy + @return {void} + */ + function destroy(obj) { + var meta = obj['__ember_meta__'], node, nodes, key, nodeObject; + if (meta) { + obj['__ember_meta__'] = null; + // remove chainWatchers to remove circular references that would prevent GC + node = meta.chains; + if (node) { + NODE_STACK.push(node); + // process tree + while (NODE_STACK.length > 0) { + node = NODE_STACK.pop(); + // push children + nodes = node._chains; + if (nodes) { + for (key in nodes) { + if (nodes.hasOwnProperty(key)) { + NODE_STACK.push(nodes[key]); + } + } + } + // remove chainWatcher in node object + if (node._watching) { + nodeObject = node._object; + if (nodeObject) { + removeChainWatcher(nodeObject, node._key, node); + } + } + } + } + } + } + + __exports__.destroy = destroy; + }); +define("ember-routing-handlebars", + ["ember-metal/core","ember-handlebars","ember-routing/system/router","ember-routing-handlebars/helpers/shared","ember-routing-handlebars/helpers/link_to","ember-routing-handlebars/helpers/outlet","ember-routing-handlebars/helpers/render","ember-routing-handlebars/helpers/action","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + Ember Routing Handlebars + + @module ember + @submodule ember-routing-handlebars + @requires ember-views + */ + + var Ember = __dependency1__["default"]; + var EmberHandlebars = __dependency2__["default"]; + var Router = __dependency3__["default"]; + + var resolvePaths = __dependency4__.resolvePaths; + var resolveParams = __dependency4__.resolveParams; + + var deprecatedLinkToHelper = __dependency5__.deprecatedLinkToHelper; + var linkToHelper = __dependency5__.linkToHelper; + var LinkView = __dependency5__.LinkView; + var queryParamsHelper = __dependency5__.queryParamsHelper; + + var outletHelper = __dependency6__.outletHelper; + var OutletView = __dependency6__.OutletView; + + var renderHelper = __dependency7__["default"]; + + var ActionHelper = __dependency8__.ActionHelper; + var actionHelper = __dependency8__.actionHelper; + + Router.resolveParams = resolveParams; + Router.resolvePaths = resolvePaths; + + Ember.LinkView = LinkView; + EmberHandlebars.ActionHelper = ActionHelper; + EmberHandlebars.OutletView = OutletView; + + EmberHandlebars.registerHelper('render', renderHelper); + EmberHandlebars.registerHelper('action', actionHelper); + EmberHandlebars.registerHelper('outlet', outletHelper); + EmberHandlebars.registerHelper('link-to', linkToHelper); + EmberHandlebars.registerHelper('linkTo', deprecatedLinkToHelper); + EmberHandlebars.registerHelper('query-params', queryParamsHelper); + + __exports__["default"] = Ember; + }); +define("ember-routing-handlebars/helpers/action", + ["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/run_loop","ember-views/system/utils","ember-views/system/action_manager","ember-routing/system/router","ember-handlebars","ember-handlebars/ext","ember-handlebars/helpers/view","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Handlebars, uuid, FEATURES, assert, deprecate + var get = __dependency2__.get; + var forEach = __dependency3__.forEach; + var uuid = __dependency4__.uuid; + var run = __dependency5__["default"]; + + var isSimpleClick = __dependency6__.isSimpleClick; + var ActionManager = __dependency7__["default"]; + var EmberRouter = __dependency8__["default"]; + + var EmberHandlebars = __dependency9__["default"]; + var handlebarsGet = __dependency10__.handlebarsGet; + var viewHelper = __dependency11__.viewHelper; + var resolveParams = __dependency12__.resolveParams; + var resolvePath = __dependency12__.resolvePath; + + /** + @module ember + @submodule ember-routing + */ + + var SafeString = EmberHandlebars.SafeString; + var a_slice = Array.prototype.slice; + + function args(options, actionName) { + var ret = []; + if (actionName) { ret.push(actionName); } + + var types = options.options.types.slice(1); + var data = options.options.data; + + return ret.concat(resolveParams(options.context, options.params, { types: types, data: data })); + } + + var ActionHelper = {}; + + // registeredActions is re-exported for compatibility with older plugins + // that were using this undocumented API. + ActionHelper.registeredActions = ActionManager.registeredActions; + + __exports__.ActionHelper = ActionHelper; + + var keys = ["alt", "shift", "meta", "ctrl"]; + + var POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/; + + var isAllowedEvent = function(event, allowedKeys) { + if (typeof allowedKeys === "undefined") { + if (POINTER_EVENT_TYPE_REGEX.test(event.type)) { + return isSimpleClick(event); + } else { + allowedKeys = ''; + } + } + + if (allowedKeys.indexOf("any") >= 0) { + return true; + } + + var allowed = true; + + forEach.call(keys, function(key) { + if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) { + allowed = false; + } + }); + + return allowed; + }; + + function isKeyEvent(eventName) { + return ['keyUp', 'keyPress', 'keyDown'].indexOf(eventName) !== -1; + } + + function ignoreKeyEvent(eventName, event, keyCode) { + var any = 'any'; + keyCode = keyCode || any; + return isKeyEvent(eventName) && keyCode !== any && keyCode !== event.which.toString(); + } + + ActionHelper.registerAction = function(actionNameOrPath, options, allowedKeys) { + var actionId = uuid(); + + ActionManager.registeredActions[actionId] = { + eventName: options.eventName, + handler: function handleRegisteredAction(event) { + if (!isAllowedEvent(event, allowedKeys)) { return true; } + + if (options.preventDefault !== false) { + event.preventDefault(); + } + + if (options.bubbles === false) { + event.stopPropagation(); + } + + var target = options.target; + var parameters = options.parameters; + var eventName = options.eventName; + var actionName; + + + if (target.target) { + target = handlebarsGet(target.root, target.target, target.options); + } else { + target = target.root; + } + + if (options.boundProperty) { + actionName = resolveParams(parameters.context, [actionNameOrPath], { types: ['ID'], data: parameters.options.data })[0]; + + if (typeof actionName === 'undefined' || typeof actionName === 'function') { + actionName = actionNameOrPath; + } + } + + if (!actionName) { + actionName = actionNameOrPath; + } + + run(function runRegisteredAction() { + if (target.send) { + target.send.apply(target, args(parameters, actionName)); + } else { + target[actionName].apply(target, args(parameters)); + } + }); + } + }; + + options.view.on('willClearRender', function() { + delete ActionManager.registeredActions[actionId]; + }); + + return actionId; + }; + + /** + The `{{action}}` helper registers an HTML element within a template for DOM + event handling and forwards that interaction to the templates's controller + or supplied `target` option (see 'Specifying a Target'). + + If the controller does not implement the event, the event is sent + to the current route, and it bubbles up the route hierarchy from there. + + User interaction with that element will invoke the supplied action name on + the appropriate target. Specifying a non-quoted action name will result in + a bound property lookup at the time the event will be triggered. + + Given the following application Handlebars template on the page + + ```handlebars +
    + click me +
    + ``` + + And application code + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + actions: { + anActionName: function() { + } + } + }); + ``` + + Will result in the following rendered HTML + + ```html +
    +
    + click me +
    +
    + ``` + + Clicking "click me" will trigger the `anActionName` action of the + `App.ApplicationController`. In this case, no additional parameters will be passed. + + If you provide additional parameters to the helper: + + ```handlebars + + ``` + + Those parameters will be passed along as arguments to the JavaScript + function implementing the action. + + ### Event Propagation + + Events triggered through the action helper will automatically have + `.preventDefault()` called on them. You do not need to do so in your event + handlers. If you need to allow event propagation (to handle file inputs for + example) you can supply the `preventDefault=false` option to the `{{action}}` helper: + + ```handlebars +
    + + +
    + ``` + + To disable bubbling, pass `bubbles=false` to the helper: + + ```handlebars + + ``` + + If you need the default handler to trigger you should either register your + own event handler, or use event methods on your view class. See [Ember.View](/api/classes/Ember.View.html) + 'Responding to Browser Events' for more information. + + ### Specifying DOM event type + + By default the `{{action}}` helper registers for DOM `click` events. You can + supply an `on` option to the helper to specify a different DOM event name: + + ```handlebars +
    + click me +
    + ``` + + See `Ember.View` 'Responding to Browser Events' for a list of + acceptable DOM event names. + + NOTE: Because `{{action}}` depends on Ember's event dispatch system it will + only function if an `Ember.EventDispatcher` instance is available. An + `Ember.EventDispatcher` instance will be created when a new `Ember.Application` + is created. Having an instance of `Ember.Application` will satisfy this + requirement. + + ### Specifying whitelisted modifier keys + + By default the `{{action}}` helper will ignore click event with pressed modifier + keys. You can supply an `allowedKeys` option to specify which keys should not be ignored. + + ```handlebars +
    + click me +
    + ``` + + This way the `{{action}}` will fire when clicking with the alt key pressed down. + + Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys. + + ```handlebars +
    + click me with any key pressed +
    + ``` + + ### Specifying a Target + + There are several possible target objects for `{{action}}` helpers: + + In a typical Ember application, where views are managed through use of the + `{{outlet}}` helper, actions will bubble to the current controller, then + to the current route, and then up the route hierarchy. + + Alternatively, a `target` option can be provided to the helper to change + which object will receive the method call. This option must be a path + to an object, accessible in the current context: + + ```handlebars + {{! the application template }} +
    + click me +
    + ``` + + ```javascript + App.ApplicationView = Ember.View.extend({ + actions: { + anActionName: function(){} + } + }); + + ``` + + ### Additional Parameters + + You may specify additional parameters to the `{{action}}` helper. These + parameters are passed along as the arguments to the JavaScript function + implementing the action. + + ```handlebars + {{#each person in people}} +
    + click me +
    + {{/each}} + ``` + + Clicking "click me" will trigger the `edit` method on the current controller + with the value of `person` as a parameter. + + @method action + @for Ember.Handlebars.helpers + @param {String} actionName + @param {Object} [context]* + @param {Hash} options + */ + function actionHelper(actionName) { + var options = arguments[arguments.length - 1]; + var contexts = a_slice.call(arguments, 1, -1); + var hash = options.hash; + var controller = options.data.keywords.controller; + + // create a hash to pass along to registerAction + var action = { + eventName: hash.on || "click", + parameters: { + context: this, + options: options, + params: contexts + }, + view: options.data.view, + bubbles: hash.bubbles, + preventDefault: hash.preventDefault, + target: { options: options }, + withKeyCode: hash.withKeyCode, + boundProperty: options.types[0] === "ID" + }; + + if (hash.target) { + action.target.root = this; + action.target.target = hash.target; + } else if (controller) { + action.target.root = controller; + } + + var actionId = ActionHelper.registerAction(actionName, action, hash.allowedKeys); + return new SafeString('data-ember-action="' + actionId + '"'); + } + + __exports__.actionHelper = actionHelper; + }); +define("ember-routing-handlebars/helpers/link_to", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-runtime/system/lazy_load","ember-runtime/system/string","ember-runtime/system/object","ember-metal/keys","ember-views/system/utils","ember-views/views/component","ember-handlebars","ember-handlebars/helpers/view","ember-routing/system/router","ember-routing-handlebars/helpers/shared","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, Logger, Handlebars, warn, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var merge = __dependency4__["default"]; + var run = __dependency5__["default"]; + var computed = __dependency6__.computed; + + var onLoad = __dependency7__.onLoad; + var fmt = __dependency8__.fmt; + var EmberObject = __dependency9__["default"]; + var keys = __dependency10__["default"]; + var isSimpleClick = __dependency11__.isSimpleClick; + var EmberComponent = __dependency12__["default"]; + var EmberHandlebars = __dependency13__["default"]; + var viewHelper = __dependency14__.viewHelper; + var EmberRouter = __dependency15__["default"]; + var resolveParams = __dependency16__.resolveParams; + var resolvePaths = __dependency16__.resolvePaths; + var routeArgs = __dependency16__.routeArgs; + + /** + @module ember + @submodule ember-routing + */ + + var slice = [].slice; + + requireModule('ember-handlebars'); + + var numberOfContextsAcceptedByHandler = function(handler, handlerInfos) { + var req = 0; + for (var i = 0, l = handlerInfos.length; i < l; i++) { + req = req + handlerInfos[i].names.length; + if (handlerInfos[i].handler === handler) + break; + } + + return req; + }; + + var QueryParams = EmberObject.extend({ + values: null + }); + + function getResolvedPaths(options) { + + var types = options.options.types; + var data = options.options.data; + + return resolvePaths(options.context, options.params, { types: types, data: data }); + } + + /** + `Ember.LinkView` renders an element whose `click` event triggers a + transition of the application's instance of `Ember.Router` to + a supplied route by name. + + Instances of `LinkView` will most likely be created through + the `link-to` Handlebars helper, but properties of this class + can be overridden to customize application-wide behavior. + + @class LinkView + @namespace Ember + @extends Ember.View + @see {Handlebars.helpers.link-to} + **/ + var LinkView = Ember.LinkView = EmberComponent.extend({ + tagName: 'a', + + /** + @deprecated Use current-when instead. + @property currentWhen + */ + currentWhen: null, + + /** + Used to determine when this LinkView is active. + + @property currentWhen + */ + 'current-when': null, + + /** + Sets the `title` attribute of the `LinkView`'s HTML element. + + @property title + @default null + **/ + title: null, + + /** + Sets the `rel` attribute of the `LinkView`'s HTML element. + + @property rel + @default null + **/ + rel: null, + + /** + The CSS class to apply to `LinkView`'s element when its `active` + property is `true`. + + @property activeClass + @type String + @default active + **/ + activeClass: 'active', + + /** + The CSS class to apply to `LinkView`'s element when its `loading` + property is `true`. + + @property loadingClass + @type String + @default loading + **/ + loadingClass: 'loading', + + /** + The CSS class to apply to a `LinkView`'s element when its `disabled` + property is `true`. + + @property disabledClass + @type String + @default disabled + **/ + disabledClass: 'disabled', + _isDisabled: false, + + /** + Determines whether the `LinkView` will trigger routing via + the `replaceWith` routing strategy. + + @property replace + @type Boolean + @default false + **/ + replace: false, + + /** + By default the `{{link-to}}` helper will bind to the `href` and + `title` attributes. It's discourage that you override these defaults, + however you can push onto the array if needed. + + @property attributeBindings + @type Array | String + @default ['href', 'title', 'rel'] + **/ + attributeBindings: ['href', 'title', 'rel', 'tabindex'], + + /** + By default the `{{link-to}}` helper will bind to the `active`, `loading`, and + `disabled` classes. It is discouraged to override these directly. + + @property classNameBindings + @type Array + @default ['active', 'loading', 'disabled'] + **/ + classNameBindings: ['active', 'loading', 'disabled'], + + /** + By default the `{{link-to}}` helper responds to the `click` event. You + can override this globally by setting this property to your custom + event name. + + This is particularly useful on mobile when one wants to avoid the 300ms + click delay using some sort of custom `tap` event. + + @property eventName + @type String + @default click + */ + eventName: 'click', + + // this is doc'ed here so it shows up in the events + // section of the API documentation, which is where + // people will likely go looking for it. + /** + Triggers the `LinkView`'s routing behavior. If + `eventName` is changed to a value other than `click` + the routing behavior will trigger on that custom event + instead. + + @event click + **/ + + /** + An overridable method called when LinkView objects are instantiated. + + Example: + + ```javascript + App.MyLinkView = Ember.LinkView.extend({ + init: function() { + this._super(); + Ember.Logger.log('Event is ' + this.get('eventName')); + } + }); + ``` + + NOTE: If you do override `init` for a framework class like `Ember.View` or + `Ember.ArrayController`, be sure to call `this._super()` in your + `init` declaration! If you don't, Ember may not have an opportunity to + do important setup work, and you'll see strange behavior in your + application. + + @method init + */ + init: function() { + this._super.apply(this, arguments); + + + // Map desired event name to invoke function + var eventName = get(this, 'eventName'); + this.on(eventName, this, this._invoke); + }, + + /** + This method is invoked by observers installed during `init` that fire + whenever the params change + + @private + @method _paramsChanged + @since 1.3.0 + */ + _paramsChanged: function() { + this.notifyPropertyChange('resolvedParams'); + }, + + /** + This is called to setup observers that will trigger a rerender. + + @private + @method _setupPathObservers + @since 1.3.0 + **/ + _setupPathObservers: function(){ + var helperParameters = this.parameters; + var linkTextPath = helperParameters.options.linkTextPath; + var paths = getResolvedPaths(helperParameters); + var length = paths.length; + var path, i, normalizedPath; + + if (linkTextPath) { + normalizedPath = getNormalizedPath(linkTextPath, helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this.rerender); + } + + for(i=0; i < length; i++) { + path = paths[i]; + if (null === path) { + // A literal value was provided, not a path, so nothing to observe. + continue; + } + + normalizedPath = getNormalizedPath(path, helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged); + } + + var queryParamsObject = this.queryParamsObject; + if (queryParamsObject) { + var values = queryParamsObject.values; + + // Install observers for all of the hash options + // provided in the (query-params) subexpression. + for (var k in values) { + if (!values.hasOwnProperty(k)) { continue; } + + if (queryParamsObject.types[k] === 'ID') { + normalizedPath = getNormalizedPath(values[k], helperParameters); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged); + } + } + } + }, + + afterRender: function(){ + this._super.apply(this, arguments); + this._setupPathObservers(); + }, + + /** + + Accessed as a classname binding to apply the `LinkView`'s `disabledClass` + CSS `class` to the element when the link is disabled. + + When `true` interactions with the element will not trigger route changes. + @property disabled + */ + disabled: computed(function computeLinkViewDisabled(key, value) { + if (value !== undefined) { this.set('_isDisabled', value); } + + return value ? get(this, 'disabledClass') : false; + }), + + /** + Accessed as a classname binding to apply the `LinkView`'s `activeClass` + CSS `class` to the element when the link is active. + + A `LinkView` is considered active when its `currentWhen` property is `true` + or the application's current route is the route the `LinkView` would trigger + transitions into. + + The `currentWhen` property can match against multiple routes by separating + route names using the ` ` (space) character. + + @property active + **/ + active: computed('loadedParams', function computeLinkViewActive() { + if (get(this, 'loading')) { return false; } + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + var contexts = loadedParams.models; + var currentWhen = this['current-when'] || this.currentWhen; + var isCurrentWhenSpecified = Boolean(currentWhen); + currentWhen = currentWhen || loadedParams.targetRouteName; + + function isActiveForRoute(routeName) { + var handlers = router.router.recognizer.handlersFor(routeName); + var leafName = handlers[handlers.length-1].handler; + var maximumContexts = numberOfContextsAcceptedByHandler(routeName, handlers); + + // NOTE: any ugliness in the calculation of activeness is largely + // due to the fact that we support automatic normalizing of + // `resource` -> `resource.index`, even though there might be + // dynamic segments / query params defined on `resource.index` + // which complicates (and makes somewhat ambiguous) the calculation + // of activeness for links that link to `resource` instead of + // directly to `resource.index`. + + // if we don't have enough contexts revert back to full route name + // this is because the leaf route will use one of the contexts + if (contexts.length > maximumContexts) { + routeName = leafName; + } + + var args = routeArgs(routeName, contexts, null); + var isActive = router.isActive.apply(router, args); + if (!isActive) { return false; } + + var emptyQueryParams = Ember.isEmpty(Ember.keys(loadedParams.queryParams)); + + if (!isCurrentWhenSpecified && !emptyQueryParams && isActive) { + var visibleQueryParams = {}; + merge(visibleQueryParams, loadedParams.queryParams); + router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + isActive = shallowEqual(visibleQueryParams, router.router.state.queryParams); + } + + return isActive; + } + + + currentWhen = currentWhen.split(' '); + for (var i = 0, len = currentWhen.length; i < len; i++) { + if (isActiveForRoute(currentWhen[i])) { + return get(this, 'activeClass'); + } + } + }), + + /** + Accessed as a classname binding to apply the `LinkView`'s `loadingClass` + CSS `class` to the element when the link is loading. + + A `LinkView` is considered loading when it has at least one + parameter whose value is currently null or undefined. During + this time, clicking the link will perform no transition and + emit a warning that the link is still in a loading state. + + @property loading + **/ + loading: computed('loadedParams', function computeLinkViewLoading() { + if (!get(this, 'loadedParams')) { return get(this, 'loadingClass'); } + }), + + /** + Returns the application's main router from the container. + + @private + @property router + **/ + router: computed(function() { + var controller = get(this, 'controller'); + if (controller && controller.container) { + return controller.container.lookup('router:main'); + } + }), + + /** + Event handler that invokes the link, activating the associated route. + + @private + @method _invoke + @param {Event} event + */ + _invoke: function(event) { + if (!isSimpleClick(event)) { return true; } + + if (this.preventDefault !== false) { + + var targetAttribute = get(this, 'target'); + if (!targetAttribute || targetAttribute === '_self') { + event.preventDefault(); + } + } + + if (this.bubbles === false) { event.stopPropagation(); } + + if (get(this, '_isDisabled')) { return false; } + + if (get(this, 'loading')) { + Ember.Logger.warn("This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid."); + return false; + } + + + var targetAttribute2 = get(this, 'target'); + if (targetAttribute2 && targetAttribute2 !== '_self') { + return false; + } + + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + + var transition = router._doTransition(loadedParams.targetRouteName, loadedParams.models, loadedParams.queryParams); + if (get(this, 'replace')) { + transition.method('replace'); + } + + // Schedule eager URL update, but after we've given the transition + // a chance to synchronously redirect. + // We need to always generate the URL instead of using the href because + // the href will include any rootURL set, but the router expects a URL + // without it! Note that we don't use the first level router because it + // calls location.formatURL(), which also would add the rootURL! + var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, transition.state.queryParams); + var url = router.router.generate.apply(router.router, args); + + run.scheduleOnce('routerTransitions', this, this._eagerUpdateUrl, transition, url); + }, + + /** + @private + @method _eagerUpdateUrl + @param transition + @param href + */ + _eagerUpdateUrl: function(transition, href) { + if (!transition.isActive || !transition.urlMethod) { + // transition was aborted, already ran to completion, + // or it has a null url-updated method. + return; + } + + if (href.indexOf('#') === 0) { + href = href.slice(1); + } + + // Re-use the routerjs hooks set up by the Ember router. + var routerjs = get(this, 'router.router'); + if (transition.urlMethod === 'update') { + routerjs.updateURL(href); + } else if (transition.urlMethod === 'replace') { + routerjs.replaceURL(href); + } + + // Prevent later update url refire. + transition.method(null); + }, + + /** + Computed property that returns an array of the + resolved parameters passed to the `link-to` helper, + e.g.: + + ```hbs + {{link-to a b '123' c}} + ``` + + will generate a `resolvedParams` of: + + ```js + [aObject, bObject, '123', cObject] + ``` + + @private + @property + @return {Array} + */ + resolvedParams: computed('router.url', function() { + var parameters = this.parameters; + var options = parameters.options; + var types = options.types; + var data = options.data; + var targetRouteName, models; + var onlyQueryParamsSupplied = (parameters.params.length === 0); + + if (onlyQueryParamsSupplied) { + var appController = this.container.lookup('controller:application'); + targetRouteName = get(appController, 'currentRouteName'); + models = []; + } else { + models = resolveParams(parameters.context, parameters.params, { types: types, data: data }); + targetRouteName = models.shift(); + } + + var suppliedQueryParams = getResolvedQueryParams(this, targetRouteName); + + return { + targetRouteName: targetRouteName, + models: models, + queryParams: suppliedQueryParams + }; + }), + + /** + Computed property that returns the current route name, + dynamic segments, and query params. Returns falsy if + for null/undefined params to indicate that the link view + is still in a loading state. + + @private + @property + @return {Array} An array with the route name and any dynamic segments + **/ + loadedParams: computed('resolvedParams', function computeLinkViewRouteArgs() { + var router = get(this, 'router'); + if (!router) { return; } + + var resolvedParams = get(this, 'resolvedParams'); + var namedRoute = resolvedParams.targetRouteName; + + if (!namedRoute) { return; } + + + if (!paramsAreLoaded(resolvedParams.models)) { return; } + + return resolvedParams; + }), + + queryParamsObject: null, + + /** + Sets the element's `href` attribute to the url for + the `LinkView`'s targeted route. + + If the `LinkView`'s `tagName` is changed to a value other + than `a`, this property will be ignored. + + @property href + **/ + href: computed('loadedParams', function computeLinkViewHref() { + if (get(this, 'tagName') !== 'a') { return; } + + var router = get(this, 'router'); + var loadedParams = get(this, 'loadedParams'); + + if (!loadedParams) { + return get(this, 'loadingHref'); + } + + var visibleQueryParams = {}; + merge(visibleQueryParams, loadedParams.queryParams); + router._prepareQueryParams(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + + var args = routeArgs(loadedParams.targetRouteName, loadedParams.models, visibleQueryParams); + var result = router.generate.apply(router, args); + return result; + }), + + /** + The default href value to use while a link-to is loading. + Only applies when tagName is 'a' + + @property loadingHref + @type String + @default # + */ + loadingHref: '#' + }); + + LinkView.toString = function() { return "LinkView"; }; + + + LinkView.reopen({ + attributeBindings: ['target'], + + /** + Sets the `target` attribute of the `LinkView`'s anchor element. + + @property target + @default null + **/ + target: null + }); + + + /** + The `{{link-to}}` helper renders a link to the supplied + `routeName` passing an optionally supplied model to the + route as its `model` context of the route. The block + for `{{link-to}}` becomes the innerHTML of the rendered + element: + + ```handlebars + {{#link-to 'photoGallery'}} + Great Hamster Photos + {{/link-to}} + ``` + + ```html + + Great Hamster Photos + + ``` + + ### Supplying a tagName + By default `{{link-to}}` renders an `` element. This can + be overridden for a single use of `{{link-to}}` by supplying + a `tagName` option: + + ```handlebars + {{#link-to 'photoGallery' tagName="li"}} + Great Hamster Photos + {{/link-to}} + ``` + + ```html +
  • + Great Hamster Photos +
  • + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Disabling the `link-to` helper + By default `{{link-to}}` is enabled. + any passed value to `disabled` helper property will disable the `link-to` helper. + + static use: the `disabled` option: + + ```handlebars + {{#link-to 'photoGallery' disabled=true}} + Great Hamster Photos + {{/link-to}} + ``` + + dynamic use: the `disabledWhen` option: + + ```handlebars + {{#link-to 'photoGallery' disabledWhen=controller.someProperty}} + Great Hamster Photos + {{/link-to}} + ``` + + any passed value to `disabled` will disable it except `undefined`. + to ensure that only `true` disable the `link-to` helper you can + override the global behaviour of `Ember.LinkView`. + + ```javascript + Ember.LinkView.reopen({ + disabled: Ember.computed(function(key, value) { + if (value !== undefined) { + this.set('_isDisabled', value === true); + } + return value === true ? get(this, 'disabledClass') : false; + }) + }); + ``` + + see "Overriding Application-wide Defaults" for more. + + ### Handling `href` + `{{link-to}}` will use your application's Router to + fill the element's `href` property with a url that + matches the path to the supplied `routeName` for your + routers's configured `Location` scheme, which defaults + to Ember.HashLocation. + + ### Handling current route + `{{link-to}}` will apply a CSS class name of 'active' + when the application's current route matches + the supplied routeName. For example, if the application's + current route is 'photoGallery.recent' the following + use of `{{link-to}}`: + + ```handlebars + {{#link-to 'photoGallery.recent'}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + will result in + + ```html +
    + Great Hamster Photos + + ``` + + The CSS class name used for active classes can be customized + for a single use of `{{link-to}}` by passing an `activeClass` + option: + + ```handlebars + {{#link-to 'photoGallery.recent' activeClass="current-url"}} + Great Hamster Photos from the last week + {{/link-to}} + ``` + + ```html + + Great Hamster Photos + + ``` + + To override this option for your entire application, see + "Overriding Application-wide Defaults". + + ### Supplying a model + An optional model argument can be used for routes whose + paths contain dynamic segments. This argument will become + the model context of the linked route: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhoto}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + ### Supplying multiple models + For deep-linking to route paths that contain multiple + dynamic segments, multiple model arguments can be used. + As the router transitions through the route path, each + supplied model argument will become the context for the + route with the dynamic segments: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}, function() { + this.route("comment", {path: "comments/:comment_id"}); + }); + }); + ``` + This argument will become the model context of the linked route: + + ```handlebars + {{#link-to 'photoGallery.comment' aPhoto comment}} + {{comment.body}} + {{/link-to}} + ``` + + ```html + + A+++ would snuggle again. + + ``` + + ### Supplying an explicit dynamic segment value + If you don't have a model object available to pass to `{{link-to}}`, + an optional string or integer argument can be passed for routes whose + paths contain dynamic segments. This argument will become the value + of the dynamic segment: + + ```javascript + App.Router.map(function() { + this.resource("photoGallery", {path: "hamster-photos/:photo_id"}); + }); + ``` + + ```handlebars + {{#link-to 'photoGallery' aPhotoId}} + {{aPhoto.title}} + {{/link-to}} + ``` + + ```html + + Tomster + + ``` + + When transitioning into the linked route, the `model` hook will + be triggered with parameters including this passed identifier. + + ### Allowing Default Action + + By default the `{{link-to}}` helper prevents the default browser action + by calling `preventDefault()` as this sort of action bubbling is normally + handled internally and we do not want to take the browser to a new URL (for + example). + + If you need to override this behavior specify `preventDefault=false` in + your template: + + ```handlebars + {{#link-to 'photoGallery' aPhotoId preventDefault=false}} + {{aPhotoId.title}} + {{/link-to}} + ``` + + ### Overriding attributes + You can override any given property of the Ember.LinkView + that is generated by the `{{link-to}}` helper by passing + key/value pairs, like so: + + ```handlebars + {{#link-to aPhoto tagName='li' title='Following this link will change your life' classNames='pic sweet'}} + Uh-mazing! + {{/link-to}} + ``` + + See [Ember.LinkView](/api/classes/Ember.LinkView.html) for a + complete list of overrideable properties. Be sure to also + check out inherited properties of `LinkView`. + + ### Overriding Application-wide Defaults + ``{{link-to}}`` creates an instance of Ember.LinkView + for rendering. To override options for your entire + application, reopen Ember.LinkView and supply the + desired values: + + ``` javascript + Ember.LinkView.reopen({ + activeClass: "is-active", + tagName: 'li' + }) + ``` + + It is also possible to override the default event in + this manner: + + ``` javascript + Ember.LinkView.reopen({ + eventName: 'customEventName' + }); + ``` + + @method link-to + @for Ember.Handlebars.helpers + @param {String} routeName + @param {Object} [context]* + @param [options] {Object} Handlebars key/value pairs of options, you can override any property of Ember.LinkView + @return {String} HTML string + @see {Ember.LinkView} + */ + function linkToHelper(name) { + var options = slice.call(arguments, -1)[0]; + var params = slice.call(arguments, 0, -1); + var hash = options.hash; + + + if (params[params.length - 1] instanceof QueryParams) { + hash.queryParamsObject = params.pop(); + } + + hash.disabledBinding = hash.disabledWhen; + + if (!options.fn) { + var linkTitle = params.shift(); + var linkType = options.types.shift(); + var context = this; + if (linkType === 'ID') { + options.linkTextPath = linkTitle; + options.fn = function() { + return EmberHandlebars.getEscaped(context, linkTitle, options); + }; + } else { + options.fn = function() { + return linkTitle; + }; + } + } + + hash.parameters = { + context: this, + options: options, + params: params + }; + + options.helperName = options.helperName || 'link-to'; + + return viewHelper.call(this, LinkView, options); + } + + /** + @method query-params + @for Ember.Handlebars.helpers + @param {Object} hash takes a hash of query parameters + @return {String} HTML string + */ + function queryParamsHelper(options) { + + return QueryParams.create({ + values: options.hash, + types: options.hashTypes + }); + } + + __exports__.queryParamsHelper = queryParamsHelper;/** + See [link-to](/api/classes/Ember.Handlebars.helpers.html#method_link-to) + + @method linkTo + @for Ember.Handlebars.helpers + @deprecated + @param {String} routeName + @param {Object} [context]* + @return {String} HTML string + */ + function deprecatedLinkToHelper() { + return linkToHelper.apply(this, arguments); + } + + function getResolvedQueryParams(linkView, targetRouteName) { + var helperParameters = linkView.parameters; + var queryParamsObject = linkView.queryParamsObject; + var resolvedQueryParams = {}; + + if (!queryParamsObject) { return resolvedQueryParams; } + var rawParams = queryParamsObject.values; + + for (var key in rawParams) { + if (!rawParams.hasOwnProperty(key)) { continue; } + + var value = rawParams[key]; + var type = queryParamsObject.types[key]; + + if (type === 'ID') { + var normalizedPath = getNormalizedPath(value, helperParameters); + value = EmberHandlebars.get(normalizedPath.root, normalizedPath.path, helperParameters.options); + } + resolvedQueryParams[key] = value; + } + return resolvedQueryParams; + } + + function getNormalizedPath(path, helperParameters) { + return EmberHandlebars.normalizePath(helperParameters.context, path, helperParameters.options.data); + } + + function paramsAreLoaded(params) { + for (var i = 0, len = params.length; i < len; ++i) { + var param = params[i]; + if (param === null || typeof param === 'undefined') { + return false; + } + } + return true; + } + + function shallowEqual(a, b) { + var k; + for (k in a) { + if (a.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + for (k in b) { + if (b.hasOwnProperty(k) && a[k] !== b[k]) { return false; } + } + return true; + } + + __exports__.LinkView = LinkView; + __exports__.deprecatedLinkToHelper = deprecatedLinkToHelper; + __exports__.linkToHelper = linkToHelper; + }); +define("ember-routing-handlebars/helpers/outlet", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-views/views/container_view","ember-handlebars/views/metamorph_view","ember-handlebars/helpers/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var onLoad = __dependency4__.onLoad; + var ContainerView = __dependency5__["default"]; + var _Metamorph = __dependency6__._Metamorph; + var viewHelper = __dependency7__.viewHelper; + + /** + @module ember + @submodule ember-routing + */ + + /** + @module ember + @submodule ember-routing + */ + + var OutletView = ContainerView.extend(_Metamorph); + __exports__.OutletView = OutletView; + /** + The `outlet` helper is a placeholder that the router will fill in with + the appropriate template based on the current state of the application. + + ``` handlebars + {{outlet}} + ``` + + By default, a template based on Ember's naming conventions will be rendered + into the `outlet` (e.g. `App.PostsRoute` will render the `posts` template). + + You can render a different template by using the `render()` method in the + route's `renderTemplate` hook. The following will render the `favoritePost` + template into the `outlet`. + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost'); + } + }); + ``` + + You can create custom named outlets for more control. + + ``` handlebars + {{outlet 'favoritePost'}} + {{outlet 'posts'}} + ``` + + Then you can define what template is rendered into each outlet in your + route. + + + ``` javascript + App.PostsRoute = Ember.Route.extend({ + renderTemplate: function() { + this.render('favoritePost', { outlet: 'favoritePost' }); + this.render('posts', { outlet: 'posts' }); + } + }); + ``` + + You can specify the view that the outlet uses to contain and manage the + templates rendered into it. + + ``` handlebars + {{outlet view='sectionContainer'}} + ``` + + ``` javascript + App.SectionContainer = Ember.ContainerView.extend({ + tagName: 'section', + classNames: ['special'] + }); + ``` + + @method outlet + @for Ember.Handlebars.helpers + @param {String} property the property on the controller + that holds the view for this outlet + @return {String} HTML string + */ + function outletHelper(property, options) { + var outletSource; + var container; + var viewName; + var viewClass; + var viewFullName; + + if (property && property.data && property.data.isRenderData) { + options = property; + property = 'main'; + } + + container = options.data.view.container; + + outletSource = options.data.view; + while (!outletSource.get('template.isTop')) { + outletSource = outletSource.get('_parentView'); + } + + // provide controller override + viewName = options.hash.view; + + if (viewName) { + viewFullName = 'view:' + viewName; + } + + viewClass = viewName ? container.lookupFactory(viewFullName) : options.hash.viewClass || OutletView; + + options.data.view.set('outletSource', outletSource); + options.hash.currentViewBinding = '_view.outletSource._outlets.' + property; + + options.helperName = options.helperName || 'outlet'; + + return viewHelper.call(this, viewClass, options); + } + + __exports__.outletHelper = outletHelper; + }); +define("ember-routing-handlebars/helpers/render", + ["ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/string","ember-routing/system/generate_controller","ember-handlebars/ext","ember-handlebars/helpers/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // assert, deprecate + var EmberError = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var camelize = __dependency5__.camelize; + var generateControllerFactory = __dependency6__.generateControllerFactory; + var generateController = __dependency6__["default"]; + var handlebarsGet = __dependency7__.handlebarsGet; + var ViewHelper = __dependency8__.ViewHelper; + + + /** + @module ember + @submodule ember-routing + */ + + /** + Calling ``{{render}}`` from within a template will insert another + template that matches the provided name. The inserted template will + access its properties on its own controller (rather than the controller + of the parent template). + + If a view class with the same name exists, the view class also will be used. + + Note: A given controller may only be used *once* in your app in this manner. + A singleton instance of the controller will be created for you. + + Example: + + ```javascript + App.NavigationController = Ember.Controller.extend({ + who: "world" + }); + ``` + + ```handlebars + + Hello, {{who}}. + ``` + + ```handelbars + +

    My great app

    + {{render "navigation"}} + ``` + + ```html +

    My great app

    +
    + Hello, world. +
    + ``` + + Optionally you may provide a second argument: a property path + that will be bound to the `model` property of the controller. + + If a `model` property path is specified, then a new instance of the + controller will be created and `{{render}}` can be used multiple times + with the same name. + + For example if you had this `author` template. + + ```handlebars +
    + Written by {{firstName}} {{lastName}}. + Total Posts: {{postCount}} +
    + ``` + + You could render it inside the `post` template using the `render` helper. + + ```handlebars +
    +

    {{title}}

    +
    {{body}}
    + {{render "author" author}} +
    + ``` + + @method render + @for Ember.Handlebars.helpers + @param {String} name + @param {Object?} contextString + @param {Hash} options + @return {String} HTML string + */ + __exports__["default"] = function renderHelper(name, contextString, options) { + var length = arguments.length; + var contextProvided = length === 3; + var container, router, controller, view, context, lookupOptions; + + container = (options || contextString).data.keywords.controller.container; + router = container.lookup('router:main'); + + if (length === 2) { + // use the singleton controller + options = contextString; + contextString = undefined; + } else if (length === 3) { + // create a new controller + context = handlebarsGet(options.contexts[1], contextString, options); + } else { + throw new EmberError("You must pass a templateName to render"); + } + + + // # legacy namespace + name = name.replace(/\//g, '.'); + // \ legacy slash as namespace support + + + view = container.lookup('view:' + name) || container.lookup('view:default'); + + // provide controller override + var controllerName = options.hash.controller || name; + var controllerFullName = 'controller:' + controllerName; + + if (options.hash.controller) { + } + + var parentController = options.data.keywords.controller; + + // choose name + if (length > 2) { + var factory = container.lookupFactory(controllerFullName) || + generateControllerFactory(container, controllerName, context); + + controller = factory.create({ + model: context, + parentController: parentController, + target: parentController + }); + + view.one('willDestroyElement', function() { + controller.destroy(); + }); + } else { + controller = container.lookup(controllerFullName) || + generateController(container, controllerName); + + controller.setProperties({ + target: parentController, + parentController: parentController + }); + } + + var root = options.contexts[1]; + + if (root) { + view.registerObserver(root, contextString, function() { + controller.set('model', handlebarsGet(root, contextString, options)); + }); + } + + options.hash.viewName = camelize(name); + + var templateName = 'template:' + name; + options.hash.template = container.lookup(templateName); + + options.hash.controller = controller; + + if (router && !context) { + router._connectActiveView(name, view); + } + + options.helperName = options.helperName || ('render "' + name + '"'); + + ViewHelper.instanceHelper(this, view, options); + } + }); +define("ember-routing-handlebars/helpers/shared", + ["ember-metal/property_get","ember-metal/array","ember-runtime/mixins/controller","ember-handlebars/ext","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var map = __dependency2__.map; + var ControllerMixin = __dependency3__["default"]; + var handlebarsResolve = __dependency4__.resolveParams; + var handlebarsGet = __dependency4__.handlebarsGet; + var typeOf = __dependency5__.typeOf; + var get = __dependency1__.get; + + function routeArgs(targetRouteName, models, queryParams) { + var args = []; + if (typeOf(targetRouteName) === 'string') { + args.push('' + targetRouteName); + } + args.push.apply(args, models); + args.push({ queryParams: queryParams }); + return args; + } + + __exports__.routeArgs = routeArgs;function getActiveTargetName(router) { + var handlerInfos = router.activeTransition ? + router.activeTransition.state.handlerInfos : + router.state.handlerInfos; + return handlerInfos[handlerInfos.length - 1].name; + } + + __exports__.getActiveTargetName = getActiveTargetName;function resolveParams(context, params, options) { + return map.call(resolvePaths(context, params, options), function(path, i) { + if (null === path) { + // Param was string/number, not a path, so just return raw string/number. + return params[i]; + } else { + return handlebarsGet(context, path, options); + } + }); + } + + __exports__.resolveParams = resolveParams;function stashParamNames(router, handlerInfos) { + if (handlerInfos._namesStashed) { return; } + + // This helper exists because router.js/route-recognizer.js awkwardly + // keeps separate a handlerInfo's list of parameter names depending + // on whether a URL transition or named transition is happening. + // Hopefully we can remove this in the future. + var targetRouteName = handlerInfos[handlerInfos.length-1].name; + var recogHandlers = router.router.recognizer.handlersFor(targetRouteName); + var dynamicParent = null; + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + var names = recogHandlers[i].names; + + if (names.length) { + dynamicParent = handlerInfo; + } + + handlerInfo._names = names; + + var route = handlerInfo.handler; + route._stashNames(handlerInfo, dynamicParent); + } + + handlerInfos._namesStashed = true; + } + + __exports__.stashParamNames = stashParamNames;function resolvePaths(context, params, options) { + var resolved = handlebarsResolve(context, params, options); + var types = options.types; + + return map.call(resolved, function(object, i) { + if (types[i] === 'ID') { + return unwrap(object, params[i]); + } else { + return null; + } + }); + + function unwrap(object, path) { + if (path === 'controller') { return path; } + + if (ControllerMixin.detect(object)) { + return unwrap(get(object, 'model'), path ? path + '.model' : 'model'); + } else { + return path; + } + } + } + + __exports__.resolvePaths = resolvePaths; + }); +define("ember-routing", + ["ember-handlebars","ember-metal/core","ember-routing/ext/run_loop","ember-routing/ext/controller","ember-routing/ext/view","ember-routing/location/api","ember-routing/location/none_location","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/system/generate_controller","ember-routing/system/controller_for","ember-routing/system/dsl","ember-routing/system/router","ember-routing/system/route","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { + "use strict"; + /** + Ember Routing + + @module ember + @submodule ember-routing + @requires ember-views + */ + + var EmberHandlebars = __dependency1__["default"]; + var Ember = __dependency2__["default"]; + + // ES6TODO: Cleanup modules with side-effects below + + var EmberLocation = __dependency6__["default"]; + var NoneLocation = __dependency7__["default"]; + var HashLocation = __dependency8__["default"]; + var HistoryLocation = __dependency9__["default"]; + var AutoLocation = __dependency10__["default"]; + + var generateControllerFactory = __dependency11__.generateControllerFactory; + var generateController = __dependency11__["default"]; + var controllerFor = __dependency12__["default"]; + var RouterDSL = __dependency13__["default"]; + var Router = __dependency14__["default"]; + var Route = __dependency15__["default"]; + + Ember.Location = EmberLocation; + Ember.AutoLocation = AutoLocation; + Ember.HashLocation = HashLocation; + Ember.HistoryLocation = HistoryLocation; + Ember.NoneLocation = NoneLocation; + + Ember.controllerFor = controllerFor; + Ember.generateControllerFactory = generateControllerFactory; + Ember.generateController = generateController; + Ember.RouterDSL = RouterDSL; + Ember.Router = Router; + Ember.Route = Route; + + __exports__["default"] = Ember; + }); +define("ember-routing/ext/controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/computed","ember-metal/utils","ember-metal/merge","ember-metal/enumerable_utils","ember-runtime/mixins/controller","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, deprecate + var get = __dependency2__.get; + var set = __dependency3__.set; + var computed = __dependency4__.computed; + var typeOf = __dependency5__.typeOf; + var meta = __dependency5__.meta; + var merge = __dependency6__["default"]; + var map = __dependency7__.map; + + var ControllerMixin = __dependency8__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + ControllerMixin.reopen({ + concatenatedProperties: ['queryParams', '_pCacheMeta'], + + init: function() { + this._super.apply(this, arguments); + listenForQueryParamChanges(this); + }, + + /** + @property queryParams + @public + */ + queryParams: null, + + /** + @property _qpDelegate + @private + */ + _qpDelegate: null, + + /** + @property _normalizedQueryParams + @private + */ + _normalizedQueryParams: computed(function() { + var m = meta(this); + if (m.proto !== this) { + return get(m.proto, '_normalizedQueryParams'); + } + + var queryParams = get(this, 'queryParams'); + if (queryParams._qpMap) { + return queryParams._qpMap; + } + + var qpMap = queryParams._qpMap = {}; + + for (var i = 0, len = queryParams.length; i < len; ++i) { + accumulateQueryParamDescriptors(queryParams[i], qpMap); + } + + return qpMap; + }), + + /** + @property _cacheMeta + @private + */ + _cacheMeta: computed(function() { + var m = meta(this); + if (m.proto !== this) { + return get(m.proto, '_cacheMeta'); + } + + var cacheMeta = {}; + var qpMap = get(this, '_normalizedQueryParams'); + for (var prop in qpMap) { + if (!qpMap.hasOwnProperty(prop)) { continue; } + + var qp = qpMap[prop]; + var scope = qp.scope; + var parts; + + if (scope === 'controller') { + parts = []; + } + + cacheMeta[prop] = { + parts: parts, // provided by route if 'model' scope + values: null, // provided by route + scope: scope, + prefix: "", + def: get(this, prop) + }; + } + + return cacheMeta; + }), + + /** + @method _updateCacheParams + @private + */ + _updateCacheParams: function(params) { + var cacheMeta = get(this, '_cacheMeta'); + for (var prop in cacheMeta) { + if (!cacheMeta.hasOwnProperty(prop)) { continue; } + var propMeta = cacheMeta[prop]; + propMeta.values = params; + + var cacheKey = this._calculateCacheKey(propMeta.prefix, propMeta.parts, propMeta.values); + var cache = this._bucketCache; + + if (cache) { + var value = cache.lookup(cacheKey, prop, propMeta.def); + set(this, prop, value); + } + } + }, + + /** + @method _qpChanged + @private + */ + _qpChanged: function(controller, _prop) { + var prop = _prop.substr(0, _prop.length-3); + var cacheMeta = get(controller, '_cacheMeta'); + var propCache = cacheMeta[prop]; + var cacheKey = controller._calculateCacheKey(propCache.prefix || "", propCache.parts, propCache.values); + var value = get(controller, prop); + + // 1. Update model-dep cache + var cache = this._bucketCache; + if (cache) { + controller._bucketCache.stash(cacheKey, prop, value); + } + + // 2. Notify a delegate (e.g. to fire a qp transition) + var delegate = controller._qpDelegate; + if (delegate) { + delegate(controller, prop); + } + }, + + /** + @method _calculateCacheKey + @private + */ + _calculateCacheKey: function(prefix, _parts, values) { + var parts = _parts || [], suffixes = ""; + for (var i = 0, len = parts.length; i < len; ++i) { + var part = parts[i]; + var value = get(values, part); + suffixes += "::" + part + ":" + value; + } + return prefix + suffixes.replace(ALL_PERIODS_REGEX, '-'); + }, + + /** + Transition the application into another route. The route may + be either a single route or route path: + + ```javascript + aController.transitionToRoute('blogPosts'); + aController.transitionToRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.transitionToRoute('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + aController.transitionToRoute('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + aController.transitionToRoute('blogComment', aPost, aComment); + aController.transitionToRoute('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + aController.transitionToRoute('/'); + aController.transitionToRoute('/blog/post/1/comment/13'); + ``` + + See also [replaceRoute](/api/classes/Ember.ControllerMixin.html#method_replaceRoute). + + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used + while transitioning to the route. + @for Ember.ControllerMixin + @method transitionToRoute + */ + transitionToRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'); + var method = target.transitionToRoute || target.transitionTo; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method transitionTo + */ + transitionTo: function() { + return this.transitionToRoute.apply(this, arguments); + }, + + /** + Transition into another route while replacing the current URL, if possible. + This will replace the current history entry instead of adding a new one. + Beside that, it is identical to `transitionToRoute` in all other respects. + + ```javascript + aController.replaceRoute('blogPosts'); + aController.replaceRoute('blogPosts.recentEntries'); + ``` + + Optionally supply a model for the route in question. The model + will be serialized into the URL using the `serialize` hook of + the route: + + ```javascript + aController.replaceRoute('blogPost', aPost); + ``` + + If a literal is passed (such as a number or a string), it will + be treated as an identifier instead. In this case, the `model` + hook of the route will be triggered: + + ```javascript + aController.replaceRoute('blogPost', 1); + ``` + + Multiple models will be applied last to first recursively up the + resource tree. + + ```javascript + App.Router.map(function() { + this.resource('blogPost', {path:':blogPostId'}, function(){ + this.resource('blogComment', {path: ':blogCommentId'}); + }); + }); + + aController.replaceRoute('blogComment', aPost, aComment); + aController.replaceRoute('blogComment', 1, 13); + ``` + + It is also possible to pass a URL (a string that starts with a + `/`). This is intended for testing and debugging purposes and + should rarely be used in production code. + + ```javascript + aController.replaceRoute('/'); + aController.replaceRoute('/blog/post/1/comment/13'); + ``` + + @param {String} name the name of the route or a URL + @param {...Object} models the model(s) or identifier(s) to be used + while transitioning to the route. + @for Ember.ControllerMixin + @method replaceRoute + */ + replaceRoute: function() { + // target may be either another controller or a router + var target = get(this, 'target'); + var method = target.replaceRoute || target.replaceWith; + return method.apply(target, arguments); + }, + + /** + @deprecated + @for Ember.ControllerMixin + @method replaceWith + */ + replaceWith: function() { + return this.replaceRoute.apply(this, arguments); + } + }); + + var ALL_PERIODS_REGEX = /\./g; + + function accumulateQueryParamDescriptors(_desc, accum) { + var desc = _desc, tmp; + if (typeOf(desc) === 'string') { + tmp = {}; + tmp[desc] = { as: null }; + desc = tmp; + } + + for (var key in desc) { + if (!desc.hasOwnProperty(key)) { return; } + + var singleDesc = desc[key]; + if (typeOf(singleDesc) === 'string') { + singleDesc = { as: singleDesc }; + } + + tmp = accum[key] || { as: null, scope: 'model' }; + merge(tmp, singleDesc); + + accum[key] = tmp; + } + } + + function listenForQueryParamChanges(controller) { + var qpMap = get(controller, '_normalizedQueryParams'); + for (var prop in qpMap) { + if (!qpMap.hasOwnProperty(prop)) { continue; } + controller.addObserver(prop + '.[]', controller, controller._qpChanged); + } + } + + + __exports__["default"] = ControllerMixin; + }); +define("ember-routing/ext/run_loop", + ["ember-metal/run_loop"], + function(__dependency1__) { + "use strict"; + var run = __dependency1__["default"]; + + /** + @module ember + @submodule ember-views + */ + + // Add a new named queue after the 'actions' queue (where RSVP promises + // resolve), which is used in router transitions to prevent unnecessary + // loading state entry if all context promises resolve on the + // 'actions' queue first. + + var queues = run.queues; + run._addQueue('routerTransitions', 'actions'); + }); +define("ember-routing/ext/view", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-views/views/view","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var run = __dependency3__["default"]; + var EmberView = __dependency4__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + EmberView.reopen({ + + /** + Sets the private `_outlets` object on the view. + + @method init + */ + init: function() { + set(this, '_outlets', {}); + this._super(); + }, + + /** + Manually fill any of a view's `{{outlet}}` areas with the + supplied view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // The html for myView now looks like: + //
    Child view:
    + + var FooView = Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + }); + var fooView = FooView.create(); + myView.connectOutlet('main', fooView); + // The html for myView now looks like: + //
    Child view: + //

    Foo

    + //
    + ``` + @method connectOutlet + @param {String} outletName A unique name for the outlet + @param {Object} view An Ember.View + */ + connectOutlet: function(outletName, view) { + if (this._pendingDisconnections) { + delete this._pendingDisconnections[outletName]; + } + + if (this._hasEquivalentView(outletName, view)) { + view.destroy(); + return; + } + + var outlets = get(this, '_outlets'); + var container = get(this, 'container'); + var router = container && container.lookup('router:main'); + var renderedName = get(view, 'renderedName'); + + set(outlets, outletName, view); + + if (router && renderedName) { + router._connectActiveView(renderedName, view); + } + }, + + /** + Determines if the view has already been created by checking if + the view has the same constructor, template, and context as the + view in the `_outlets` object. + + @private + @method _hasEquivalentView + @param {String} outletName The name of the outlet we are checking + @param {Object} view An Ember.View + @return {Boolean} + */ + _hasEquivalentView: function(outletName, view) { + var existingView = get(this, '_outlets.'+outletName); + return existingView && + existingView.constructor === view.constructor && + existingView.get('template') === view.get('template') && + existingView.get('context') === view.get('context'); + }, + + /** + Removes an outlet from the view. + + Example + + ```javascript + var MyView = Ember.View.extend({ + template: Ember.Handlebars.compile('Child view: {{outlet "main"}} ') + }); + var myView = MyView.create(); + myView.appendTo('body'); + // myView's html: + //
    Child view:
    + + var FooView = Ember.View.extend({ + template: Ember.Handlebars.compile('

    Foo

    ') + }); + var fooView = FooView.create(); + myView.connectOutlet('main', fooView); + // myView's html: + //
    Child view: + //

    Foo

    + //
    + + myView.disconnectOutlet('main'); + // myView's html: + //
    Child view:
    + ``` + + @method disconnectOutlet + @param {String} outletName The name of the outlet to be removed + */ + disconnectOutlet: function(outletName) { + if (!this._pendingDisconnections) { + this._pendingDisconnections = {}; + } + this._pendingDisconnections[outletName] = true; + run.once(this, '_finishDisconnections'); + }, + + /** + Gets an outlet that is pending disconnection and then + nullifys the object on the `_outlet` object. + + @private + @method _finishDisconnections + */ + _finishDisconnections: function() { + if (this.isDestroyed) return; // _outlets will be gone anyway + var outlets = get(this, '_outlets'); + var pendingDisconnections = this._pendingDisconnections; + this._pendingDisconnections = null; + + for (var outletName in pendingDisconnections) { + set(outlets, outletName, null); + } + } + }); + + __exports__["default"] = EmberView; + }); +define("ember-routing/location/api", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // deprecate, assert + var get = __dependency2__.get; + var set = __dependency3__.set; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.Location returns an instance of the correct implementation of + the `location` API. + + ## Implementations + + You can pass an implementation name (`hash`, `history`, `none`) to force a + particular implementation to be used in your application. + + ### HashLocation + + Using `HashLocation` results in URLs with a `#` (hash sign) separating the + server side URL portion of the URL from the portion that is used by Ember. + This relies upon the `hashchange` event existing in the browser. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'hash' + }); + ``` + + This will result in a posts.new url of `/#/posts/new`. + + ### HistoryLocation + + Using `HistoryLocation` results in URLs that are indistinguishable from a + standard URL. This relies upon the browser's `history` API. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'history' + }); + ``` + + This will result in a posts.new url of `/posts/new`. + + Keep in mind that your server must serve the Ember app at all the routes you + define. + + ### AutoLocation + + Using `AutoLocation`, the router will use the best Location class supported by + the browser it is running in. + + Browsers that support the `history` API will use `HistoryLocation`, those that + do not, but still support the `hashchange` event will use `HashLocation`, and + in the rare case neither is supported will use `NoneLocation`. + + Example: + + ```javascript + App.Router.map(function() { + this.resource('posts', function() { + this.route('new'); + }); + }); + + App.Router.reopen({ + location: 'auto' + }); + ``` + + This will result in a posts.new url of `/posts/new` for modern browsers that + support the `history` api or `/#/posts/new` for older ones, like Internet + Explorer 9 and below. + + When a user visits a link to your application, they will be automatically + upgraded or downgraded to the appropriate `Location` class, with the URL + transformed accordingly, if needed. + + Keep in mind that since some of your users will use `HistoryLocation`, your + server must serve the Ember app at all the routes you define. + + ### NoneLocation + + Using `NoneLocation` causes Ember to not store the applications URL state + in the actual URL. This is generally used for testing purposes, and is one + of the changes made when calling `App.setupForTesting()`. + + ## Location API + + Each location implementation must provide the following methods: + + * implementation: returns the string name used to reference the implementation. + * getURL: returns the current URL. + * setURL(path): sets the current URL. + * replaceURL(path): replace the current URL (optional). + * onUpdateURL(callback): triggers the callback when the URL changes. + * formatURL(url): formats `url` to be placed into `href` attribute. + + Calling setURL or replaceURL will not trigger onUpdateURL callbacks. + + @class Location + @namespace Ember + @static + */ + __exports__["default"] = { + /** + This is deprecated in favor of using the container to lookup the location + implementation as desired. + + For example: + + ```javascript + // Given a location registered as follows: + container.register('location:history-test', HistoryTestLocation); + + // You could create a new instance via: + container.lookup('location:history-test'); + ``` + + @method create + @param {Object} options + @return {Object} an instance of an implementation of the `location` API + @deprecated Use the container to lookup the location implementation that you + need. + */ + create: function(options) { + var implementation = options && options.implementation; + + var implementationClass = this.implementations[implementation]; + + return implementationClass.create.apply(implementationClass, arguments); + }, + + /** + This is deprecated in favor of using the container to register the + location implementation as desired. + + Example: + + ```javascript + Application.initializer({ + name: "history-test-location", + + initialize: function(container, application) { + application.register('location:history-test', HistoryTestLocation); + } + }); + ``` + + @method registerImplementation + @param {String} name + @param {Object} implementation of the `location` API + @deprecated Register your custom location implementation with the + container directly. + */ + registerImplementation: function(name, implementation) { + + this.implementations[name] = implementation; + }, + + implementations: {}, + _location: window.location, + + /** + Returns the current `location.hash` by parsing location.href since browsers + inconsistently URL-decode `location.hash`. + + https://bugzilla.mozilla.org/show_bug.cgi?id=483304 + + @private + @method getHash + @since 1.4.0 + */ + _getHash: function () { + // AutoLocation has it at _location, HashLocation at .location. + // Being nice and not changing + var href = (this._location || this.location).href; + var hashIndex = href.indexOf('#'); + + if (hashIndex === -1) { + return ''; + } else { + return href.substr(hashIndex); + } + } + }; + }); +define("ember-routing/location/auto_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-routing/location/api","ember-routing/location/history_location","ember-routing/location/hash_location","ember-routing/location/none_location","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES + var get = __dependency2__.get; + var set = __dependency3__.set; + + var EmberLocation = __dependency4__["default"]; + var HistoryLocation = __dependency5__["default"]; + var HashLocation = __dependency6__["default"]; + var NoneLocation = __dependency7__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.AutoLocation will select the best location option based off browser + support with the priority order: history, hash, none. + + Clean pushState paths accessed by hashchange-only browsers will be redirected + to the hash-equivalent and vice versa so future transitions are consistent. + + Keep in mind that since some of your users will use `HistoryLocation`, your + server must serve the Ember app at all the routes you define. + + @class AutoLocation + @namespace Ember + @static + */ + __exports__["default"] = { + + /** + @private + + This property is used by router:main to know whether to cancel the routing + setup process, which is needed while we redirect the browser. + + @since 1.5.1 + @property cancelRouterSetup + @default false + */ + cancelRouterSetup: false, + + /** + @private + + Will be pre-pended to path upon state change. + + @since 1.5.1 + @property rootURL + @default '/' + */ + rootURL: '/', + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _window + @default window + */ + _window: window, + + /** + @private + + Attached for mocking in tests + + @property location + @default window.location + */ + _location: window.location, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _history + @default window.history + */ + _history: window.history, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _HistoryLocation + @default Ember.HistoryLocation + */ + _HistoryLocation: HistoryLocation, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _HashLocation + @default Ember.HashLocation + */ + _HashLocation: HashLocation, + + /** + @private + + Attached for mocking in tests + + @since 1.5.1 + @property _NoneLocation + @default Ember.NoneLocation + */ + _NoneLocation: NoneLocation, + + /** + @private + + Returns location.origin or builds it if device doesn't support it. + + @method _getOrigin + */ + _getOrigin: function () { + var location = this._location; + var origin = location.origin; + + // Older browsers, especially IE, don't have origin + if (!origin) { + origin = location.protocol + '//' + location.hostname; + + if (location.port) { + origin += ':' + location.port; + } + } + + return origin; + }, + + /** + @private + + We assume that if the history object has a pushState method, the host should + support HistoryLocation. + + @method _getSupportsHistory + */ + _getSupportsHistory: function () { + // Boosted from Modernizr: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/history.js + // The stock browser on Android 2.2 & 2.3 returns positive on history support + // Unfortunately support is really buggy and there is no clean way to detect + // these bugs, so we fall back to a user agent sniff :( + var userAgent = this._window.navigator.userAgent; + + // We only want Android 2, stock browser, and not Chrome which identifies + // itself as 'Mobile Safari' as well + if (userAgent.indexOf('Android 2') !== -1 && + userAgent.indexOf('Mobile Safari') !== -1 && + userAgent.indexOf('Chrome') === -1) { + return false; + } + + return !!(this._history && 'pushState' in this._history); + }, + + /** + @private + + IE8 running in IE7 compatibility mode gives false positive, so we must also + check documentMode. + + @method _getSupportsHashChange + */ + _getSupportsHashChange: function () { + var _window = this._window; + var documentMode = _window.document.documentMode; + + return ('onhashchange' in _window && (documentMode === undefined || documentMode > 7 )); + }, + + /** + @private + + Redirects the browser using location.replace, prepending the locatin.origin + to prevent phishing attempts + + @method _replacePath + */ + _replacePath: function (path) { + this._location.replace(this._getOrigin() + path); + }, + + /** + @since 1.5.1 + @private + @method _getRootURL + */ + _getRootURL: function () { + return this.rootURL; + }, + + /** + @private + + Returns the current `location.pathname`, normalized for IE inconsistencies. + + @method _getPath + */ + _getPath: function () { + var pathname = this._location.pathname; + // Various versions of IE/Opera don't always return a leading slash + if (pathname.charAt(0) !== '/') { + pathname = '/' + pathname; + } + + return pathname; + }, + + /** + @private + + Returns normalized location.hash as an alias to Ember.Location._getHash + + @since 1.5.1 + @method _getHash + */ + _getHash: EmberLocation._getHash, + + /** + @private + + Returns location.search + + @since 1.5.1 + @method _getQuery + */ + _getQuery: function () { + return this._location.search; + }, + + /** + @private + + Returns the full pathname including query and hash + + @method _getFullPath + */ + _getFullPath: function () { + return this._getPath() + this._getQuery() + this._getHash(); + }, + + /** + @private + + Returns the current path as it should appear for HistoryLocation supported + browsers. This may very well differ from the real current path (e.g. if it + starts off as a hashed URL) + + @method _getHistoryPath + */ + _getHistoryPath: function () { + var rootURL = this._getRootURL(); + var path = this._getPath(); + var hash = this._getHash(); + var query = this._getQuery(); + var rootURLIndex = path.indexOf(rootURL); + var routeHash, hashParts; + + + // By convention, Ember.js routes using HashLocation are required to start + // with `#/`. Anything else should NOT be considered a route and should + // be passed straight through, without transformation. + if (hash.substr(0, 2) === '#/') { + // There could be extra hash segments after the route + hashParts = hash.substr(1).split('#'); + // The first one is always the route url + routeHash = hashParts.shift(); + + // If the path already has a trailing slash, remove the one + // from the hashed route so we don't double up. + if (path.slice(-1) === '/') { + routeHash = routeHash.substr(1); + } + + // This is the "expected" final order + path += routeHash; + path += query; + + if (hashParts.length) { + path += '#' + hashParts.join('#'); + } + } else { + path += query; + path += hash; + } + + return path; + }, + + /** + @private + + Returns the current path as it should appear for HashLocation supported + browsers. This may very well differ from the real current path. + + @method _getHashPath + */ + _getHashPath: function () { + var rootURL = this._getRootURL(); + var path = rootURL; + var historyPath = this._getHistoryPath(); + var routePath = historyPath.substr(rootURL.length); + + if (routePath !== '') { + if (routePath.charAt(0) !== '/') { + routePath = '/' + routePath; + } + + path += '#' + routePath; + } + + return path; + }, + + /** + Selects the best location option based off browser support and returns an + instance of that Location class. + + @see Ember.AutoLocation + @method create + */ + create: function (options) { + if (options && options.rootURL) { + this.rootURL = options.rootURL; + } + + var historyPath, hashPath; + var cancelRouterSetup = false; + var implementationClass = this._NoneLocation; + var currentPath = this._getFullPath(); + + if (this._getSupportsHistory()) { + historyPath = this._getHistoryPath(); + + // Since we support history paths, let's be sure we're using them else + // switch the location over to it. + if (currentPath === historyPath) { + implementationClass = this._HistoryLocation; + } else { + + if (currentPath.substr(0, 2) === '/#') { + this._history.replaceState({ path: historyPath }, null, historyPath); + implementationClass = this._HistoryLocation; + } else { + cancelRouterSetup = true; + this._replacePath(historyPath); + } + } + + } else if (this._getSupportsHashChange()) { + hashPath = this._getHashPath(); + + // Be sure we're using a hashed path, otherwise let's switch over it to so + // we start off clean and consistent. We'll count an index path with no + // hash as "good enough" as well. + if (currentPath === hashPath || (currentPath === '/' && hashPath === '/#/')) { + implementationClass = this._HashLocation; + } else { + // Our URL isn't in the expected hash-supported format, so we want to + // cancel the router setup and replace the URL to start off clean + cancelRouterSetup = true; + this._replacePath(hashPath); + } + } + + var implementation = implementationClass.create.apply(implementationClass, arguments); + + if (cancelRouterSetup) { + set(implementation, 'cancelRouterSetup', true); + } + + return implementation; + } + }; + }); +define("ember-routing/location/hash_location", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/object","ember-routing/location/api","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var run = __dependency3__["default"]; + var guidFor = __dependency4__.guidFor; + + var EmberObject = __dependency5__["default"]; + var EmberLocation = __dependency6__["default"]; + var jQuery = __dependency7__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + `Ember.HashLocation` implements the location API using the browser's + hash. At present, it relies on a `hashchange` event existing in the + browser. + + @class HashLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'hash', + + init: function() { + set(this, 'location', get(this, '_location') || window.location); + }, + + /** + @private + + Returns normalized location.hash + + @since 1.5.1 + @method getHash + */ + getHash: EmberLocation._getHash, + + /** + Returns the current `location.hash`, minus the '#' at the front. + + @private + @method getURL + */ + getURL: function() { + return this.getHash().substr(1); + }, + + /** + Set the `location.hash` and remembers what was set. This prevents + `onUpdateURL` callbacks from triggering when the hash was set by + `HashLocation`. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + get(this, 'location').hash = path; + set(this, 'lastSetURL', path); + }, + + /** + Uses location.replace to update the url without a page reload + or history modification. + + @private + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + get(this, 'location').replace('#' + path); + set(this, 'lastSetURL', path); + }, + + /** + Register a callback to be invoked when the hash changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var self = this; + var guid = guidFor(this); + + jQuery(window).on('hashchange.ember-location-'+guid, function() { + run(function() { + var path = self.getURL(); + if (get(self, 'lastSetURL') === path) { return; } + + set(self, 'lastSetURL', null); + + callback(path); + }); + }); + }, + + /** + Given a URL, formats it to be placed into the page as part + of an element's `href` attribute. + + This is used, for example, when using the {{action}} helper + to generate a URL based on an event. + + @private + @method formatURL + @param url {String} + */ + formatURL: function(url) { + return '#' + url; + }, + + /** + Cleans up the HashLocation event listener. + + @private + @method willDestroy + */ + willDestroy: function() { + var guid = guidFor(this); + + jQuery(window).off('hashchange.ember-location-'+guid); + } + }); + }); +define("ember-routing/location/history_location", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-runtime/system/object","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + + var EmberObject = __dependency5__["default"]; + var jQuery = __dependency6__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + var popstateFired = false; + var supportsHistoryState = window.history && 'state' in window.history; + + /** + Ember.HistoryLocation implements the location API using the browser's + history.pushState API. + + @class HistoryLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'history', + + init: function() { + set(this, 'location', get(this, 'location') || window.location); + set(this, 'baseURL', jQuery('base').attr('href') || ''); + }, + + /** + Used to set state on first call to setURL + + @private + @method initState + */ + initState: function() { + set(this, 'history', get(this, 'history') || window.history); + this.replaceState(this.formatURL(this.getURL())); + }, + + /** + Will be pre-pended to path upon state change + + @property rootURL + @default '/' + */ + rootURL: '/', + + /** + Returns the current `location.pathname` without `rootURL` or `baseURL` + + @private + @method getURL + @return url {String} + */ + getURL: function() { + var rootURL = get(this, 'rootURL'); + var location = get(this, 'location'); + var path = location.pathname; + var baseURL = get(this, 'baseURL'); + + rootURL = rootURL.replace(/\/$/, ''); + baseURL = baseURL.replace(/\/$/, ''); + + var url = path.replace(baseURL, '').replace(rootURL, ''); + var search = location.search || ''; + + url += search; + + return url; + }, + + /** + Uses `history.pushState` to update the url without a page reload. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (!state || state.path !== path) { + this.pushState(path); + } + }, + + /** + Uses `history.replaceState` to update the url without a page reload + or history modification. + + @private + @method replaceURL + @param path {String} + */ + replaceURL: function(path) { + var state = this.getState(); + path = this.formatURL(path); + + if (!state || state.path !== path) { + this.replaceState(path); + } + }, + + /** + Get the current `history.state`. Checks for if a polyfill is + required and if so fetches this._historyState. The state returned + from getState may be null if an iframe has changed a window's + history. + + @private + @method getState + @return state {Object} + */ + getState: function() { + return supportsHistoryState ? get(this, 'history').state : this._historyState; + }, + + /** + Pushes a new state. + + @private + @method pushState + @param path {String} + */ + pushState: function(path) { + var state = { path: path }; + + get(this, 'history').pushState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + Replaces the current state. + + @private + @method replaceState + @param path {String} + */ + replaceState: function(path) { + var state = { path: path }; + + get(this, 'history').replaceState(state, null, path); + + // store state if browser doesn't support `history.state` + if (!supportsHistoryState) { + this._historyState = state; + } + + // used for webkit workaround + this._previousURL = this.getURL(); + }, + + /** + Register a callback to be invoked whenever the browser + history changes, including using forward and back buttons. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + var guid = guidFor(this); + var self = this; + + jQuery(window).on('popstate.ember-location-'+guid, function(e) { + // Ignore initial page load popstate event in Chrome + if (!popstateFired) { + popstateFired = true; + if (self.getURL() === self._previousURL) { return; } + } + callback(self.getURL()); + }); + }, + + /** + Used when using `{{action}}` helper. The url is always appended to the rootURL. + + @private + @method formatURL + @param url {String} + @return formatted url {String} + */ + formatURL: function(url) { + var rootURL = get(this, 'rootURL'); + var baseURL = get(this, 'baseURL'); + + if (url !== '') { + rootURL = rootURL.replace(/\/$/, ''); + baseURL = baseURL.replace(/\/$/, ''); + } else if(baseURL.match(/^\//) && rootURL.match(/^\//)) { + baseURL = baseURL.replace(/\/$/, ''); + } + + return baseURL + rootURL + url; + }, + + /** + Cleans up the HistoryLocation event listener. + + @private + @method willDestroy + */ + willDestroy: function() { + var guid = guidFor(this); + + jQuery(window).off('popstate.ember-location-'+guid); + } + }); + }); +define("ember-routing/location/none_location", + ["ember-metal/property_get","ember-metal/property_set","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var set = __dependency2__.set; + var EmberObject = __dependency3__["default"]; + + /** + @module ember + @submodule ember-routing + */ + + /** + Ember.NoneLocation does not interact with the browser. It is useful for + testing, or when you need to manage state with your Router, but temporarily + don't want it to muck with the URL (for example when you embed your + application in a larger page). + + @class NoneLocation + @namespace Ember + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + implementation: 'none', + path: '', + + /** + Returns the current path. + + @private + @method getURL + @return {String} path + */ + getURL: function() { + return get(this, 'path'); + }, + + /** + Set the path and remembers what was set. Using this method + to change the path will not invoke the `updateURL` callback. + + @private + @method setURL + @param path {String} + */ + setURL: function(path) { + set(this, 'path', path); + }, + + /** + Register a callback to be invoked when the path changes. These + callbacks will execute when the user presses the back or forward + button, but not after `setURL` is invoked. + + @private + @method onUpdateURL + @param callback {Function} + */ + onUpdateURL: function(callback) { + this.updateCallback = callback; + }, + + /** + Sets the path and calls the `updateURL` callback. + + @private + @method handleURL + @param callback {Function} + */ + handleURL: function(url) { + set(this, 'path', url); + this.updateCallback(url); + }, + + /** + Given a URL, formats it to be placed into the page as part + of an element's `href` attribute. + + This is used, for example, when using the {{action}} helper + to generate a URL based on an event. + + @private + @method formatURL + @param url {String} + @return {String} url + */ + formatURL: function(url) { + // The return value is not overly meaningful, but we do not want to throw + // errors when test code renders templates containing {{action href=true}} + // helpers. + return url; + } + }); + }); +define("ember-routing/system/cache", + ["ember-runtime/system/object","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + + __exports__["default"] = EmberObject.extend({ + init: function() { + this.cache = {}; + }, + has: function(bucketKey) { + return bucketKey in this.cache; + }, + stash: function(bucketKey, key, value) { + var bucket = this.cache[bucketKey]; + if (!bucket) { + bucket = this.cache[bucketKey] = {}; + } + bucket[key] = value; + }, + lookup: function(bucketKey, prop, defaultValue) { + var cache = this.cache; + if (!(bucketKey in cache)) { + return defaultValue; + } + var bucket = cache[bucketKey]; + if (prop in bucket) { + return bucket[prop]; + } else { + return defaultValue; + } + }, + cache: null + }); + }); +define("ember-routing/system/controller_for", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-routing + */ + + /** + + Finds a controller instance. + + @for Ember + @method controllerFor + @private + */ + __exports__["default"] = function controllerFor(container, controllerName, lookupOptions) { + return container.lookup('controller:' + controllerName, lookupOptions); + } + }); +define("ember-routing/system/dsl", + ["ember-metal/core","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // FEATURES, assert + + /** + @module ember + @submodule ember-routing + */ + + function DSL(name) { + this.parent = name; + this.matches = []; + } + __exports__["default"] = DSL; + + DSL.prototype = { + route: function(name, options, callback) { + if (arguments.length === 2 && typeof options === 'function') { + callback = options; + options = {}; + } + + if (arguments.length === 1) { + options = {}; + } + + var type = options.resetNamespace === true ? 'resource' : 'route'; + + + if (typeof options.path !== 'string') { + options.path = "/" + name; + } + + if (canNest(this) && options.resetNamespace !== true) { + name = this.parent + "." + name; + } + + if (callback) { + var dsl = new DSL(name); + route(dsl, 'loading'); + route(dsl, 'error', { path: "/_unused_dummy_error_path_route_" + name + "/:error" }); + + if (callback) { callback.call(dsl); } + + this.push(options.path, name, dsl.generate()); + } else { + this.push(options.path, name, null); + } + + }, + + push: function(url, name, callback) { + var parts = name.split('.'); + if (url === "" || url === "/" || parts[parts.length-1] === "index") { this.explicitIndex = true; } + + this.matches.push([url, name, callback]); + }, + + resource: function(name, options, callback) { + if (arguments.length === 2 && typeof options === 'function') { + callback = options; + options = {}; + } + + if (arguments.length === 1) { + options = {}; + } + + options.resetNamespace = true; + this.route(name, options, callback); + }, + + generate: function() { + var dslMatches = this.matches; + + if (!this.explicitIndex) { + route(this, "index", { path: "/" }); + } + + return function(match) { + for (var i=0, l=dslMatches.length; i +
    + {{outlet "anOutletName"}} +
    + ``` + + ```handlebars + +

    Photos

    + ``` + + You can render `photos.hbs` into the `"anOutletName"` outlet of + `application.hbs` by calling `render`: + + ```js + // posts route + Ember.Route.extend({ + renderTemplate: function(){ + this.render('posts', { + into: 'application', + outlet: 'anOutletName' + }) + } + }); + ``` + + `render` additionally allows you to supply which `view`, `controller`, and + `model` objects should be loaded and associated with the rendered template. + + + ```js + // posts route + Ember.Route.extend({ + renderTemplate: function(controller, model){ + this.render('posts', { // the template to render, referenced by name + into: 'application', // the template to render into, referenced by name + outlet: 'anOutletName', // the outlet inside `options.template` to render into. + view: 'aViewName', // the view to use for this template, referenced by name + controller: 'someControllerName', // the controller to use for this template, referenced by name + model: model // the model to set on `options.controller`. + }) + } + }); + ``` + + The string values provided for the template name, view, and controller + will eventually pass through to the resolver for lookup. See + Ember.Resolver for how these are mapped to JavaScript objects in your + application. + + Not all options need to be passed to `render`. Default values will be used + based on the name of the route specified in the router or the Route's + `controllerName`, `viewName` and and `templateName` properties. + + For example: + + ```js + // router + Router.map(function() { + this.route('index'); + this.resource('post', {path: '/posts/:post_id'}); + }); + ``` + + ```js + // post route + PostRoute = App.Route.extend({ + renderTemplate: function() { + this.render(); // all defaults apply + } + }); + ``` + + The name of the `PostRoute`, defined by the router, is `post`. + + The following equivalent default options will be applied when + the Route calls `render`: + + ```js + // + this.render('post', { // the template name associated with 'post' Route + into: 'application', // the parent route to 'post' Route + outlet: 'main', // {{outlet}} and {{outlet 'main' are synonymous}}, + view: 'post', // the view associated with the 'post' Route + controller: 'post', // the controller associated with the 'post' Route + }) + ``` + + By default the controller's `model` will be the route's model, so it does not + need to be passed unless you wish to change which model is being used. + + @method render + @param {String} name the name of the template to render + @param {Object} [options] the options + @param {String} [options.into] the template to render into, + referenced by name. Defaults to the parent template + @param {String} [options.outlet] the outlet inside `options.template` to render into. + Defaults to 'main' + @param {String} [options.controller] the controller to use for this template, + referenced by name. Defaults to the Route's paired controller + @param {String} [options.model] the model object to set on `options.controller` + Defaults to the return value of the Route's model hook + */ + render: function(name, options) { + + var namePassed = typeof name === 'string' && !!name; + + if (typeof name === 'object' && !options) { + options = name; + name = this.routeName; + } + + options = options || {}; + options.namePassed = namePassed; + + var templateName; + + if (name) { + name = name.replace(/\//g, '.'); + templateName = name; + } else { + name = this.routeName; + templateName = this.templateName || name; + } + + var viewName = options.view || namePassed && name || this.viewName || name; + + var container = this.container; + var view = container.lookup('view:' + viewName); + var template = view ? view.get('template') : null; + + if (!template) { + template = container.lookup('template:' + templateName); + } + + if (!view && !template) { + if (get(this.router, 'namespace.LOG_VIEW_LOOKUPS')) { + } + return; + } + + options = normalizeOptions(this, name, template, options); + view = setupView(view, container, options); + + if (options.outlet === 'main') { this.lastRenderedTemplate = name; } + + appendView(this, view, options); + }, + + /** + Disconnects a view that has been rendered into an outlet. + + You may pass any or all of the following options to `disconnectOutlet`: + + * `outlet`: the name of the outlet to clear (default: 'main') + * `parentView`: the name of the view containing the outlet to clear + (default: the view rendered by the parent route) + + Example: + + ```js + App.ApplicationRoute = App.Route.extend({ + actions: { + showModal: function(evt) { + this.render(evt.modalName, { + outlet: 'modal', + into: 'application' + }); + }, + hideModal: function(evt) { + this.disconnectOutlet({ + outlet: 'modal', + parentView: 'application' + }); + } + } + }); + ``` + + Alternatively, you can pass the `outlet` name directly as a string. + + Example: + + ```js + hideModal: function(evt) { + this.disconnectOutlet('modal'); + } + ``` + + @method disconnectOutlet + @param {Object|String} options the options hash or outlet name + */ + disconnectOutlet: function(options) { + if (!options || typeof options === "string") { + var outletName = options; + options = {}; + options.outlet = outletName; + } + options.parentView = options.parentView ? options.parentView.replace(/\//g, '.') : parentTemplate(this); + options.outlet = options.outlet || 'main'; + + var parentView = this.router._lookupActiveView(options.parentView); + if (parentView) { parentView.disconnectOutlet(options.outlet); } + }, + + willDestroy: function() { + this.teardownViews(); + }, + + /** + @private + + @method teardownViews + */ + teardownViews: function() { + // Tear down the top level view + if (this.teardownTopLevelView) { this.teardownTopLevelView(); } + + // Tear down any outlets rendered with 'into' + var teardownOutletViews = this.teardownOutletViews || []; + forEach(teardownOutletViews, function(teardownOutletView) { + teardownOutletView(); + }); + + delete this.teardownTopLevelView; + delete this.teardownOutletViews; + delete this.lastRenderedTemplate; + } + }); + + var defaultQPMeta = { + qps: [], + map: {}, + states: {} + }; + + function parentRoute(route) { + var handlerInfo = handlerInfoFor(route, route.router.router.state.handlerInfos, -1); + return handlerInfo && handlerInfo.handler; + } + + function handlerInfoFor(route, handlerInfos, _offset) { + if (!handlerInfos) { return; } + + var offset = _offset || 0, current; + for (var i=0, l=handlerInfos.length; i 1) { + var qp0 = qps[0].qp, qp1=qps[1].qp; + } + var qp = qps[0].qp; + queryParams[qp.urlKey] = qp.route.serializeQueryParam(qps[0].value, qp.urlKey, qp.type); + } + }, + + _deserializeQueryParams: function(targetRouteName, queryParams) { + forEachQueryParam(this, targetRouteName, queryParams, function(key, value, qp) { + delete queryParams[key]; + queryParams[qp.prop] = qp.route.deserializeQueryParam(value, qp.urlKey, qp.type); + }); + }, + + _pruneDefaultQueryParamValues: function(targetRouteName, queryParams) { + var qps = this._queryParamsFor(targetRouteName); + for (var key in queryParams) { + var qp = qps.map[key]; + if (qp && qp.sdef === queryParams[key]) { + delete queryParams[key]; + } + } + }, + + _doTransition: function(_targetRouteName, models, _queryParams) { + var targetRouteName = _targetRouteName || getActiveTargetName(this.router); + + var queryParams = {}; + merge(queryParams, _queryParams); + this._prepareQueryParams(targetRouteName, models, queryParams); + + var transitionArgs = routeArgs(targetRouteName, models, queryParams); + var transitionPromise = this.router.transitionTo.apply(this.router, transitionArgs); + + listenForTransitionErrors(transitionPromise); + + return transitionPromise; + }, + + _prepareQueryParams: function(targetRouteName, models, queryParams) { + this._hydrateUnsuppliedQueryParams(targetRouteName, models, queryParams); + this._serializeQueryParams(targetRouteName, queryParams); + this._pruneDefaultQueryParamValues(targetRouteName, queryParams); + }, + + /** + Returns a merged query params meta object for a given route. + Useful for asking a route what its known query params are. + */ + _queryParamsFor: function(leafRouteName) { + if (this._qpCache[leafRouteName]) { + return this._qpCache[leafRouteName]; + } + + var map = {}, qps = [], qpCache = this._qpCache[leafRouteName] = { + map: map, + qps: qps + }; + + var routerjs = this.router; + var recogHandlerInfos = routerjs.recognizer.handlersFor(leafRouteName); + + for (var i = 0, len = recogHandlerInfos.length; i < len; ++i) { + var recogHandler = recogHandlerInfos[i]; + var route = routerjs.getHandler(recogHandler.handler); + var qpMeta = get(route, '_qp'); + + if (!qpMeta) { continue; } + + merge(map, qpMeta.map); + qps.push.apply(qps, qpMeta.qps); + } + + return { + qps: qps, + map: map + }; + }, + + /* + becomeResolved: function(payload, resolvedContext) { + var params = this.serialize(resolvedContext); + + if (payload) { + this.stashResolvedModel(payload, resolvedContext); + payload.params = payload.params || {}; + payload.params[this.name] = params; + } + + return this.factory('resolved', { + context: resolvedContext, + name: this.name, + handler: this.handler, + params: params + }); + }, + */ + + _hydrateUnsuppliedQueryParams: function(leafRouteName, contexts, queryParams) { + var state = calculatePostTransitionState(this, leafRouteName, contexts); + var handlerInfos = state.handlerInfos; + var appCache = this._bucketCache; + + stashParamNames(this, handlerInfos); + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var route = handlerInfos[i].handler; + var qpMeta = get(route, '_qp'); + + for (var j = 0, qpLen = qpMeta.qps.length; j < qpLen; ++j) { + var qp = qpMeta.qps[j]; + var presentProp = qp.prop in queryParams && qp.prop || + qp.fprop in queryParams && qp.fprop; + + if (presentProp) { + if (presentProp !== qp.fprop) { + queryParams[qp.fprop] = queryParams[presentProp]; + delete queryParams[presentProp]; + } + } else { + var controllerProto = qp.cProto; + var cacheMeta = get(controllerProto, '_cacheMeta'); + + var cacheKey = controllerProto._calculateCacheKey(qp.ctrl, cacheMeta[qp.prop].parts, state.params); + queryParams[qp.fprop] = appCache.lookup(cacheKey, qp.prop, qp.def); + } + } + } + }, + + _scheduleLoadingEvent: function(transition, originRoute) { + this._cancelLoadingEvent(); + this._loadingStateTimer = run.scheduleOnce('routerTransitions', this, '_fireLoadingEvent', transition, originRoute); + }, + + _fireLoadingEvent: function(transition, originRoute) { + if (!this.router.activeTransition) { + // Don't fire an event if we've since moved on from + // the transition that put us in a loading state. + return; + } + + transition.trigger(true, 'loading', transition, originRoute); + }, + + _cancelLoadingEvent: function () { + if (this._loadingStateTimer) { + run.cancel(this._loadingStateTimer); + } + this._loadingStateTimer = null; + } + }); + + /* + Helper function for iterating root-ward, starting + from (but not including) the provided `originRoute`. + + Returns true if the last callback fired requested + to bubble upward. + + @private + */ + function forEachRouteAbove(originRoute, transition, callback) { + var handlerInfos = transition.state.handlerInfos; + var originRouteFound = false; + var handlerInfo, route; + + for (var i = handlerInfos.length - 1; i >= 0; --i) { + handlerInfo = handlerInfos[i]; + route = handlerInfo.handler; + + if (!originRouteFound) { + if (originRoute === route) { + originRouteFound = true; + } + continue; + } + + if (callback(route, handlerInfos[i + 1].handler) !== true) { + return false; + } + } + return true; + } + + // These get invoked when an action bubbles above ApplicationRoute + // and are not meant to be overridable. + var defaultActionHandlers = { + + willResolveModel: function(transition, originRoute) { + originRoute.router._scheduleLoadingEvent(transition, originRoute); + }, + + error: function(error, transition, originRoute) { + // Attempt to find an appropriate error substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childErrorRouteName = findChildRouteName(route, childRoute, 'error'); + if (childErrorRouteName) { + router.intermediateTransitionTo(childErrorRouteName, error); + return; + } + return true; + }); + + if (tryTopLevel) { + // Check for top-level error state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_error')) { + router.intermediateTransitionTo('application_error', error); + return; + } + } + + logError(error, 'Error while processing route: ' + transition.targetName); + }, + + loading: function(transition, originRoute) { + // Attempt to find an appropriate loading substate to enter. + var router = originRoute.router; + + var tryTopLevel = forEachRouteAbove(originRoute, transition, function(route, childRoute) { + var childLoadingRouteName = findChildRouteName(route, childRoute, 'loading'); + + if (childLoadingRouteName) { + router.intermediateTransitionTo(childLoadingRouteName); + return; + } + + // Don't bubble above pivot route. + if (transition.pivotHandler !== route) { + return true; + } + }); + + if (tryTopLevel) { + // Check for top-level loading state to enter. + if (routeHasBeenDefined(originRoute.router, 'application_loading')) { + router.intermediateTransitionTo('application_loading'); + return; + } + } + } + }; + + function logError(error, initialMessage) { + var errorArgs = []; + + if (initialMessage) { errorArgs.push(initialMessage); } + + if (error) { + if (error.message) { errorArgs.push(error.message); } + if (error.stack) { errorArgs.push(error.stack); } + + if (typeof error === "string") { errorArgs.push(error); } + } + + Ember.Logger.error.apply(this, errorArgs); + } + + function findChildRouteName(parentRoute, originatingChildRoute, name) { + var router = parentRoute.router; + var childName; + var targetChildRouteName = originatingChildRoute.routeName.split('.').pop(); + var namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.'; + + + // Second, try general loading state, e.g. 'loading' + childName = namespace + name; + if (routeHasBeenDefined(router, childName)) { + return childName; + } + } + + function routeHasBeenDefined(router, name) { + var container = router.container; + return router.hasRoute(name) && + (container.has('template:' + name) || container.has('route:' + name)); + } + + function triggerEvent(handlerInfos, ignoreFailure, args) { + var name = args.shift(); + + if (!handlerInfos) { + if (ignoreFailure) { return; } + throw new EmberError("Can't trigger action '" + name + "' because your app hasn't finished transitioning into its first route. To trigger an action on destination routes during a transition, you can call `.send()` on the `Transition` object passed to the `model/beforeModel/afterModel` hooks."); + } + + var eventWasHandled = false; + var handlerInfo, handler; + + for (var i = handlerInfos.length - 1; i >= 0; i--) { + handlerInfo = handlerInfos[i]; + handler = handlerInfo.handler; + + if (handler._actions && handler._actions[name]) { + if (handler._actions[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (defaultActionHandlers[name]) { + defaultActionHandlers[name].apply(null, args); + return; + } + + if (!eventWasHandled && !ignoreFailure) { + throw new EmberError("Nothing handled the action '" + name + "'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble."); + } + } + + function calculatePostTransitionState(emberRouter, leafRouteName, contexts) { + var routerjs = emberRouter.router; + var state = routerjs.applyIntent(leafRouteName, contexts); + var handlerInfos = state.handlerInfos; + var params = state.params; + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + if (!handlerInfo.isResolved) { + handlerInfo = handlerInfo.becomeResolved(null, handlerInfo.context); + } + params[handlerInfo.name] = handlerInfo.params; + } + return state; + } + + function updatePaths(router) { + var appController = router.container.lookup('controller:application'); + + if (!appController) { + // appController might not exist when top-level loading/error + // substates have been entered since ApplicationRoute hasn't + // actually been entered at that point. + return; + } + + var infos = router.router.currentHandlerInfos; + var path = EmberRouter._routePath(infos); + + if (!('currentPath' in appController)) { + defineProperty(appController, 'currentPath'); + } + + set(appController, 'currentPath', path); + + if (!('currentRouteName' in appController)) { + defineProperty(appController, 'currentRouteName'); + } + + set(appController, 'currentRouteName', infos[infos.length - 1].name); + } + + EmberRouter.reopenClass({ + router: null, + + /** + The `Router.map` function allows you to define mappings from URLs to routes + and resources in your application. These mappings are defined within the + supplied callback function using `this.resource` and `this.route`. + + ```javascript + App.Router.map(function({ + this.route('about'); + this.resource('article'); + })); + ``` + + For more detailed examples please see + [the guides](http://emberjs.com/guides/routing/defining-your-routes/). + + @method map + @param callback + */ + map: function(callback) { + var router = this.router; + if (!router) { + router = new Router(); + + + router._triggerWillChangeContext = Ember.K; + router._triggerWillLeave = Ember.K; + + + router.callbacks = []; + router.triggerEvent = triggerEvent; + this.reopenClass({ router: router }); + } + + var dsl = EmberRouterDSL.map(function() { + this.resource('application', { path: "/" }, function() { + for (var i=0; i < router.callbacks.length; i++) { + router.callbacks[i].call(this); + } + callback.call(this); + }); + }); + + router.callbacks.push(callback); + router.map(dsl.generate()); + return router; + }, + + _routePath: function(handlerInfos) { + var path = []; + + // We have to handle coalescing resource names that + // are prefixed with their parent's names, e.g. + // ['foo', 'foo.bar.baz'] => 'foo.bar.baz', not 'foo.foo.bar.baz' + + function intersectionMatches(a1, a2) { + for (var i = 0, len = a1.length; i < len; ++i) { + if (a1[i] !== a2[i]) { + return false; + } + } + return true; + } + + var name, nameParts, oldNameParts; + for (var i=1, l=handlerInfos.length; i 0) - (diff < 0); + } + + /** + This will compare two javascript values of possibly different types. + It will tell you which one is greater than the other by returning: + + - -1 if the first is smaller than the second, + - 0 if both are equal, + - 1 if the first is greater than the second. + + The order is calculated based on `Ember.ORDER_DEFINITION`, if types are different. + In case they have the same type an appropriate comparison for this type is made. + + ```javascript + Ember.compare('hello', 'hello'); // 0 + Ember.compare('abc', 'dfg'); // -1 + Ember.compare(2, 1); // 1 + ``` + + @method compare + @for Ember + @param {Object} v First value to compare + @param {Object} w Second value to compare + @return {Number} -1 if v < w, 0 if v = w and 1 if v > w. + */ + __exports__["default"] = function compare(v, w) { + if (v === w) { + return 0; + } + + var type1 = typeOf(v); + var type2 = typeOf(w); + + if (Comparable) { + if (type1 ==='instance' && Comparable.detect(v.constructor)) { + return v.constructor.compare(v, w); + } + + if (type2 === 'instance' && Comparable.detect(w.constructor)) { + return 1 - w.constructor.compare(w, v); + } + } + + var res = spaceship(TYPE_ORDER[type1], TYPE_ORDER[type2]); + if (res !== 0) { + return res; + } + + // types are equal - so we have to check values now + switch (type1) { + case 'boolean': + case 'number': + return spaceship(v,w); + + case 'string': + return spaceship(v.localeCompare(w), 0); + + case 'array': + var vLen = v.length; + var wLen = w.length; + var len = Math.min(vLen, wLen); + + for (var i = 0; i < len; i++) { + var r = compare(v[i], w[i]); + if (r !== 0) { + return r; + } + } + + // all elements are equal now + // shorter array should be ordered first + return spaceship(vLen, wLen); + + case 'instance': + if (Comparable && Comparable.detect(v)) { + return v.compare(v, w); + } + return 0; + + case 'date': + return spaceship(v.getTime(), w.getTime()); + + default: + return 0; + } + } + }); +define("ember-runtime/computed/array_computed", + ["ember-metal/core","ember-runtime/computed/reduce_computed","ember-metal/enumerable_utils","ember-metal/platform","ember-metal/observer","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var reduceComputed = __dependency2__.reduceComputed; + var ReduceComputedProperty = __dependency2__.ReduceComputedProperty; + var forEach = __dependency3__.forEach; + var o_create = __dependency4__.create; + var addObserver = __dependency5__.addObserver; + var EmberError = __dependency6__["default"]; + + var a_slice = [].slice; + + function ArrayComputedProperty() { + var cp = this; + + ReduceComputedProperty.apply(this, arguments); + + this.func = (function(reduceFunc) { + return function (propertyName) { + if (!cp._hasInstanceMeta(this, propertyName)) { + // When we recompute an array computed property, we need already + // retrieved arrays to be updated; we can't simply empty the cache and + // hope the array is re-retrieved. + forEach(cp._dependentKeys, function(dependentKey) { + addObserver(this, dependentKey, function() { + cp.recomputeOnce.call(this, propertyName); + }); + }, this); + } + + return reduceFunc.apply(this, arguments); + }; + })(this.func); + + return this; + } + + ArrayComputedProperty.prototype = o_create(ReduceComputedProperty.prototype); + + ArrayComputedProperty.prototype.initialValue = function () { + return Ember.A(); + }; + + ArrayComputedProperty.prototype.resetValue = function (array) { + array.clear(); + return array; + }; + + // This is a stopgap to keep the reference counts correct with lazy CPs. + ArrayComputedProperty.prototype.didChange = function (obj, keyName) { + return; + }; + + /** + Creates a computed property which operates on dependent arrays and + is updated with "one at a time" semantics. When items are added or + removed from the dependent array(s) an array computed only operates + on the change instead of re-evaluating the entire array. This should + return an array, if you'd like to use "one at a time" semantics and + compute some value other then an array look at + `Ember.reduceComputed`. + + If there are more than one arguments the first arguments are + considered to be dependent property keys. The last argument is + required to be an options object. The options object can have the + following three properties. + + `initialize` - An optional initialize function. Typically this will be used + to set up state on the instanceMeta object. + + `removedItem` - A function that is called each time an element is + removed from the array. + + `addedItem` - A function that is called each time an element is + added to the array. + + + The `initialize` function has the following signature: + + ```javascript + function(array, changeMeta, instanceMeta) + ``` + + `array` - The initial value of the arrayComputed, an empty array. + + `changeMeta` - An object which contains meta information about the + computed. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + + The `removedItem` and `addedItem` functions both have the following signature: + + ```javascript + function(accumulatedValue, item, changeMeta, instanceMeta) + ``` + + `accumulatedValue` - The value returned from the last time + `removedItem` or `addedItem` was called or an empty array. + + `item` - the element added or removed from the array + + `changeMeta` - An object which contains meta information about the + change. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + - `index` the index of the added or removed item + - `item` the added or removed item: this is exactly the same as + the second arg + - `arrayChanged` the array that triggered the change. Can be + useful when depending on multiple arrays. + + For property changes triggered on an item property change (when + depKey is something like `someArray.@each.someProperty`), + `changeMeta` will also contain the following property: + + - `previousValues` an object whose keys are the properties that changed on + the item, and whose values are the item's previous values. + + `previousValues` is important Ember coalesces item property changes via + Ember.run.once. This means that by the time removedItem gets called, item has + the new values, but you may need the previous value (eg for sorting & + filtering). + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + The `removedItem` and `addedItem` functions should return the accumulated + value. It is acceptable to not return anything (ie return undefined) + to invalidate the computation. This is generally not a good idea for + arrayComputed but it's used in eg max and min. + + Example + + ```javascript + Ember.computed.map = function(dependentKey, callback) { + var options = { + addedItem: function(array, item, changeMeta, instanceMeta) { + var mapped = callback(item); + array.insertAt(changeMeta.index, mapped); + return array; + }, + removedItem: function(array, item, changeMeta, instanceMeta) { + array.removeAt(changeMeta.index, 1); + return array; + } + }; + + return Ember.arrayComputed(dependentKey, options); + }; + ``` + + @method arrayComputed + @for Ember + @param {String} [dependentKeys*] + @param {Object} options + @return {Ember.ComputedProperty} + */ + function arrayComputed (options) { + var args; + + if (arguments.length > 1) { + args = a_slice.call(arguments, 0, -1); + options = a_slice.call(arguments, -1)[0]; + } + + if (typeof options !== 'object') { + throw new EmberError('Array Computed Property declared without an options hash'); + } + + var cp = new ArrayComputedProperty(options); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + __exports__.arrayComputed = arrayComputed; + __exports__.ArrayComputedProperty = ArrayComputedProperty; + }); +define("ember-runtime/computed/reduce_computed", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/property_events","ember-metal/expand_properties","ember-metal/observer","ember-metal/computed","ember-metal/platform","ember-metal/enumerable_utils","ember-runtime/system/tracked_array","ember-runtime/mixins/array","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var e_get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var metaFor = __dependency4__.meta; + var EmberError = __dependency5__["default"]; + var propertyWillChange = __dependency6__.propertyWillChange; + var propertyDidChange = __dependency6__.propertyDidChange; + var expandProperties = __dependency7__["default"]; + var addObserver = __dependency8__.addObserver; + var observersFor = __dependency8__.observersFor; + var removeObserver = __dependency8__.removeObserver; + var addBeforeObserver = __dependency8__.addBeforeObserver; + var removeBeforeObserver = __dependency8__.removeBeforeObserver; + var ComputedProperty = __dependency9__.ComputedProperty; + var cacheFor = __dependency9__.cacheFor; + var o_create = __dependency10__.create; + var forEach = __dependency11__.forEach; + var TrackedArray = __dependency12__["default"]; + var EmberArray = __dependency13__["default"]; + var run = __dependency14__["default"]; + var isArray = __dependency4__.isArray; + + var cacheSet = cacheFor.set; + var cacheGet = cacheFor.get; + var cacheRemove = cacheFor.remove; + var a_slice = [].slice; + // Here we explicitly don't allow `@each.foo`; it would require some special + // testing, but there's no particular reason why it should be disallowed. + var eachPropertyPattern = /^(.*)\.@each\.(.*)/; + var doubleEachPropertyPattern = /(.*\.@each){2,}/; + var arrayBracketPattern = /\.\[\]$/; + + function get(obj, key) { + if (key === '@this') { + return obj; + } + + return e_get(obj, key); + } + + /* + Tracks changes to dependent arrays, as well as to properties of items in + dependent arrays. + + @class DependentArraysObserver + */ + function DependentArraysObserver(callbacks, cp, instanceMeta, context, propertyName, sugarMeta) { + // user specified callbacks for `addedItem` and `removedItem` + this.callbacks = callbacks; + + // the computed property: remember these are shared across instances + this.cp = cp; + + // the ReduceComputedPropertyInstanceMeta this DependentArraysObserver is + // associated with + this.instanceMeta = instanceMeta; + + // A map of array guids to dependentKeys, for the given context. We track + // this because we want to set up the computed property potentially before the + // dependent array even exists, but when the array observer fires, we lack + // enough context to know what to update: we can recover that context by + // getting the dependentKey. + this.dependentKeysByGuid = {}; + + // a map of dependent array guids -> TrackedArray instances. We use + // this to lazily recompute indexes for item property observers. + this.trackedArraysByGuid = {}; + + // We suspend observers to ignore replacements from `reset` when totally + // recomputing. Unfortunately we cannot properly suspend the observers + // because we only have the key; instead we make the observers no-ops + this.suspended = false; + + // This is used to coalesce item changes from property observers within a + // single item. + this.changedItems = {}; + // This is used to coalesce item changes for multiple items that depend on + // some shared state. + this.changedItemCount = 0; + } + + function ItemPropertyObserverContext (dependentArray, index, trackedArray) { + + this.dependentArray = dependentArray; + this.index = index; + this.item = dependentArray.objectAt(index); + this.trackedArray = trackedArray; + this.beforeObserver = null; + this.observer = null; + this.destroyed = false; + } + + DependentArraysObserver.prototype = { + setValue: function (newValue) { + this.instanceMeta.setValue(newValue, true); + }, + + getValue: function () { + return this.instanceMeta.getValue(); + }, + + setupObservers: function (dependentArray, dependentKey) { + this.dependentKeysByGuid[guidFor(dependentArray)] = dependentKey; + + dependentArray.addArrayObserver(this, { + willChange: 'dependentArrayWillChange', + didChange: 'dependentArrayDidChange' + }); + + if (this.cp._itemPropertyKeys[dependentKey]) { + this.setupPropertyObservers(dependentKey, this.cp._itemPropertyKeys[dependentKey]); + } + }, + + teardownObservers: function (dependentArray, dependentKey) { + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; + + delete this.dependentKeysByGuid[guidFor(dependentArray)]; + + this.teardownPropertyObservers(dependentKey, itemPropertyKeys); + + dependentArray.removeArrayObserver(this, { + willChange: 'dependentArrayWillChange', + didChange: 'dependentArrayDidChange' + }); + }, + + suspendArrayObservers: function (callback, binding) { + var oldSuspended = this.suspended; + this.suspended = true; + callback.call(binding); + this.suspended = oldSuspended; + }, + + setupPropertyObservers: function (dependentKey, itemPropertyKeys) { + var dependentArray = get(this.instanceMeta.context, dependentKey); + var length = get(dependentArray, 'length'); + var observerContexts = new Array(length); + + this.resetTransformations(dependentKey, observerContexts); + + forEach(dependentArray, function (item, index) { + var observerContext = this.createPropertyObserverContext(dependentArray, index, this.trackedArraysByGuid[dependentKey]); + observerContexts[index] = observerContext; + + forEach(itemPropertyKeys, function (propertyKey) { + addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); + addObserver(item, propertyKey, this, observerContext.observer); + }, this); + }, this); + }, + + teardownPropertyObservers: function (dependentKey, itemPropertyKeys) { + var dependentArrayObserver = this; + var trackedArray = this.trackedArraysByGuid[dependentKey]; + var beforeObserver, observer, item; + + if (!trackedArray) { return; } + + trackedArray.apply(function (observerContexts, offset, operation) { + if (operation === TrackedArray.DELETE) { return; } + + forEach(observerContexts, function (observerContext) { + observerContext.destroyed = true; + beforeObserver = observerContext.beforeObserver; + observer = observerContext.observer; + item = observerContext.item; + + forEach(itemPropertyKeys, function (propertyKey) { + removeBeforeObserver(item, propertyKey, dependentArrayObserver, beforeObserver); + removeObserver(item, propertyKey, dependentArrayObserver, observer); + }); + }); + }); + }, + + createPropertyObserverContext: function (dependentArray, index, trackedArray) { + var observerContext = new ItemPropertyObserverContext(dependentArray, index, trackedArray); + + this.createPropertyObserver(observerContext); + + return observerContext; + }, + + createPropertyObserver: function (observerContext) { + var dependentArrayObserver = this; + + observerContext.beforeObserver = function (obj, keyName) { + return dependentArrayObserver.itemPropertyWillChange(obj, keyName, observerContext.dependentArray, observerContext); + }; + + observerContext.observer = function (obj, keyName) { + return dependentArrayObserver.itemPropertyDidChange(obj, keyName, observerContext.dependentArray, observerContext); + }; + }, + + resetTransformations: function (dependentKey, observerContexts) { + this.trackedArraysByGuid[dependentKey] = new TrackedArray(observerContexts); + }, + + trackAdd: function (dependentKey, index, newItems) { + var trackedArray = this.trackedArraysByGuid[dependentKey]; + + if (trackedArray) { + trackedArray.addItems(index, newItems); + } + }, + + trackRemove: function (dependentKey, index, removedCount) { + var trackedArray = this.trackedArraysByGuid[dependentKey]; + + if (trackedArray) { + return trackedArray.removeItems(index, removedCount); + } + + return []; + }, + + updateIndexes: function (trackedArray, array) { + var length = get(array, 'length'); + // OPTIMIZE: we could stop updating once we hit the object whose observer + // fired; ie partially apply the transformations + trackedArray.apply(function (observerContexts, offset, operation, operationIndex) { + // we don't even have observer contexts for removed items, even if we did, + // they no longer have any index in the array + if (operation === TrackedArray.DELETE) { return; } + if (operationIndex === 0 && operation === TrackedArray.RETAIN && observerContexts.length === length && offset === 0) { + // If we update many items we don't want to walk the array each time: we + // only need to update the indexes at most once per run loop. + return; + } + + forEach(observerContexts, function (context, index) { + context.index = index + offset; + }); + }); + }, + + dependentArrayWillChange: function (dependentArray, index, removedCount, addedCount) { + if (this.suspended) { return; } + + var removedItem = this.callbacks.removedItem; + var changeMeta; + var guid = guidFor(dependentArray); + var dependentKey = this.dependentKeysByGuid[guid]; + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey] || []; + var length = get(dependentArray, 'length'); + var normalizedIndex = normalizeIndex(index, length, 0); + var normalizedRemoveCount = normalizeRemoveCount(normalizedIndex, length, removedCount); + var item, itemIndex, sliceIndex, observerContexts; + + observerContexts = this.trackRemove(dependentKey, normalizedIndex, normalizedRemoveCount); + + function removeObservers(propertyKey) { + observerContexts[sliceIndex].destroyed = true; + removeBeforeObserver(item, propertyKey, this, observerContexts[sliceIndex].beforeObserver); + removeObserver(item, propertyKey, this, observerContexts[sliceIndex].observer); + } + + for (sliceIndex = normalizedRemoveCount - 1; sliceIndex >= 0; --sliceIndex) { + itemIndex = normalizedIndex + sliceIndex; + if (itemIndex >= length) { break; } + + item = dependentArray.objectAt(itemIndex); + + forEach(itemPropertyKeys, removeObservers, this); + + changeMeta = new ChangeMeta(dependentArray, item, itemIndex, this.instanceMeta.propertyName, this.cp, normalizedRemoveCount); + this.setValue(removedItem.call( + this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); + } + }, + + dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) { + if (this.suspended) { return; } + + var addedItem = this.callbacks.addedItem; + var guid = guidFor(dependentArray); + var dependentKey = this.dependentKeysByGuid[guid]; + var observerContexts = new Array(addedCount); + var itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey]; + var length = get(dependentArray, 'length'); + var normalizedIndex = normalizeIndex(index, length, addedCount); + var endIndex = normalizedIndex + addedCount; + var changeMeta, observerContext; + + forEach(dependentArray.slice(normalizedIndex, endIndex), function (item, sliceIndex) { + if (itemPropertyKeys) { + observerContext = this.createPropertyObserverContext(dependentArray, normalizedIndex + sliceIndex, + this.trackedArraysByGuid[dependentKey]); + observerContexts[sliceIndex] = observerContext; + + forEach(itemPropertyKeys, function (propertyKey) { + addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); + addObserver(item, propertyKey, this, observerContext.observer); + }, this); + } + + changeMeta = new ChangeMeta(dependentArray, item, normalizedIndex + sliceIndex, this.instanceMeta.propertyName, this.cp, addedCount); + this.setValue(addedItem.call( + this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); + }, this); + + this.trackAdd(dependentKey, normalizedIndex, observerContexts); + }, + + itemPropertyWillChange: function (obj, keyName, array, observerContext) { + var guid = guidFor(obj); + + if (!this.changedItems[guid]) { + this.changedItems[guid] = { + array: array, + observerContext: observerContext, + obj: obj, + previousValues: {} + }; + } + + ++this.changedItemCount; + this.changedItems[guid].previousValues[keyName] = get(obj, keyName); + }, + + itemPropertyDidChange: function (obj, keyName, array, observerContext) { + if (--this.changedItemCount === 0) { + this.flushChanges(); + } + }, + + flushChanges: function () { + var changedItems = this.changedItems; + var key, c, changeMeta; + + for (key in changedItems) { + c = changedItems[key]; + if (c.observerContext.destroyed) { continue; } + + this.updateIndexes(c.observerContext.trackedArray, c.observerContext.dependentArray); + + changeMeta = new ChangeMeta(c.array, c.obj, c.observerContext.index, this.instanceMeta.propertyName, this.cp, changedItems.length, c.previousValues); + this.setValue( + this.callbacks.removedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); + this.setValue( + this.callbacks.addedItem.call(this.instanceMeta.context, this.getValue(), c.obj, changeMeta, this.instanceMeta.sugarMeta)); + } + + this.changedItems = {}; + } + }; + + function normalizeIndex(index, length, newItemsOffset) { + if (index < 0) { + return Math.max(0, length + index); + } else if (index < length) { + return index; + } else /* index > length */ { + return Math.min(length - newItemsOffset, index); + } + } + + function normalizeRemoveCount(index, length, removedCount) { + return Math.min(removedCount, length - index); + } + + function ChangeMeta(dependentArray, item, index, propertyName, property, changedCount, previousValues){ + this.arrayChanged = dependentArray; + this.index = index; + this.item = item; + this.propertyName = propertyName; + this.property = property; + this.changedCount = changedCount; + + if (previousValues) { + // previous values only available for item property changes + this.previousValues = previousValues; + } + } + + function addItems(dependentArray, callbacks, cp, propertyName, meta) { + forEach(dependentArray, function (item, index) { + meta.setValue( callbacks.addedItem.call( + this, meta.getValue(), item, new ChangeMeta(dependentArray, item, index, propertyName, cp, dependentArray.length), meta.sugarMeta)); + }, this); + } + + function reset(cp, propertyName) { + var callbacks = cp._callbacks(); + var hadMeta = cp._hasInstanceMeta(this, propertyName); + var meta = cp._instanceMeta(this, propertyName); + + if (hadMeta) { meta.setValue(cp.resetValue(meta.getValue())); } + + if (cp.options.initialize) { + cp.options.initialize.call(this, meta.getValue(), { + property: cp, + propertyName: propertyName + }, meta.sugarMeta); + } + } + + function partiallyRecomputeFor(obj, dependentKey) { + if (arrayBracketPattern.test(dependentKey)) { + return false; + } + + var value = get(obj, dependentKey); + return EmberArray.detect(value); + } + + function ReduceComputedPropertyInstanceMeta(context, propertyName, initialValue) { + this.context = context; + this.propertyName = propertyName; + this.cache = metaFor(context).cache; + this.dependentArrays = {}; + this.sugarMeta = {}; + this.initialValue = initialValue; + } + + ReduceComputedPropertyInstanceMeta.prototype = { + getValue: function () { + var value = cacheGet(this.cache, this.propertyName); + + if (value !== undefined) { + return value; + } else { + return this.initialValue; + } + }, + + setValue: function(newValue, triggerObservers) { + // This lets sugars force a recomputation, handy for very simple + // implementations of eg max. + if (newValue === cacheGet(this.cache, this.propertyName)) { + return; + } + + if (triggerObservers) { + propertyWillChange(this.context, this.propertyName); + } + + if (newValue === undefined) { + cacheRemove(this.cache, this.propertyName); + } else { + cacheSet(this.cache, this.propertyName, newValue); + } + + if (triggerObservers) { + propertyDidChange(this.context, this.propertyName); + } + } + }; + + /** + A computed property whose dependent keys are arrays and which is updated with + "one at a time" semantics. + + @class ReduceComputedProperty + @namespace Ember + @extends Ember.ComputedProperty + @constructor + */ + + __exports__.ReduceComputedProperty = ReduceComputedProperty; + // TODO: default export + + function ReduceComputedProperty(options) { + var cp = this; + + this.options = options; + this._dependentKeys = null; + // A map of dependentKey -> [itemProperty, ...] that tracks what properties of + // items in the array we must track to update this property. + this._itemPropertyKeys = {}; + this._previousItemPropertyKeys = {}; + + this.readOnly(); + this.cacheable(); + + this.recomputeOnce = function(propertyName) { + // What we really want to do is coalesce by . + // We need a form of `scheduleOnce` that accepts an arbitrary token to + // coalesce by, in addition to the target and method. + run.once(this, recompute, propertyName); + }; + + var recompute = function(propertyName) { + var dependentKeys = cp._dependentKeys; + var meta = cp._instanceMeta(this, propertyName); + var callbacks = cp._callbacks(); + + reset.call(this, cp, propertyName); + + meta.dependentArraysObserver.suspendArrayObservers(function () { + forEach(cp._dependentKeys, function (dependentKey) { + + if (!partiallyRecomputeFor(this, dependentKey)) { return; } + + var dependentArray = get(this, dependentKey); + var previousDependentArray = meta.dependentArrays[dependentKey]; + + if (dependentArray === previousDependentArray) { + // The array may be the same, but our item property keys may have + // changed, so we set them up again. We can't easily tell if they've + // changed: the array may be the same object, but with different + // contents. + if (cp._previousItemPropertyKeys[dependentKey]) { + delete cp._previousItemPropertyKeys[dependentKey]; + meta.dependentArraysObserver.setupPropertyObservers(dependentKey, cp._itemPropertyKeys[dependentKey]); + } + } else { + meta.dependentArrays[dependentKey] = dependentArray; + + if (previousDependentArray) { + meta.dependentArraysObserver.teardownObservers(previousDependentArray, dependentKey); + } + + if (dependentArray) { + meta.dependentArraysObserver.setupObservers(dependentArray, dependentKey); + } + } + }, this); + }, this); + + forEach(cp._dependentKeys, function(dependentKey) { + if (!partiallyRecomputeFor(this, dependentKey)) { return; } + + var dependentArray = get(this, dependentKey); + + if (dependentArray) { + addItems.call(this, dependentArray, callbacks, cp, propertyName, meta); + } + }, this); + }; + + + this.func = function (propertyName) { + + recompute.call(this, propertyName); + + return cp._instanceMeta(this, propertyName).getValue(); + }; + } + + ReduceComputedProperty.prototype = o_create(ComputedProperty.prototype); + + function defaultCallback(computedValue) { + return computedValue; + } + + ReduceComputedProperty.prototype._callbacks = function () { + if (!this.callbacks) { + var options = this.options; + + this.callbacks = { + removedItem: options.removedItem || defaultCallback, + addedItem: options.addedItem || defaultCallback + }; + } + + return this.callbacks; + }; + + ReduceComputedProperty.prototype._hasInstanceMeta = function (context, propertyName) { + return !!metaFor(context).cacheMeta[propertyName]; + }; + + ReduceComputedProperty.prototype._instanceMeta = function (context, propertyName) { + var cacheMeta = metaFor(context).cacheMeta; + var meta = cacheMeta[propertyName]; + + if (!meta) { + meta = cacheMeta[propertyName] = new ReduceComputedPropertyInstanceMeta(context, propertyName, this.initialValue()); + meta.dependentArraysObserver = new DependentArraysObserver(this._callbacks(), this, meta, context, propertyName, meta.sugarMeta); + } + + return meta; + }; + + ReduceComputedProperty.prototype.initialValue = function () { + if (typeof this.options.initialValue === 'function') { + return this.options.initialValue(); + } + else { + return this.options.initialValue; + } + }; + + ReduceComputedProperty.prototype.resetValue = function (value) { + return this.initialValue(); + }; + + ReduceComputedProperty.prototype.itemPropertyKey = function (dependentArrayKey, itemPropertyKey) { + this._itemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey] || []; + this._itemPropertyKeys[dependentArrayKey].push(itemPropertyKey); + }; + + ReduceComputedProperty.prototype.clearItemPropertyKeys = function (dependentArrayKey) { + if (this._itemPropertyKeys[dependentArrayKey]) { + this._previousItemPropertyKeys[dependentArrayKey] = this._itemPropertyKeys[dependentArrayKey]; + this._itemPropertyKeys[dependentArrayKey] = []; + } + }; + + ReduceComputedProperty.prototype.property = function () { + var cp = this; + var args = a_slice.call(arguments); + var propertyArgs = {}; + var match, dependentArrayKey, itemPropertyKey; + + forEach(args, function (dependentKey) { + if (doubleEachPropertyPattern.test(dependentKey)) { + throw new EmberError('Nested @each properties not supported: ' + dependentKey); + } else if (match = eachPropertyPattern.exec(dependentKey)) { + dependentArrayKey = match[1]; + + var itemPropertyKeyPattern = match[2]; + var addItemPropertyKey = function (itemPropertyKey) { + cp.itemPropertyKey(dependentArrayKey, itemPropertyKey); + }; + + expandProperties(itemPropertyKeyPattern, addItemPropertyKey); + propertyArgs[guidFor(dependentArrayKey)] = dependentArrayKey; + } else { + propertyArgs[guidFor(dependentKey)] = dependentKey; + } + }); + + var propertyArgsToArray = []; + for (var guid in propertyArgs) { + propertyArgsToArray.push(propertyArgs[guid]); + } + + return ComputedProperty.prototype.property.apply(this, propertyArgsToArray); + }; + + /** + Creates a computed property which operates on dependent arrays and + is updated with "one at a time" semantics. When items are added or + removed from the dependent array(s) a reduce computed only operates + on the change instead of re-evaluating the entire array. + + If there are more than one arguments the first arguments are + considered to be dependent property keys. The last argument is + required to be an options object. The options object can have the + following four properties: + + `initialValue` - A value or function that will be used as the initial + value for the computed. If this property is a function the result of calling + the function will be used as the initial value. This property is required. + + `initialize` - An optional initialize function. Typically this will be used + to set up state on the instanceMeta object. + + `removedItem` - A function that is called each time an element is removed + from the array. + + `addedItem` - A function that is called each time an element is added to + the array. + + + The `initialize` function has the following signature: + + ```javascript + function(initialValue, changeMeta, instanceMeta) + ``` + + `initialValue` - The value of the `initialValue` property from the + options object. + + `changeMeta` - An object which contains meta information about the + computed. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + + The `removedItem` and `addedItem` functions both have the following signature: + + ```javascript + function(accumulatedValue, item, changeMeta, instanceMeta) + ``` + + `accumulatedValue` - The value returned from the last time + `removedItem` or `addedItem` was called or `initialValue`. + + `item` - the element added or removed from the array + + `changeMeta` - An object which contains meta information about the + change. It contains the following properties: + + - `property` the computed property + - `propertyName` the name of the property on the object + - `index` the index of the added or removed item + - `item` the added or removed item: this is exactly the same as + the second arg + - `arrayChanged` the array that triggered the change. Can be + useful when depending on multiple arrays. + + For property changes triggered on an item property change (when + depKey is something like `someArray.@each.someProperty`), + `changeMeta` will also contain the following property: + + - `previousValues` an object whose keys are the properties that changed on + the item, and whose values are the item's previous values. + + `previousValues` is important Ember coalesces item property changes via + Ember.run.once. This means that by the time removedItem gets called, item has + the new values, but you may need the previous value (eg for sorting & + filtering). + + `instanceMeta` - An object that can be used to store meta + information needed for calculating your computed. For example a + unique computed might use this to store the number of times a given + element is found in the dependent array. + + The `removedItem` and `addedItem` functions should return the accumulated + value. It is acceptable to not return anything (ie return undefined) + to invalidate the computation. This is generally not a good idea for + arrayComputed but it's used in eg max and min. + + Note that observers will be fired if either of these functions return a value + that differs from the accumulated value. When returning an object that + mutates in response to array changes, for example an array that maps + everything from some other array (see `Ember.computed.map`), it is usually + important that the *same* array be returned to avoid accidentally triggering observers. + + Example + + ```javascript + Ember.computed.max = function(dependentKey) { + return Ember.reduceComputed(dependentKey, { + initialValue: -Infinity, + + addedItem: function(accumulatedValue, item, changeMeta, instanceMeta) { + return Math.max(accumulatedValue, item); + }, + + removedItem: function(accumulatedValue, item, changeMeta, instanceMeta) { + if (item < accumulatedValue) { + return accumulatedValue; + } + } + }); + }; + ``` + + Dependent keys may refer to `@this` to observe changes to the object itself, + which must be array-like, rather than a property of the object. This is + mostly useful for array proxies, to ensure objects are retrieved via + `objectAtContent`. This is how you could sort items by properties defined on an item controller. + + Example + + ```javascript + App.PeopleController = Ember.ArrayController.extend({ + itemController: 'person', + + sortedPeople: Ember.computed.sort('@this.@each.reversedName', function(personA, personB) { + // `reversedName` isn't defined on Person, but we have access to it via + // the item controller App.PersonController. If we'd used + // `content.@each.reversedName` above, we would be getting the objects + // directly and not have access to `reversedName`. + // + var reversedNameA = get(personA, 'reversedName'); + var reversedNameB = get(personB, 'reversedName'); + + return Ember.compare(reversedNameA, reversedNameB); + }) + }); + + App.PersonController = Ember.ObjectController.extend({ + reversedName: function() { + return reverse(get(this, 'name')); + }.property('name') + }); + ``` + + Dependent keys whose values are not arrays are treated as regular + dependencies: when they change, the computed property is completely + recalculated. It is sometimes useful to have dependent arrays with similar + semantics. Dependent keys which end in `.[]` do not use "one at a time" + semantics. When an item is added or removed from such a dependency, the + computed property is completely recomputed. + + When the computed property is completely recomputed, the `accumulatedValue` + is discarded, it starts with `initialValue` again, and each item is passed + to `addedItem` in turn. + + Example + + ```javascript + Ember.Object.extend({ + // When `string` is changed, `computed` is completely recomputed. + string: 'a string', + + // When an item is added to `array`, `addedItem` is called. + array: [], + + // When an item is added to `anotherArray`, `computed` is completely + // recomputed. + anotherArray: [], + + computed: Ember.reduceComputed('string', 'array', 'anotherArray.[]', { + addedItem: addedItemCallback, + removedItem: removedItemCallback + }) + }); + ``` + + @method reduceComputed + @for Ember + @param {String} [dependentKeys*] + @param {Object} options + @return {Ember.ComputedProperty} + */ + function reduceComputed(options) { + var args; + + if (arguments.length > 1) { + args = a_slice.call(arguments, 0, -1); + options = a_slice.call(arguments, -1)[0]; + } + + if (typeof options !== 'object') { + throw new EmberError('Reduce Computed Property declared without an options hash'); + } + + if (!('initialValue' in options)) { + throw new EmberError('Reduce Computed Property declared without an initial value'); + } + + var cp = new ReduceComputedProperty(options); + + if (args) { + cp.property.apply(cp, args); + } + + return cp; + } + + __exports__.reduceComputed = reduceComputed; + }); +define("ember-runtime/computed/reduce_computed_macros", + ["ember-metal/core","ember-metal/merge","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/enumerable_utils","ember-metal/run_loop","ember-metal/observer","ember-runtime/computed/array_computed","ember-runtime/computed/reduce_computed","ember-runtime/system/object_proxy","ember-runtime/system/subarray","ember-metal/keys","ember-runtime/compare","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var merge = __dependency2__["default"]; + var get = __dependency3__.get; + var set = __dependency4__.set; + var isArray = __dependency5__.isArray; + var guidFor = __dependency5__.guidFor; + var EmberError = __dependency6__["default"]; + var forEach = __dependency7__.forEach; + var run = __dependency8__["default"]; + var addObserver = __dependency9__.addObserver; + var arrayComputed = __dependency10__.arrayComputed; + var reduceComputed = __dependency11__.reduceComputed; + var ObjectProxy = __dependency12__["default"]; + var SubArray = __dependency13__["default"]; + var keys = __dependency14__["default"]; + var compare = __dependency15__["default"]; + + var a_slice = [].slice; + + /** + A computed property that returns the sum of the value + in the dependent array. + + @method computed.sum + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the sum of all values in the dependentKey's array + @since 1.4.0 + */ + + function sum(dependentKey){ + return reduceComputed(dependentKey, { + initialValue: 0, + + addedItem: function(accumulatedValue, item, changeMeta, instanceMeta){ + return accumulatedValue + item; + }, + + removedItem: function(accumulatedValue, item, changeMeta, instanceMeta){ + return accumulatedValue - item; + } + }); + } + + __exports__.sum = sum;/** + A computed property that calculates the maximum value in the + dependent array. This will return `-Infinity` when the dependent + array is empty. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age'), + maxChildAge: Ember.computed.max('childAges') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('maxChildAge'); // -Infinity + lordByron.get('children').pushObject({ + name: 'Augusta Ada Byron', age: 7 + }); + lordByron.get('maxChildAge'); // 7 + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('maxChildAge'); // 8 + ``` + + @method computed.max + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the largest value in the dependentKey's array + */ + function max(dependentKey) { + return reduceComputed(dependentKey, { + initialValue: -Infinity, + + addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + return Math.max(accumulatedValue, item); + }, + + removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + if (item < accumulatedValue) { + return accumulatedValue; + } + } + }); + } + + __exports__.max = max;/** + A computed property that calculates the minimum value in the + dependent array. This will return `Infinity` when the dependent + array is empty. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age'), + minChildAge: Ember.computed.min('childAges') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('minChildAge'); // Infinity + lordByron.get('children').pushObject({ + name: 'Augusta Ada Byron', age: 7 + }); + lordByron.get('minChildAge'); // 7 + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('minChildAge'); // 5 + ``` + + @method computed.min + @for Ember + @param {String} dependentKey + @return {Ember.ComputedProperty} computes the smallest value in the dependentKey's array + */ + function min(dependentKey) { + return reduceComputed(dependentKey, { + initialValue: Infinity, + + addedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + return Math.min(accumulatedValue, item); + }, + + removedItem: function (accumulatedValue, item, changeMeta, instanceMeta) { + if (item > accumulatedValue) { + return accumulatedValue; + } + } + }); + } + + __exports__.min = min;/** + Returns an array mapped via the callback + + The callback method you provide should have the following signature. + `item` is the current item in the iteration. + `index` is the integer index of the current item in the iteration. + + ```javascript + function(item, index); + ``` + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + excitingChores: Ember.computed.map('chores', function(chore, index) { + return chore.toUpperCase() + '!'; + }) + }); + + var hamster = Hamster.create({ + chores: ['clean', 'write more unit tests'] + }); + + hamster.get('excitingChores'); // ['CLEAN!', 'WRITE MORE UNIT TESTS!'] + ``` + + @method computed.map + @for Ember + @param {String} dependentKey + @param {Function} callback + @return {Ember.ComputedProperty} an array mapped via the callback + */ + function map(dependentKey, callback) { + var options = { + addedItem: function(array, item, changeMeta, instanceMeta) { + var mapped = callback.call(this, item, changeMeta.index); + array.insertAt(changeMeta.index, mapped); + return array; + }, + removedItem: function(array, item, changeMeta, instanceMeta) { + array.removeAt(changeMeta.index, 1); + return array; + } + }; + + return arrayComputed(dependentKey, options); + } + + __exports__.map = map;/** + Returns an array mapped to the specified key. + + ```javascript + var Person = Ember.Object.extend({ + childAges: Ember.computed.mapBy('children', 'age') + }); + + var lordByron = Person.create({ children: [] }); + + lordByron.get('childAges'); // [] + lordByron.get('children').pushObject({ name: 'Augusta Ada Byron', age: 7 }); + lordByron.get('childAges'); // [7] + lordByron.get('children').pushObjects([{ + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + }]); + lordByron.get('childAges'); // [7, 5, 8] + ``` + + @method computed.mapBy + @for Ember + @param {String} dependentKey + @param {String} propertyKey + @return {Ember.ComputedProperty} an array mapped to the specified key + */ + function mapBy (dependentKey, propertyKey) { + var callback = function(item) { return get(item, propertyKey); }; + return map(dependentKey + '.@each.' + propertyKey, callback); + } + + __exports__.mapBy = mapBy;/** + @method computed.mapProperty + @for Ember + @deprecated Use `Ember.computed.mapBy` instead + @param dependentKey + @param propertyKey + */ + var mapProperty = mapBy; + __exports__.mapProperty = mapProperty; + /** + Filters the array by the callback. + + The callback method you provide should have the following signature. + `item` is the current item in the iteration. + `index` is the integer index of the current item in the iteration. + + ```javascript + function(item, index); + ``` + + ```javascript + var Hamster = Ember.Object.extend({ + remainingChores: Ember.computed.filter('chores', function(chore, index) { + return !chore.done; + }) + }); + + var hamster = Hamster.create({ + chores: [ + { name: 'cook', done: true }, + { name: 'clean', done: true }, + { name: 'write more unit tests', done: false } + ] + }); + + hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] + ``` + + @method computed.filter + @for Ember + @param {String} dependentKey + @param {Function} callback + @return {Ember.ComputedProperty} the filtered array + */ + function filter(dependentKey, callback) { + var options = { + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.filteredArrayIndexes = new SubArray(); + }, + + addedItem: function (array, item, changeMeta, instanceMeta) { + var match = !!callback.call(this, item, changeMeta.index); + var filterIndex = instanceMeta.filteredArrayIndexes.addItem(changeMeta.index, match); + + if (match) { + array.insertAt(filterIndex, item); + } + + return array; + }, + + removedItem: function(array, item, changeMeta, instanceMeta) { + var filterIndex = instanceMeta.filteredArrayIndexes.removeItem(changeMeta.index); + + if (filterIndex > -1) { + array.removeAt(filterIndex); + } + + return array; + } + }; + + return arrayComputed(dependentKey, options); + } + + __exports__.filter = filter;/** + Filters the array by the property and value + + ```javascript + var Hamster = Ember.Object.extend({ + remainingChores: Ember.computed.filterBy('chores', 'done', false) + }); + + var hamster = Hamster.create({ + chores: [ + { name: 'cook', done: true }, + { name: 'clean', done: true }, + { name: 'write more unit tests', done: false } + ] + }); + + hamster.get('remainingChores'); // [{ name: 'write more unit tests', done: false }] + ``` + + @method computed.filterBy + @for Ember + @param {String} dependentKey + @param {String} propertyKey + @param {*} value + @return {Ember.ComputedProperty} the filtered array + */ + function filterBy (dependentKey, propertyKey, value) { + var callback; + + if (arguments.length === 2) { + callback = function(item) { + return get(item, propertyKey); + }; + } else { + callback = function(item) { + return get(item, propertyKey) === value; + }; + } + + return filter(dependentKey + '.@each.' + propertyKey, callback); + } + + __exports__.filterBy = filterBy;/** + @method computed.filterProperty + @for Ember + @param dependentKey + @param propertyKey + @param value + @deprecated Use `Ember.computed.filterBy` instead + */ + var filterProperty = filterBy; + __exports__.filterProperty = filterProperty; + /** + A computed property which returns a new array with all the unique + elements from one or more dependent arrays. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + uniqueFruits: Ember.computed.uniq('fruits') + }); + + var hamster = Hamster.create({ + fruits: [ + 'banana', + 'grape', + 'kale', + 'banana' + ] + }); + + hamster.get('uniqueFruits'); // ['banana', 'grape', 'kale'] + ``` + + @method computed.uniq + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + unique elements from the dependent array + */ + function uniq() { + var args = a_slice.call(arguments); + + args.push({ + initialize: function(array, changeMeta, instanceMeta) { + instanceMeta.itemCounts = {}; + }, + + addedItem: function(array, item, changeMeta, instanceMeta) { + var guid = guidFor(item); + + if (!instanceMeta.itemCounts[guid]) { + instanceMeta.itemCounts[guid] = 1; + array.pushObject(item); + } else { + ++instanceMeta.itemCounts[guid]; + } + return array; + }, + + removedItem: function(array, item, _, instanceMeta) { + var guid = guidFor(item); + var itemCounts = instanceMeta.itemCounts; + + if (--itemCounts[guid] === 0) { + array.removeObject(item); + } + + return array; + } + }); + + return arrayComputed.apply(null, args); + } + + __exports__.uniq = uniq;/** + Alias for [Ember.computed.uniq](/api/#method_computed_uniq). + + @method computed.union + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + unique elements from the dependent array + */ + var union = uniq; + __exports__.union = union; + /** + A computed property which returns a new array with all the duplicated + elements from two or more dependent arrays. + + Example + + ```javascript + var obj = Ember.Object.createWithMixins({ + adaFriends: ['Charles Babbage', 'John Hobhouse', 'William King', 'Mary Somerville'], + charlesFriends: ['William King', 'Mary Somerville', 'Ada Lovelace', 'George Peacock'], + friendsInCommon: Ember.computed.intersect('adaFriends', 'charlesFriends') + }); + + obj.get('friendsInCommon'); // ['William King', 'Mary Somerville'] + ``` + + @method computed.intersect + @for Ember + @param {String} propertyKey* + @return {Ember.ComputedProperty} computes a new array with all the + duplicated elements from the dependent arrays + */ + function intersect() { + var args = a_slice.call(arguments); + + args.push({ + initialize: function (array, changeMeta, instanceMeta) { + instanceMeta.itemCounts = {}; + }, + + addedItem: function(array, item, changeMeta, instanceMeta) { + var itemGuid = guidFor(item); + var dependentGuid = guidFor(changeMeta.arrayChanged); + var numberOfDependentArrays = changeMeta.property._dependentKeys.length; + var itemCounts = instanceMeta.itemCounts; + + if (!itemCounts[itemGuid]) { + itemCounts[itemGuid] = {}; + } + + if (itemCounts[itemGuid][dependentGuid] === undefined) { + itemCounts[itemGuid][dependentGuid] = 0; + } + + if (++itemCounts[itemGuid][dependentGuid] === 1 && + numberOfDependentArrays === keys(itemCounts[itemGuid]).length) { + array.addObject(item); + } + + return array; + }, + + removedItem: function(array, item, changeMeta, instanceMeta) { + var itemGuid = guidFor(item); + var dependentGuid = guidFor(changeMeta.arrayChanged); + var numberOfDependentArrays = changeMeta.property._dependentKeys.length; + var numberOfArraysItemAppearsIn; + var itemCounts = instanceMeta.itemCounts; + + if (itemCounts[itemGuid][dependentGuid] === undefined) { + itemCounts[itemGuid][dependentGuid] = 0; + } + + if (--itemCounts[itemGuid][dependentGuid] === 0) { + delete itemCounts[itemGuid][dependentGuid]; + numberOfArraysItemAppearsIn = keys(itemCounts[itemGuid]).length; + + if (numberOfArraysItemAppearsIn === 0) { + delete itemCounts[itemGuid]; + } + + array.removeObject(item); + } + + return array; + } + }); + + return arrayComputed.apply(null, args); + } + + __exports__.intersect = intersect;/** + A computed property which returns a new array with all the + properties from the first dependent array that are not in the second + dependent array. + + Example + + ```javascript + var Hamster = Ember.Object.extend({ + likes: ['banana', 'grape', 'kale'], + wants: Ember.computed.setDiff('likes', 'fruits') + }); + + var hamster = Hamster.create({ + fruits: [ + 'grape', + 'kale', + ] + }); + + hamster.get('wants'); // ['banana'] + ``` + + @method computed.setDiff + @for Ember + @param {String} setAProperty + @param {String} setBProperty + @return {Ember.ComputedProperty} computes a new array with all the + items from the first dependent array that are not in the second + dependent array + */ + function setDiff(setAProperty, setBProperty) { + if (arguments.length !== 2) { + throw new EmberError('setDiff requires exactly two dependent arrays.'); + } + + return arrayComputed(setAProperty, setBProperty, { + addedItem: function (array, item, changeMeta, instanceMeta) { + var setA = get(this, setAProperty); + var setB = get(this, setBProperty); + + if (changeMeta.arrayChanged === setA) { + if (!setB.contains(item)) { + array.addObject(item); + } + } else { + array.removeObject(item); + } + + return array; + }, + + removedItem: function (array, item, changeMeta, instanceMeta) { + var setA = get(this, setAProperty); + var setB = get(this, setBProperty); + + if (changeMeta.arrayChanged === setB) { + if (setA.contains(item)) { + array.addObject(item); + } + } else { + array.removeObject(item); + } + + return array; + } + }); + } + + __exports__.setDiff = setDiff;function binarySearch(array, item, low, high) { + var mid, midItem, res, guidMid, guidItem; + + if (arguments.length < 4) { + high = get(array, 'length'); + } + + if (arguments.length < 3) { + low = 0; + } + + if (low === high) { + return low; + } + + mid = low + Math.floor((high - low) / 2); + midItem = array.objectAt(mid); + + guidMid = _guidFor(midItem); + guidItem = _guidFor(item); + + if (guidMid === guidItem) { + return mid; + } + + res = this.order(midItem, item); + + if (res === 0) { + res = guidMid < guidItem ? -1 : 1; + } + + + if (res < 0) { + return this.binarySearch(array, item, mid+1, high); + } else if (res > 0) { + return this.binarySearch(array, item, low, mid); + } + + return mid; + + function _guidFor(item) { + if (SearchProxy.detectInstance(item)) { + return guidFor(get(item, 'content')); + } + + return guidFor(item); + } + } + + + var SearchProxy = ObjectProxy.extend(); + + /** + A computed property which returns a new array with all the + properties from the first dependent array sorted based on a property + or sort function. + + The callback method you provide should have the following signature: + + ```javascript + function(itemA, itemB); + ``` + + - `itemA` the first item to compare. + - `itemB` the second item to compare. + + This function should return negative number (e.g. `-1`) when `itemA` should come before + `itemB`. It should return positive number (e.g. `1`) when `itemA` should come after + `itemB`. If the `itemA` and `itemB` are equal this function should return `0`. + + Therefore, if this function is comparing some numeric values, simple `itemA - itemB` or + `itemA.get( 'foo' ) - itemB.get( 'foo' )` can be used instead of series of `if`. + + Example + + ```javascript + var ToDoList = Ember.Object.extend({ + // using standard ascending sort + todosSorting: ['name'], + sortedTodos: Ember.computed.sort('todos', 'todosSorting'), + + // using descending sort + todosSortingDesc: ['name:desc'], + sortedTodosDesc: Ember.computed.sort('todos', 'todosSortingDesc'), + + // using a custom sort function + priorityTodos: Ember.computed.sort('todos', function(a, b){ + if (a.priority > b.priority) { + return 1; + } else if (a.priority < b.priority) { + return -1; + } + + return 0; + }) + }); + + var todoList = ToDoList.create({todos: [ + { name: 'Unit Test', priority: 2 }, + { name: 'Documentation', priority: 3 }, + { name: 'Release', priority: 1 } + ]}); + + todoList.get('sortedTodos'); // [{ name:'Documentation', priority:3 }, { name:'Release', priority:1 }, { name:'Unit Test', priority:2 }] + todoList.get('sortedTodosDesc'); // [{ name:'Unit Test', priority:2 }, { name:'Release', priority:1 }, { name:'Documentation', priority:3 }] + todoList.get('priorityTodos'); // [{ name:'Release', priority:1 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] + ``` + + @method computed.sort + @for Ember + @param {String} dependentKey + @param {String or Function} sortDefinition a dependent key to an + array of sort properties (add `:desc` to the arrays sort properties to sort descending) or a function to use when sorting + @return {Ember.ComputedProperty} computes a new sorted array based + on the sort property array or callback function + */ + function sort(itemsKey, sortDefinition) { + + var initFn, sortPropertiesKey; + + if (typeof sortDefinition === 'function') { + initFn = function (array, changeMeta, instanceMeta) { + instanceMeta.order = sortDefinition; + instanceMeta.binarySearch = binarySearch; + }; + } else { + sortPropertiesKey = sortDefinition; + + initFn = function (array, changeMeta, instanceMeta) { + function setupSortProperties() { + var sortPropertyDefinitions = get(this, sortPropertiesKey); + var sortProperties = instanceMeta.sortProperties = []; + var sortPropertyAscending = instanceMeta.sortPropertyAscending = {}; + var sortProperty, idx, asc; + + + changeMeta.property.clearItemPropertyKeys(itemsKey); + + forEach(sortPropertyDefinitions, function (sortPropertyDefinition) { + if ((idx = sortPropertyDefinition.indexOf(':')) !== -1) { + sortProperty = sortPropertyDefinition.substring(0, idx); + asc = sortPropertyDefinition.substring(idx+1).toLowerCase() !== 'desc'; + } else { + sortProperty = sortPropertyDefinition; + asc = true; + } + + sortProperties.push(sortProperty); + sortPropertyAscending[sortProperty] = asc; + changeMeta.property.itemPropertyKey(itemsKey, sortProperty); + }); + + sortPropertyDefinitions.addObserver('@each', this, updateSortPropertiesOnce); + } + + function updateSortPropertiesOnce() { + run.once(this, updateSortProperties, changeMeta.propertyName); + } + + function updateSortProperties(propertyName) { + setupSortProperties.call(this); + changeMeta.property.recomputeOnce.call(this, propertyName); + } + + addObserver(this, sortPropertiesKey, updateSortPropertiesOnce); + setupSortProperties.call(this); + + instanceMeta.order = function (itemA, itemB) { + var isProxy = itemB instanceof SearchProxy; + var sortProperty, result, asc; + + for (var i = 0; i < this.sortProperties.length; ++i) { + sortProperty = this.sortProperties[i]; + result = compare(get(itemA, sortProperty), isProxy ? itemB[sortProperty] : get(itemB, sortProperty)); + + if (result !== 0) { + asc = this.sortPropertyAscending[sortProperty]; + return asc ? result : (-1 * result); + } + } + + return 0; + }; + + instanceMeta.binarySearch = binarySearch; + }; + } + + return arrayComputed(itemsKey, { + initialize: initFn, + + addedItem: function (array, item, changeMeta, instanceMeta) { + var index = instanceMeta.binarySearch(array, item); + array.insertAt(index, item); + + return array; + }, + + removedItem: function (array, item, changeMeta, instanceMeta) { + var proxyProperties, index, searchItem; + + if (changeMeta.previousValues) { + proxyProperties = merge({ content: item }, changeMeta.previousValues); + + searchItem = SearchProxy.create(proxyProperties); + } else { + searchItem = item; + } + + index = instanceMeta.binarySearch(array, searchItem); + array.removeAt(index); + + return array; + } + }); + } + + __exports__.sort = sort; + }); +define("ember-runtime/controllers/array_controller", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/enumerable_utils","ember-runtime/system/array_proxy","ember-runtime/mixins/sortable","ember-runtime/mixins/controller","ember-metal/computed","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var forEach = __dependency4__.forEach; + var replace = __dependency4__.replace; + var ArrayProxy = __dependency5__["default"]; + var SortableMixin = __dependency6__["default"]; + var ControllerMixin = __dependency7__["default"]; + var computed = __dependency8__.computed; + var EmberError = __dependency9__["default"]; + + + /** + `Ember.ArrayController` provides a way for you to publish a collection of + objects so that you can easily bind to the collection from a Handlebars + `#each` helper, an `Ember.CollectionView`, or other controllers. + + The advantage of using an `ArrayController` is that you only have to set up + your view bindings once; to change what's displayed, simply swap out the + `model` property on the controller. + + For example, imagine you wanted to display a list of items fetched via an XHR + request. Create an `Ember.ArrayController` and set its `model` property: + + ```javascript + MyApp.listController = Ember.ArrayController.create(); + + $.get('people.json', function(data) { + MyApp.listController.set('model', data); + }); + ``` + + Then, create a view that binds to your new controller: + + ```handlebars + {{#each MyApp.listController}} + {{firstName}} {{lastName}} + {{/each}} + ``` + + Although you are binding to the controller, the behavior of this controller + is to pass through any methods or properties to the underlying array. This + capability comes from `Ember.ArrayProxy`, which this class inherits from. + + Sometimes you want to display computed properties within the body of an + `#each` helper that depend on the underlying items in `model`, but are not + present on those items. To do this, set `itemController` to the name of a + controller (probably an `ObjectController`) that will wrap each individual item. + + For example: + + ```handlebars + {{#each post in controller}} +
  • {{post.title}} ({{post.titleLength}} characters)
  • + {{/each}} + ``` + + ```javascript + App.PostsController = Ember.ArrayController.extend({ + itemController: 'post' + }); + + App.PostController = Ember.ObjectController.extend({ + // the `title` property will be proxied to the underlying post. + titleLength: function() { + return this.get('title').length; + }.property('title') + }); + ``` + + In some cases it is helpful to return a different `itemController` depending + on the particular item. Subclasses can do this by overriding + `lookupItemController`. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + lookupItemController: function( object ) { + if (object.get('isSpecial')) { + return "special"; // use App.SpecialController + } else { + return "regular"; // use App.RegularController + } + } + }); + ``` + + The itemController instances will have a `parentController` property set to + the `ArrayController` instance. + + @class ArrayController + @namespace Ember + @extends Ember.ArrayProxy + @uses Ember.SortableMixin + @uses Ember.ControllerMixin + */ + + __exports__["default"] = ArrayProxy.extend(ControllerMixin, SortableMixin, { + + /** + The controller used to wrap items, if any. If the value is a string, it will + be used to lookup the container for the controller. As an alternative, you + can also provide a controller class as the value. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + itemController: Ember.ObjectController.extend({ + //Item Controller Implementation + }) + }); + ``` + + @property itemController + @type String | Ember.Controller + @default null + */ + itemController: null, + + /** + Return the name of the controller to wrap items, or `null` if items should + be returned directly. The default implementation simply returns the + `itemController` property, but subclasses can override this method to return + different controllers for different objects. + + For example: + + ```javascript + App.MyArrayController = Ember.ArrayController.extend({ + lookupItemController: function( object ) { + if (object.get('isSpecial')) { + return "special"; // use App.SpecialController + } else { + return "regular"; // use App.RegularController + } + } + }); + ``` + + @method lookupItemController + @param {Object} object + @return {String} + */ + lookupItemController: function(object) { + return get(this, 'itemController'); + }, + + objectAtContent: function(idx) { + var length = get(this, 'length'); + var arrangedContent = get(this, 'arrangedContent'); + var object = arrangedContent && arrangedContent.objectAt(idx); + var controllerClass; + + if (idx >= 0 && idx < length) { + controllerClass = this.lookupItemController(object); + + if (controllerClass) { + return this.controllerAt(idx, object, controllerClass); + } + } + + // When `controllerClass` is falsy, we have not opted in to using item + // controllers, so return the object directly. + + // When the index is out of range, we want to return the "out of range" + // value, whatever that might be. Rather than make assumptions + // (e.g. guessing `null` or `undefined`) we defer this to `arrangedContent`. + return object; + }, + + arrangedContentDidChange: function() { + this._super(); + this._resetSubControllers(); + }, + + arrayContentDidChange: function(idx, removedCnt, addedCnt) { + var subControllers = this._subControllers; + + if (subControllers.length) { + var subControllersToRemove = subControllers.slice(idx, idx + removedCnt); + + forEach(subControllersToRemove, function(subController) { + if (subController) { + subController.destroy(); + } + }); + + replace(subControllers, idx, removedCnt, new Array(addedCnt)); + } + + // The shadow array of subcontrollers must be updated before we trigger + // observers, otherwise observers will get the wrong subcontainer when + // calling `objectAt` + this._super(idx, removedCnt, addedCnt); + }, + + init: function() { + this._super(); + this._subControllers = []; + }, + + model: computed(function () { + return Ember.A(); + }), + + /** + * Flag to mark as being "virtual". Used to keep this instance + * from participating in the parentController hierarchy. + * + * @private + * @property _isVirtual + * @type Boolean + */ + _isVirtual: false, + + controllerAt: function(idx, object, controllerClass) { + var container = get(this, 'container'); + var subControllers = this._subControllers; + var fullName, subController, subControllerFactory, parentController, options; + + if (subControllers.length > idx) { + subController = subControllers[idx]; + + if (subController) { + return subController; + } + } + + if (this._isVirtual) { + parentController = get(this, 'parentController'); + } else { + parentController = this; + } + + + fullName = 'controller:' + controllerClass; + + if (!container.has(fullName)) { + throw new EmberError('Could not resolve itemController: "' + controllerClass + '"'); + } + + subController = container.lookupFactory(fullName).create({ + target: parentController, + parentController: parentController, + model: object + }); + + + subControllers[idx] = subController; + + return subController; + }, + + _subControllers: null, + + _resetSubControllers: function() { + var controller; + var subControllers = this._subControllers; + + if (subControllers.length) { + for (var i = 0, length = subControllers.length; length > i; i++) { + controller = subControllers[i]; + + if (controller) { + controller.destroy(); + } + } + + subControllers.length = 0; + } + }, + + willDestroy: function() { + this._resetSubControllers(); + this._super(); + } + }); + }); +define("ember-runtime/controllers/controller", + ["ember-runtime/system/object","ember-runtime/mixins/controller","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + var Mixin = __dependency2__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + /** + @class Controller + @namespace Ember + @extends Ember.Object + @uses Ember.ControllerMixin + */ + __exports__["default"] = EmberObject.extend(Mixin); + }); +define("ember-runtime/controllers/object_controller", + ["ember-runtime/mixins/controller","ember-runtime/system/object_proxy","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var ControllerMixin = __dependency1__["default"]; + var ObjectProxy = __dependency2__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + /** + `Ember.ObjectController` is part of Ember's Controller layer. It is intended + to wrap a single object, proxying unhandled attempts to `get` and `set` to the underlying + model object, and to forward unhandled action attempts to its `target`. + + `Ember.ObjectController` derives this functionality from its superclass + `Ember.ObjectProxy` and the `Ember.ControllerMixin` mixin. + + @class ObjectController + @namespace Ember + @extends Ember.ObjectProxy + @uses Ember.ControllerMixin + **/ + __exports__["default"] = ObjectProxy.extend(ControllerMixin); + }); +define("ember-runtime/copy", + ["ember-metal/enumerable_utils","ember-metal/utils","ember-runtime/system/object","ember-runtime/mixins/copyable","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var indexOf = __dependency1__.indexOf; + var typeOf = __dependency2__.typeOf; + var EmberObject = __dependency3__["default"]; + var Copyable = __dependency4__["default"]; + + function _copy(obj, deep, seen, copies) { + var ret, loc, key; + + // primitive data types are immutable, just return them. + if (typeof obj !== 'object' || obj === null) { + return obj; + } + + // avoid cyclical loops + if (deep && (loc = indexOf(seen, obj)) >= 0) { + return copies[loc]; + } + + + // IMPORTANT: this specific test will detect a native array only. Any other + // object will need to implement Copyable. + if (typeOf(obj) === 'array') { + ret = obj.slice(); + + if (deep) { + loc = ret.length; + + while (--loc >= 0) { + ret[loc] = _copy(ret[loc], deep, seen, copies); + } + } + } else if (Copyable && Copyable.detect(obj)) { + ret = obj.copy(deep, seen, copies); + } else if (obj instanceof Date) { + ret = new Date(obj.getTime()); + } else { + ret = {}; + + for (key in obj) { + // support Null prototype + if (!Object.prototype.hasOwnProperty.call(obj, key)) { + continue; + } + + // Prevents browsers that don't respect non-enumerability from + // copying internal Ember properties + if (key.substring(0, 2) === '__') { + continue; + } + + ret[key] = deep ? _copy(obj[key], deep, seen, copies) : obj[key]; + } + } + + if (deep) { + seen.push(obj); + copies.push(ret); + } + + return ret; + } + + /** + Creates a clone of the passed object. This function can take just about + any type of object and create a clone of it, including primitive values + (which are not actually cloned because they are immutable). + + If the passed object implements the `clone()` method, then this function + will simply call that method and return the result. + + @method copy + @for Ember + @param {Object} obj The object to clone + @param {Boolean} deep If true, a deep copy of the object is made + @return {Object} The cloned object + */ + __exports__["default"] = function copy(obj, deep) { + // fast paths + if ('object' !== typeof obj || obj === null) { + return obj; // can't copy primitives + } + + if (Copyable && Copyable.detect(obj)) { + return obj.copy(deep); + } + + return _copy(obj, deep, deep ? [] : null, deep ? [] : null); + } + }); +define("ember-runtime/core", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + /** + Compares two objects, returning true if they are logically equal. This is + a deeper comparison than a simple triple equal. For sets it will compare the + internal objects. For any other object that implements `isEqual()` it will + respect that method. + + ```javascript + Ember.isEqual('hello', 'hello'); // true + Ember.isEqual(1, 2); // false + Ember.isEqual([4, 2], [4, 2]); // false + ``` + + @method isEqual + @for Ember + @param {Object} a first object to compare + @param {Object} b second object to compare + @return {Boolean} + */ + var isEqual = function isEqual(a, b) { + if (a && typeof a.isEqual === 'function') { + return a.isEqual(b); + } + + if (a instanceof Date && b instanceof Date) { + return a.getTime() === b.getTime(); + } + + return a === b; + }; + __exports__.isEqual = isEqual; + }); +define("ember-runtime/ext/function", + ["ember-metal/core","ember-metal/expand_properties","ember-metal/computed","ember-metal/mixin"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.EXTEND_PROTOTYPES, Ember.assert + var expandProperties = __dependency2__["default"]; + var computed = __dependency3__.computed; + var observer = __dependency4__.observer; + + var a_slice = Array.prototype.slice; + var FunctionPrototype = Function.prototype; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Function) { + + /** + The `property` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + `true`, which is the default. + + Computed properties allow you to treat a function like a property: + + ```javascript + MyApp.President = Ember.Object.extend({ + firstName: '', + lastName: '', + + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + }.property() // Call this flag to mark the function as a property + }); + + var president = MyApp.President.create({ + firstName: 'Barack', + lastName: 'Obama' + }); + + president.get('fullName'); // 'Barack Obama' + ``` + + Treating a function like a property is useful because they can work with + bindings, just like any other property. + + Many computed properties have dependencies on other properties. For + example, in the above example, the `fullName` property depends on + `firstName` and `lastName` to determine its value. You can tell Ember + about these dependencies like this: + + ```javascript + MyApp.President = Ember.Object.extend({ + firstName: '', + lastName: '', + + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + + // Tell Ember.js that this computed property depends on firstName + // and lastName + }.property('firstName', 'lastName') + }); + ``` + + Make sure you list these dependencies so Ember knows when to update + bindings that connect to a computed property. Changing a dependency + will not immediately trigger an update of the computed property, but + will instead clear the cache so that it is updated when the next `get` + is called on the property. + + See [Ember.ComputedProperty](/api/classes/Ember.ComputedProperty.html), [Ember.computed](/api/#method_computed). + + @method property + @for Function + */ + FunctionPrototype.property = function () { + var ret = computed(this); + // ComputedProperty.prototype.property expands properties; no need for us to + // do so here. + return ret.property.apply(ret, arguments); + }; + + /** + The `observes` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + true, which is the default. + + You can observe property changes simply by adding the `observes` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property changes + }.observes('value') + }); + ``` + + In the future this method may become asynchronous. If you want to ensure + synchronous behavior, use `observesImmediately`. + + See `Ember.observer`. + + @method observes + @for Function + */ + FunctionPrototype.observes = function() { + var length = arguments.length; + var args = new Array(length); + for (var x = 0; x < length; x++) { + args[x] = arguments[x]; + } + return observer.apply(this, args.concat(this)); + }; + + /** + The `observesImmediately` extension of Javascript's Function prototype is + available when `Ember.EXTEND_PROTOTYPES` or + `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. + + You can observe property changes simply by adding the `observesImmediately` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes immediately after the "value" property changes + }.observesImmediately('value') + }); + ``` + + In the future, `observes` may become asynchronous. In this event, + `observesImmediately` will maintain the synchronous behavior. + + See `Ember.immediateObserver`. + + @method observesImmediately + @for Function + */ + FunctionPrototype.observesImmediately = function () { + for (var i = 0, l = arguments.length; i < l; i++) { + var arg = arguments[i]; + } + + // observes handles property expansion + return this.observes.apply(this, arguments); + }; + + /** + The `observesBefore` extension of Javascript's Function prototype is + available when `Ember.EXTEND_PROTOTYPES` or + `Ember.EXTEND_PROTOTYPES.Function` is true, which is the default. + + You can get notified when a property change is about to happen by + by adding the `observesBefore` call to the end of your method + declarations in classes that you write. For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property is about to change + }.observesBefore('value') + }); + ``` + + See `Ember.beforeObserver`. + + @method observesBefore + @for Function + */ + FunctionPrototype.observesBefore = function () { + var watched = []; + var addWatchedProperty = function (obs) { + watched.push(obs); + }; + + for (var i = 0, l = arguments.length; i < l; ++i) { + expandProperties(arguments[i], addWatchedProperty); + } + + this.__ember_observesBefore__ = watched; + + return this; + }; + + /** + The `on` extension of Javascript's Function prototype is available + when `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Function` is + true, which is the default. + + You can listen for events simply by adding the `on` call to the end of + your method declarations in classes or mixins that you write. For example: + + ```javascript + Ember.Mixin.create({ + doSomethingWithElement: function() { + // Executes whenever the "didInsertElement" event fires + }.on('didInsertElement') + }); + ``` + + See `Ember.on`. + + @method on + @for Function + */ + FunctionPrototype.on = function () { + var events = a_slice.call(arguments); + this.__ember_listens__ = events; + + return this; + }; + } + }); +define("ember-runtime/ext/rsvp", + ["ember-metal/core","ember-metal/logger","ember-metal/run_loop","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /* globals RSVP:true */ + + var Ember = __dependency1__["default"]; + var Logger = __dependency2__["default"]; + var run = __dependency3__["default"]; + + var RSVP = requireModule('rsvp'); + var testModuleName = 'ember-testing/test'; + var Test; + + var asyncStart = function() { + if (Ember.Test && Ember.Test.adapter) { + Ember.Test.adapter.asyncStart(); + } + }; + + var asyncEnd = function() { + if (Ember.Test && Ember.Test.adapter) { + Ember.Test.adapter.asyncEnd(); + } + }; + + RSVP.configure('async', function(callback, promise) { + var async = !run.currentRunLoop; + + if (Ember.testing && async) { asyncStart(); } + + run.backburner.schedule('actions', function(){ + if (Ember.testing && async) { asyncEnd(); } + callback(promise); + }); + }); + + RSVP.Promise.prototype.fail = function(callback, label){ + return this['catch'](callback, label); + }; + + RSVP.onerrorDefault = function (error) { + if (error instanceof Error) { + if (Ember.testing) { + // ES6TODO: remove when possible + if (!Test && Ember.__loader.registry[testModuleName]) { + Test = requireModule(testModuleName)['default']; + } + + if (Test && Test.adapter) { + Test.adapter.exception(error); + } else { + throw error; + } + } else if (Ember.onerror) { + Ember.onerror(error); + } else { + Logger.error(error.stack); + } + } + }; + + RSVP.on('error', RSVP.onerrorDefault); + + __exports__["default"] = RSVP; + }); +define("ember-runtime/ext/string", + ["ember-metal/core","ember-runtime/system/string"], + function(__dependency1__, __dependency2__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.EXTEND_PROTOTYPES, Ember.assert, Ember.FEATURES + var fmt = __dependency2__.fmt; + var w = __dependency2__.w; + var loc = __dependency2__.loc; + var camelize = __dependency2__.camelize; + var decamelize = __dependency2__.decamelize; + var dasherize = __dependency2__.dasherize; + var underscore = __dependency2__.underscore; + var capitalize = __dependency2__.capitalize; + var classify = __dependency2__.classify; + + var StringPrototype = String.prototype; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { + + /** + See [Ember.String.fmt](/api/classes/Ember.String.html#method_fmt). + + @method fmt + @for String + */ + StringPrototype.fmt = function () { + return fmt(this, arguments); + }; + + /** + See [Ember.String.w](/api/classes/Ember.String.html#method_w). + + @method w + @for String + */ + StringPrototype.w = function () { + return w(this); + }; + + /** + See [Ember.String.loc](/api/classes/Ember.String.html#method_loc). + + @method loc + @for String + */ + StringPrototype.loc = function () { + return loc(this, arguments); + }; + + /** + See [Ember.String.camelize](/api/classes/Ember.String.html#method_camelize). + + @method camelize + @for String + */ + StringPrototype.camelize = function () { + return camelize(this); + }; + + /** + See [Ember.String.decamelize](/api/classes/Ember.String.html#method_decamelize). + + @method decamelize + @for String + */ + StringPrototype.decamelize = function () { + return decamelize(this); + }; + + /** + See [Ember.String.dasherize](/api/classes/Ember.String.html#method_dasherize). + + @method dasherize + @for String + */ + StringPrototype.dasherize = function () { + return dasherize(this); + }; + + /** + See [Ember.String.underscore](/api/classes/Ember.String.html#method_underscore). + + @method underscore + @for String + */ + StringPrototype.underscore = function () { + return underscore(this); + }; + + /** + See [Ember.String.classify](/api/classes/Ember.String.html#method_classify). + + @method classify + @for String + */ + StringPrototype.classify = function () { + return classify(this); + }; + + /** + See [Ember.String.capitalize](/api/classes/Ember.String.html#method_capitalize). + + @method capitalize + @for String + */ + StringPrototype.capitalize = function () { + return capitalize(this); + }; + } + }); +define("ember-runtime/mixins/-proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/observer","ember-metal/property_events","ember-metal/computed","ember-metal/properties","ember-metal/mixin","ember-runtime/system/string","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var meta = __dependency4__.meta; + var addObserver = __dependency5__.addObserver; + var removeObserver = __dependency5__.removeObserver; + var addBeforeObserver = __dependency5__.addBeforeObserver; + var removeBeforeObserver = __dependency5__.removeBeforeObserver; + var propertyWillChange = __dependency6__.propertyWillChange; + var propertyDidChange = __dependency6__.propertyDidChange; + var computed = __dependency7__.computed; + var defineProperty = __dependency8__.defineProperty; + var Mixin = __dependency9__.Mixin; + var observer = __dependency9__.observer; + var fmt = __dependency10__.fmt; + var EmberObject = __dependency11__["default"]; + + function contentPropertyWillChange(content, contentKey) { + var key = contentKey.slice(8); // remove "content." + if (key in this) { return; } // if shadowed in proxy + propertyWillChange(this, key); + } + + function contentPropertyDidChange(content, contentKey) { + var key = contentKey.slice(8); // remove "content." + if (key in this) { return; } // if shadowed in proxy + propertyDidChange(this, key); + } + + /** + `Ember.ProxyMixin` forwards all properties not defined by the proxy itself + to a proxied `content` object. See Ember.ObjectProxy for more details. + + @class ProxyMixin + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + The object whose properties will be forwarded. + + @property content + @type Ember.Object + @default null + */ + content: null, + _contentDidChange: observer('content', function() { + }), + + isTruthy: computed.bool('content'), + + _debugContainerKey: null, + + willWatchProperty: function (key) { + var contentKey = 'content.' + key; + addBeforeObserver(this, contentKey, null, contentPropertyWillChange); + addObserver(this, contentKey, null, contentPropertyDidChange); + }, + + didUnwatchProperty: function (key) { + var contentKey = 'content.' + key; + removeBeforeObserver(this, contentKey, null, contentPropertyWillChange); + removeObserver(this, contentKey, null, contentPropertyDidChange); + }, + + unknownProperty: function (key) { + var content = get(this, 'content'); + if (content) { + return get(content, key); + } + }, + + setUnknownProperty: function (key, value) { + var m = meta(this); + if (m.proto === this) { + // if marked as prototype then just defineProperty + // rather than delegate + defineProperty(this, key, null, value); + return value; + } + + var content = get(this, 'content'); + return set(content, key, value); + } + + }); + }); +define("ember-runtime/mixins/action_handler", + ["ember-metal/merge","ember-metal/mixin","ember-metal/property_get","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var merge = __dependency1__["default"]; + var Mixin = __dependency2__.Mixin; + var get = __dependency3__.get; + var typeOf = __dependency4__.typeOf; + + /** + The `Ember.ActionHandler` mixin implements support for moving an `actions` + property to an `_actions` property at extend time, and adding `_actions` + to the object's mergedProperties list. + + `Ember.ActionHandler` is available on some familiar classes including + `Ember.Route`, `Ember.View`, `Ember.Component`, and controllers such as + `Ember.Controller` and `Ember.ObjectController`. + (Internally the mixin is used by `Ember.CoreView`, `Ember.ControllerMixin`, + and `Ember.Route` and available to the above classes through + inheritance.) + + @class ActionHandler + @namespace Ember + */ + var ActionHandler = Mixin.create({ + mergedProperties: ['_actions'], + + /** + The collection of functions, keyed by name, available on this + `ActionHandler` as action targets. + + These functions will be invoked when a matching `{{action}}` is triggered + from within a template and the application's current route is this route. + + Actions can also be invoked from other parts of your application + via `ActionHandler#send`. + + The `actions` hash will inherit action handlers from + the `actions` hash defined on extended parent classes + or mixins rather than just replace the entire hash, e.g.: + + ```js + App.CanDisplayBanner = Ember.Mixin.create({ + actions: { + displayBanner: function(msg) { + // ... + } + } + }); + + App.WelcomeRoute = Ember.Route.extend(App.CanDisplayBanner, { + actions: { + playMusic: function() { + // ... + } + } + }); + + // `WelcomeRoute`, when active, will be able to respond + // to both actions, since the actions hash is merged rather + // then replaced when extending mixins / parent classes. + this.send('displayBanner'); + this.send('playMusic'); + ``` + + Within a Controller, Route, View or Component's action handler, + the value of the `this` context is the Controller, Route, View or + Component object: + + ```js + App.SongRoute = Ember.Route.extend({ + actions: { + myAction: function() { + this.controllerFor("song"); + this.transitionTo("other.route"); + ... + } + } + }); + ``` + + It is also possible to call `this._super()` from within an + action handler if it overrides a handler defined on a parent + class or mixin: + + Take for example the following routes: + + ```js + App.DebugRoute = Ember.Mixin.create({ + actions: { + debugRouteInformation: function() { + console.debug("trololo"); + } + } + }); + + App.AnnoyingDebugRoute = Ember.Route.extend(App.DebugRoute, { + actions: { + debugRouteInformation: function() { + // also call the debugRouteInformation of mixed in App.DebugRoute + this._super(); + + // show additional annoyance + window.alert(...); + } + } + }); + ``` + + ## Bubbling + + By default, an action will stop bubbling once a handler defined + on the `actions` hash handles it. To continue bubbling the action, + you must return `true` from the handler: + + ```js + App.Router.map(function() { + this.resource("album", function() { + this.route("song"); + }); + }); + + App.AlbumRoute = Ember.Route.extend({ + actions: { + startPlaying: function() { + } + } + }); + + App.AlbumSongRoute = Ember.Route.extend({ + actions: { + startPlaying: function() { + // ... + + if (actionShouldAlsoBeTriggeredOnParentRoute) { + return true; + } + } + } + }); + ``` + + @property actions + @type Hash + @default null + */ + + /** + Moves `actions` to `_actions` at extend time. Note that this currently + modifies the mixin themselves, which is technically dubious but + is practically of little consequence. This may change in the future. + + @private + @method willMergeMixin + */ + willMergeMixin: function(props) { + var hashName; + + if (!props._actions) { + + if (typeOf(props.actions) === 'object') { + hashName = 'actions'; + } else if (typeOf(props.events) === 'object') { + hashName = 'events'; + } + + if (hashName) { + props._actions = merge(props._actions || {}, props[hashName]); + } + + delete props[hashName]; + } + }, + + /** + Triggers a named action on the `ActionHandler`. Any parameters + supplied after the `actionName` string will be passed as arguments + to the action target function. + + If the `ActionHandler` has its `target` property set, actions may + bubble to the `target`. Bubbling happens when an `actionName` can + not be found in the `ActionHandler`'s `actions` hash or if the + action target function returns `true`. + + Example + + ```js + App.WelcomeRoute = Ember.Route.extend({ + actions: { + playTheme: function() { + this.send('playMusic', 'theme.mp3'); + }, + playMusic: function(track) { + // ... + } + } + }); + ``` + + @method send + @param {String} actionName The action to trigger + @param {*} context a context to send with the action + */ + send: function(actionName) { + var args = [].slice.call(arguments, 1); + var target; + + if (this._actions && this._actions[actionName]) { + if (this._actions[actionName].apply(this, args) === true) { + // handler returned true, so this action will bubble + } else { + return; + } + } + + if (target = get(this, 'target')) { + target.send.apply(target, arguments); + } + } + }); + + __exports__["default"] = ActionHandler; + }); +define("ember-runtime/mixins/array", + ["ember-metal/core","ember-metal/property_get","ember-metal/computed","ember-metal/is_none","ember-runtime/mixins/enumerable","ember-metal/enumerable_utils","ember-metal/mixin","ember-metal/property_events","ember-metal/events","ember-metal/watching","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // .......................................................... + // HELPERS + // + var Ember = __dependency1__["default"]; + // ES6TODO: Ember.A + var get = __dependency2__.get; + var computed = __dependency3__.computed; + var cacheFor = __dependency3__.cacheFor; + var isNone = __dependency4__.isNone; + var none = __dependency4__.none; + var Enumerable = __dependency5__["default"]; + var map = __dependency6__.map; + var Mixin = __dependency7__.Mixin; + var required = __dependency7__.required; + var propertyWillChange = __dependency8__.propertyWillChange; + var propertyDidChange = __dependency8__.propertyDidChange; + var addListener = __dependency9__.addListener; + var removeListener = __dependency9__.removeListener; + var sendEvent = __dependency9__.sendEvent; + var hasListeners = __dependency9__.hasListeners; + var isWatching = __dependency10__.isWatching; + + function arrayObserversHelper(obj, target, opts, operation, notify) { + var willChange = (opts && opts.willChange) || 'arrayWillChange'; + var didChange = (opts && opts.didChange) || 'arrayDidChange'; + var hasObservers = get(obj, 'hasArrayObservers'); + + if (hasObservers === notify) { + propertyWillChange(obj, 'hasArrayObservers'); + } + + operation(obj, '@array:before', target, willChange); + operation(obj, '@array:change', target, didChange); + + if (hasObservers === notify) { + propertyDidChange(obj, 'hasArrayObservers'); + } + + return obj; + } + + // .......................................................... + // ARRAY + // + /** + This mixin implements Observer-friendly Array-like behavior. It is not a + concrete implementation, but it can be used up by other classes that want + to appear like arrays. + + For example, ArrayProxy and ArrayController are both concrete classes that can + be instantiated to implement array-like behavior. Both of these classes use + the Array Mixin by way of the MutableArray mixin, which allows observable + changes to be made to the underlying array. + + Unlike `Ember.Enumerable,` this mixin defines methods specifically for + collections that provide index-ordered access to their contents. When you + are designing code that needs to accept any kind of Array-like object, you + should use these methods instead of Array primitives because these will + properly notify observers of changes to the array. + + Although these methods are efficient, they do add a layer of indirection to + your application so it is a good idea to use them only when you need the + flexibility of using both true JavaScript arrays and "virtual" arrays such + as controllers and collections. + + You can use the methods defined in this module to access and modify array + contents in a KVO-friendly way. You can also be notified whenever the + membership of an array changes by using `.observes('myArray.[]')`. + + To support `Ember.Array` in your own class, you must override two + primitives to use it: `replace()` and `objectAt()`. + + Note that the Ember.Array mixin also incorporates the `Ember.Enumerable` + mixin. All `Ember.Array`-like objects are also enumerable. + + @class Array + @namespace Ember + @uses Ember.Enumerable + @since Ember 0.9.0 + */ + __exports__["default"] = Mixin.create(Enumerable, { + + /** + Your array must support the `length` property. Your replace methods should + set this property whenever it changes. + + @property {Number} length + */ + length: required(), + + /** + Returns the object at the given `index`. If the given `index` is negative + or is greater or equal than the array length, returns `undefined`. + + This is one of the primitives you must implement to support `Ember.Array`. + If your object supports retrieving the value of an array item using `get()` + (i.e. `myArray.get(0)`), then you do not need to implement this method + yourself. + + ```javascript + var arr = ['a', 'b', 'c', 'd']; + + arr.objectAt(0); // 'a' + arr.objectAt(3); // 'd' + arr.objectAt(-1); // undefined + arr.objectAt(4); // undefined + arr.objectAt(5); // undefined + ``` + + @method objectAt + @param {Number} idx The index of the item to return. + @return {*} item at index or undefined + */ + objectAt: function(idx) { + if (idx < 0 || idx >= get(this, 'length')) { + return undefined; + } + + return get(this, idx); + }, + + /** + This returns the objects at the specified indexes, using `objectAt`. + + ```javascript + var arr = ['a', 'b', 'c', 'd']; + + arr.objectsAt([0, 1, 2]); // ['a', 'b', 'c'] + arr.objectsAt([2, 3, 4]); // ['c', 'd', undefined] + ``` + + @method objectsAt + @param {Array} indexes An array of indexes of items to return. + @return {Array} + */ + objectsAt: function(indexes) { + var self = this; + + return map(indexes, function(idx) { + return self.objectAt(idx); + }); + }, + + // overrides Ember.Enumerable version + nextObject: function(idx) { + return this.objectAt(idx); + }, + + /** + This is the handler for the special array content property. If you get + this property, it will return this. If you set this property to a new + array, it will replace the current content. + + This property overrides the default property defined in `Ember.Enumerable`. + + @property [] + @return this + */ + '[]': computed(function(key, value) { + if (value !== undefined) { + this.replace(0, get(this, 'length'), value); + } + + return this; + }), + + firstObject: computed(function() { + return this.objectAt(0); + }), + + lastObject: computed(function() { + return this.objectAt(get(this, 'length') - 1); + }), + + // optimized version from Enumerable + contains: function(obj) { + return this.indexOf(obj) >= 0; + }, + + // Add any extra methods to Ember.Array that are native to the built-in Array. + /** + Returns a new array that is a slice of the receiver. This implementation + uses the observable array methods to retrieve the objects for the new + slice. + + ```javascript + var arr = ['red', 'green', 'blue']; + + arr.slice(0); // ['red', 'green', 'blue'] + arr.slice(0, 2); // ['red', 'green'] + arr.slice(1, 100); // ['green', 'blue'] + ``` + + @method slice + @param {Integer} beginIndex (Optional) index to begin slicing from. + @param {Integer} endIndex (Optional) index to end the slice at (but not included). + @return {Array} New array with specified slice + */ + slice: function(beginIndex, endIndex) { + var ret = Ember.A(); + var length = get(this, 'length'); + + if (isNone(beginIndex)) { + beginIndex = 0; + } + + if (isNone(endIndex) || (endIndex > length)) { + endIndex = length; + } + + if (beginIndex < 0) { + beginIndex = length + beginIndex; + } + + if (endIndex < 0) { + endIndex = length + endIndex; + } + + while (beginIndex < endIndex) { + ret[ret.length] = this.objectAt(beginIndex++); + } + + return ret; + }, + + /** + Returns the index of the given object's first occurrence. + If no `startAt` argument is given, the starting location to + search is 0. If it's negative, will count backward from + the end of the array. Returns -1 if no match is found. + + ```javascript + var arr = ['a', 'b', 'c', 'd', 'a']; + + arr.indexOf('a'); // 0 + arr.indexOf('z'); // -1 + arr.indexOf('a', 2); // 4 + arr.indexOf('a', -1); // 4 + arr.indexOf('b', 3); // -1 + arr.indexOf('a', 100); // -1 + ``` + + @method indexOf + @param {Object} object the item to search for + @param {Number} startAt optional starting location to search, default 0 + @return {Number} index or -1 if not found + */ + indexOf: function(object, startAt) { + var len = get(this, 'length'); + var idx; + + if (startAt === undefined) { + startAt = 0; + } + + if (startAt < 0) { + startAt += len; + } + + for (idx = startAt; idx < len; idx++) { + if (this.objectAt(idx) === object) { + return idx; + } + } + + return -1; + }, + + /** + Returns the index of the given object's last occurrence. + If no `startAt` argument is given, the search starts from + the last position. If it's negative, will count backward + from the end of the array. Returns -1 if no match is found. + + ```javascript + var arr = ['a', 'b', 'c', 'd', 'a']; + + arr.lastIndexOf('a'); // 4 + arr.lastIndexOf('z'); // -1 + arr.lastIndexOf('a', 2); // 0 + arr.lastIndexOf('a', -1); // 4 + arr.lastIndexOf('b', 3); // 1 + arr.lastIndexOf('a', 100); // 4 + ``` + + @method lastIndexOf + @param {Object} object the item to search for + @param {Number} startAt optional starting location to search, default 0 + @return {Number} index or -1 if not found + */ + lastIndexOf: function(object, startAt) { + var len = get(this, 'length'); + var idx; + + if (startAt === undefined || startAt >= len) { + startAt = len-1; + } + + if (startAt < 0) { + startAt += len; + } + + for (idx = startAt; idx >= 0; idx--) { + if (this.objectAt(idx) === object) { + return idx; + } + } + + return -1; + }, + + // .......................................................... + // ARRAY OBSERVERS + // + + /** + Adds an array observer to the receiving array. The array observer object + normally must implement two methods: + + * `arrayWillChange(observedObj, start, removeCount, addCount)` - This method will be + called just before the array is modified. + * `arrayDidChange(observedObj, start, removeCount, addCount)` - This method will be + called just after the array is modified. + + Both callbacks will be passed the observed object, starting index of the + change as well a a count of the items to be removed and added. You can use + these callbacks to optionally inspect the array during the change, clear + caches, or do any other bookkeeping necessary. + + In addition to passing a target, you can also include an options hash + which you can use to override the method names that will be invoked on the + target. + + @method addArrayObserver + @param {Object} target The observer object. + @param {Hash} opts Optional hash of configuration options including + `willChange` and `didChange` option. + @return {Ember.Array} receiver + */ + + addArrayObserver: function(target, opts) { + return arrayObserversHelper(this, target, opts, addListener, false); + }, + + /** + Removes an array observer from the object if the observer is current + registered. Calling this method multiple times with the same object will + have no effect. + + @method removeArrayObserver + @param {Object} target The object observing the array. + @param {Hash} opts Optional hash of configuration options including + `willChange` and `didChange` option. + @return {Ember.Array} receiver + */ + removeArrayObserver: function(target, opts) { + return arrayObserversHelper(this, target, opts, removeListener, true); + }, + + /** + Becomes true whenever the array currently has observers watching changes + on the array. + + @property {Boolean} hasArrayObservers + */ + hasArrayObservers: computed(function() { + return hasListeners(this, '@array:change') || hasListeners(this, '@array:before'); + }), + + /** + If you are implementing an object that supports `Ember.Array`, call this + method just before the array content changes to notify any observers and + invalidate any related properties. Pass the starting index of the change + as well as a delta of the amounts to change. + + @method arrayContentWillChange + @param {Number} startIdx The starting index in the array that will change. + @param {Number} removeAmt The number of items that will be removed. If you + pass `null` assumes 0 + @param {Number} addAmt The number of items that will be added. If you + pass `null` assumes 0. + @return {Ember.Array} receiver + */ + arrayContentWillChange: function(startIdx, removeAmt, addAmt) { + var removing, lim; + + // if no args are passed assume everything changes + if (startIdx === undefined) { + startIdx = 0; + removeAmt = addAmt = -1; + } else { + if (removeAmt === undefined) { + removeAmt = -1; + } + + if (addAmt === undefined) { + addAmt = -1; + } + } + + // Make sure the @each proxy is set up if anyone is observing @each + if (isWatching(this, '@each')) { + get(this, '@each'); + } + + sendEvent(this, '@array:before', [this, startIdx, removeAmt, addAmt]); + + if (startIdx >= 0 && removeAmt >= 0 && get(this, 'hasEnumerableObservers')) { + removing = []; + lim = startIdx + removeAmt; + + for (var idx = startIdx; idx < lim; idx++) { + removing.push(this.objectAt(idx)); + } + } else { + removing = removeAmt; + } + + this.enumerableContentWillChange(removing, addAmt); + + return this; + }, + + /** + If you are implementing an object that supports `Ember.Array`, call this + method just after the array content changes to notify any observers and + invalidate any related properties. Pass the starting index of the change + as well as a delta of the amounts to change. + + @method arrayContentDidChange + @param {Number} startIdx The starting index in the array that did change. + @param {Number} removeAmt The number of items that were removed. If you + pass `null` assumes 0 + @param {Number} addAmt The number of items that were added. If you + pass `null` assumes 0. + @return {Ember.Array} receiver + */ + arrayContentDidChange: function(startIdx, removeAmt, addAmt) { + var adding, lim; + + // if no args are passed assume everything changes + if (startIdx === undefined) { + startIdx = 0; + removeAmt = addAmt = -1; + } else { + if (removeAmt === undefined) { + removeAmt = -1; + } + + if (addAmt === undefined) { + addAmt = -1; + } + } + + if (startIdx >= 0 && addAmt >= 0 && get(this, 'hasEnumerableObservers')) { + adding = []; + lim = startIdx + addAmt; + + for (var idx = startIdx; idx < lim; idx++) { + adding.push(this.objectAt(idx)); + } + } else { + adding = addAmt; + } + + this.enumerableContentDidChange(removeAmt, adding); + sendEvent(this, '@array:change', [this, startIdx, removeAmt, addAmt]); + + var length = get(this, 'length'); + var cachedFirst = cacheFor(this, 'firstObject'); + var cachedLast = cacheFor(this, 'lastObject'); + + if (this.objectAt(0) !== cachedFirst) { + propertyWillChange(this, 'firstObject'); + propertyDidChange(this, 'firstObject'); + } + + if (this.objectAt(length-1) !== cachedLast) { + propertyWillChange(this, 'lastObject'); + propertyDidChange(this, 'lastObject'); + } + + return this; + }, + + // .......................................................... + // ENUMERATED PROPERTIES + // + + /** + Returns a special object that can be used to observe individual properties + on the array. Just get an equivalent property on this object and it will + return an enumerable that maps automatically to the named key on the + member objects. + + If you merely want to watch for any items being added or removed to the array, + use the `[]` property instead of `@each`. + + @property @each + */ + '@each': computed(function() { + if (!this.__each) { + // ES6TODO: GRRRRR + var EachProxy = requireModule('ember-runtime/system/each_proxy')['EachProxy']; + + this.__each = new EachProxy(this); + } + + return this.__each; + }) + }); + }); +define("ember-runtime/mixins/comparable", + ["ember-metal/mixin","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var required = __dependency1__.required; + + /** + @module ember + @submodule ember-runtime + */ + + /** + Implements some standard methods for comparing objects. Add this mixin to + any class you create that can compare its instances. + + You should implement the `compare()` method. + + @class Comparable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + + /** + Override to return the result of the comparison of the two parameters. The + compare method should return: + + - `-1` if `a < b` + - `0` if `a == b` + - `1` if `a > b` + + Default implementation raises an exception. + + @method compare + @param a {Object} the first object to compare + @param b {Object} the second object to compare + @return {Integer} the result of the comparison + */ + compare: required(Function) + }); + }); +define("ember-runtime/mixins/controller", + ["ember-metal/core","ember-metal/property_get","ember-runtime/system/object","ember-metal/mixin","ember-metal/computed","ember-runtime/mixins/action_handler","ember-runtime/mixins/controller_content_model_alias_deprecation","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.deprecate + var get = __dependency2__.get; + var EmberObject = __dependency3__["default"]; + var Mixin = __dependency4__.Mixin; + var computed = __dependency5__.computed; + var ActionHandler = __dependency6__["default"]; + var ControllerContentModelAliasDeprecation = __dependency7__["default"]; + + /** + `Ember.ControllerMixin` provides a standard interface for all classes that + compose Ember's controller layer: `Ember.Controller`, + `Ember.ArrayController`, and `Ember.ObjectController`. + + @class ControllerMixin + @namespace Ember + @uses Ember.ActionHandler + */ + __exports__["default"] = Mixin.create(ActionHandler, ControllerContentModelAliasDeprecation, { + /* ducktype as a controller */ + isController: true, + + /** + The object to which actions from the view should be sent. + + For example, when a Handlebars template uses the `{{action}}` helper, + it will attempt to send the action to the view's controller's `target`. + + By default, the value of the target property is set to the router, and + is injected when a controller is instantiated. This injection is defined + in Ember.Application#buildContainer, and is applied as part of the + applications initialization process. It can also be set after a controller + has been instantiated, for instance when using the render helper in a + template, or when a controller is used as an `itemController`. In most + cases the `target` property will automatically be set to the logical + consumer of actions for the controller. + + @property target + @default null + */ + target: null, + + container: null, + + parentController: null, + + store: null, + + /** + The controller's current model. When retrieving or modifying a controller's + model, this property should be used instead of the `content` property. + + @property model + @public + */ + model: null, + + /** + @private + */ + content: computed.alias('model') + + }); + }); +define("ember-runtime/mixins/controller_content_model_alias_deprecation", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.deprecate + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + + /** + The ControllerContentModelAliasDeprecation mixin is used to provide a useful + deprecation warning when specifying `content` directly on a `Ember.Controller` + (without also specifying `model`). + + Ember versions prior to 1.7 used `model` as an alias of `content`, but due to + much confusion this alias was reversed (so `content` is now an alias of `model). + + This change reduces many caveats with model/content, and also sets a + simple ground rule: Never set a controllers content, rather always set + it's model and ember will do the right thing. + + + `Ember.ControllerContentModelAliasDeprecation` is used internally by Ember in + `Ember.Controller`. + + @class ControllerContentModelAliasDeprecation + @namespace Ember + @private + @since 1.7.0 + */ + __exports__["default"] = Mixin.create({ + /** + @private + + Moves `content` to `model` at extend time if a `model` is not also specified. + + Note that this currently modifies the mixin themselves, which is technically + dubious but is practically of little consequence. This may change in the + future. + + @method willMergeMixin + @since 1.4.0 + */ + willMergeMixin: function(props) { + // Calling super is only OK here since we KNOW that + // there is another Mixin loaded first. + this._super.apply(this, arguments); + + var modelSpecified = !!props.model; + + if (props.content && !modelSpecified) { + props.model = props.content; + delete props['content']; + + } + } + }); + }); +define("ember-runtime/mixins/copyable", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/mixin","ember-runtime/mixins/freezable","ember-runtime/system/string","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + + var get = __dependency1__.get; + var set = __dependency2__.set; + var required = __dependency3__.required; + var Freezable = __dependency4__.Freezable; + var Mixin = __dependency3__.Mixin; + var fmt = __dependency5__.fmt; + var EmberError = __dependency6__["default"]; + + + /** + Implements some standard methods for copying an object. Add this mixin to + any object you create that can create a copy of itself. This mixin is + added automatically to the built-in array. + + You should generally implement the `copy()` method to return a copy of the + receiver. + + Note that `frozenCopy()` will only work if you also implement + `Ember.Freezable`. + + @class Copyable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + /** + Override to return a copy of the receiver. Default implementation raises + an exception. + + @method copy + @param {Boolean} deep if `true`, a deep copy of the object should be made + @return {Object} copy of receiver + */ + copy: required(Function), + + /** + If the object implements `Ember.Freezable`, then this will return a new + copy if the object is not frozen and the receiver if the object is frozen. + + Raises an exception if you try to call this method on a object that does + not support freezing. + + You should use this method whenever you want a copy of a freezable object + since a freezable object can simply return itself without actually + consuming more memory. + + @method frozenCopy + @return {Object} copy of receiver or receiver + */ + frozenCopy: function() { + if (Freezable && Freezable.detect(this)) { + return get(this, 'isFrozen') ? this : this.copy().freeze(); + } else { + throw new EmberError(fmt("%@ does not support freezing", [this])); + } + } + }); + }); +define("ember-runtime/mixins/deferred", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","ember-metal/computed","ember-runtime/ext/rsvp","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.FEATURES, Ember.Test + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + var computed = __dependency4__.computed; + var RSVP = __dependency5__["default"]; + + /** + @module ember + @submodule ember-runtime + */ + + + /** + @class Deferred + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + Add handlers to be called when the Deferred object is resolved or rejected. + + @method then + @param {Function} resolve a callback function to be called when done + @param {Function} reject a callback function to be called when failed + */ + then: function(resolve, reject, label) { + var deferred, promise, entity; + + entity = this; + deferred = get(this, '_deferred'); + promise = deferred.promise; + + function fulfillmentHandler(fulfillment) { + if (fulfillment === promise) { + return resolve(entity); + } else { + return resolve(fulfillment); + } + } + + return promise.then(resolve && fulfillmentHandler, reject, label); + }, + + /** + Resolve a Deferred object and call any `doneCallbacks` with the given args. + + @method resolve + */ + resolve: function(value) { + var deferred, promise; + + deferred = get(this, '_deferred'); + promise = deferred.promise; + + if (value === this) { + deferred.resolve(promise); + } else { + deferred.resolve(value); + } + }, + + /** + Reject a Deferred object and call any `failCallbacks` with the given args. + + @method reject + */ + reject: function(value) { + get(this, '_deferred').reject(value); + }, + + _deferred: computed(function() { + + return RSVP.defer('Ember: DeferredMixin - ' + this); + }) + }); + }); +define("ember-runtime/mixins/enumerable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/enumerable_utils","ember-metal/computed","ember-metal/property_events","ember-metal/events","ember-runtime/compare","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // .......................................................... + // HELPERS + // + + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var set = __dependency3__.set; + var apply = __dependency4__.apply; + var Mixin = __dependency5__.Mixin; + var required = __dependency5__.required; + var aliasMethod = __dependency5__.aliasMethod; + var indexOf = __dependency6__.indexOf; + var computed = __dependency7__.computed; + var propertyWillChange = __dependency8__.propertyWillChange; + var propertyDidChange = __dependency8__.propertyDidChange; + var addListener = __dependency9__.addListener; + var removeListener = __dependency9__.removeListener; + var sendEvent = __dependency9__.sendEvent; + var hasListeners = __dependency9__.hasListeners; + var compare = __dependency10__["default"]; + + var a_slice = Array.prototype.slice; + + var contexts = []; + + function popCtx() { + return contexts.length===0 ? {} : contexts.pop(); + } + + function pushCtx(ctx) { + contexts.push(ctx); + return null; + } + + function iter(key, value) { + var valueProvided = arguments.length === 2; + + function i(item) { + var cur = get(item, key); + return valueProvided ? value===cur : !!cur; + } + + return i; + } + + /** + This mixin defines the common interface implemented by enumerable objects + in Ember. Most of these methods follow the standard Array iteration + API defined up to JavaScript 1.8 (excluding language-specific features that + cannot be emulated in older versions of JavaScript). + + This mixin is applied automatically to the Array class on page load, so you + can use any of these methods on simple arrays. If Array already implements + one of these methods, the mixin will not override them. + + ## Writing Your Own Enumerable + + To make your own custom class enumerable, you need two items: + + 1. You must have a length property. This property should change whenever + the number of items in your enumerable object changes. If you use this + with an `Ember.Object` subclass, you should be sure to change the length + property using `set().` + + 2. You must implement `nextObject().` See documentation. + + Once you have these two methods implemented, apply the `Ember.Enumerable` mixin + to your class and you will be able to enumerate the contents of your object + like any other collection. + + ## Using Ember Enumeration with Other Libraries + + Many other libraries provide some kind of iterator or enumeration like + facility. This is often where the most common API conflicts occur. + Ember's API is designed to be as friendly as possible with other + libraries by implementing only methods that mostly correspond to the + JavaScript 1.8 API. + + @class Enumerable + @namespace Ember + @since Ember 0.9 + */ + __exports__["default"] = Mixin.create({ + + /** + Implement this method to make your class enumerable. + + This method will be call repeatedly during enumeration. The index value + will always begin with 0 and increment monotonically. You don't have to + rely on the index value to determine what object to return, but you should + always check the value and start from the beginning when you see the + requested index is 0. + + The `previousObject` is the object that was returned from the last call + to `nextObject` for the current iteration. This is a useful way to + manage iteration if you are tracing a linked list, for example. + + Finally the context parameter will always contain a hash you can use as + a "scratchpad" to maintain any other state you need in order to iterate + properly. The context object is reused and is not reset between + iterations so make sure you setup the context with a fresh state whenever + the index parameter is 0. + + Generally iterators will continue to call `nextObject` until the index + reaches the your current length-1. If you run out of data before this + time for some reason, you should simply return undefined. + + The default implementation of this method simply looks up the index. + This works great on any Array-like objects. + + @method nextObject + @param {Number} index the current index of the iteration + @param {Object} previousObject the value returned by the last call to + `nextObject`. + @param {Object} context a context object you can use to maintain state. + @return {Object} the next object in the iteration or undefined + */ + nextObject: required(Function), + + /** + Helper method returns the first object from a collection. This is usually + used by bindings and other parts of the framework to extract a single + object if the enumerable contains only one item. + + If you override this method, you should implement it so that it will + always return the same value each time it is called. If your enumerable + contains only one object, this method should always return that object. + If your enumerable is empty, this method should return `undefined`. + + ```javascript + var arr = ["a", "b", "c"]; + arr.get('firstObject'); // "a" + + var arr = []; + arr.get('firstObject'); // undefined + ``` + + @property firstObject + @return {Object} the object or undefined + */ + firstObject: computed('[]', function() { + if (get(this, 'length')===0) return undefined ; + + // handle generic enumerables + var context = popCtx(), ret; + ret = this.nextObject(0, null, context); + pushCtx(context); + return ret; + }), + + /** + Helper method returns the last object from a collection. If your enumerable + contains only one object, this method should always return that object. + If your enumerable is empty, this method should return `undefined`. + + ```javascript + var arr = ["a", "b", "c"]; + arr.get('lastObject'); // "c" + + var arr = []; + arr.get('lastObject'); // undefined + ``` + + @property lastObject + @return {Object} the last object or undefined + */ + lastObject: computed('[]', function() { + var len = get(this, 'length'); + if (len===0) return undefined ; + var context = popCtx(), idx=0, cur, last = null; + do { + last = cur; + cur = this.nextObject(idx++, last, context); + } while (cur !== undefined); + pushCtx(context); + return last; + }), + + /** + Returns `true` if the passed object can be found in the receiver. The + default version will iterate through the enumerable until the object + is found. You may want to override this with a more efficient version. + + ```javascript + var arr = ["a", "b", "c"]; + arr.contains("a"); // true + arr.contains("z"); // false + ``` + + @method contains + @param {Object} obj The object to search for. + @return {Boolean} `true` if object is found in enumerable. + */ + contains: function(obj) { + return this.find(function(item) { return item===obj; }) !== undefined; + }, + + /** + Iterates through the enumerable, calling the passed function on each + item. This method corresponds to the `forEach()` method defined in + JavaScript 1.6. + + The callback method you provide should have the following signature (all + parameters are optional): + + ```javascript + function(item, index, enumerable); + ``` + + - `item` is the current item in the iteration. + - `index` is the current index in the iteration. + - `enumerable` is the enumerable object itself. + + Note that in addition to a callback, you can also pass an optional target + object that will be set as `this` on the context. This is a good way + to give your iterator function access to the current object. + + @method forEach + @param {Function} callback The callback to execute + @param {Object} [target] The target object to use + @return {Object} receiver + */ + forEach: function(callback, target) { + if (typeof callback !== 'function') throw new TypeError() ; + var len = get(this, 'length'), last = null, context = popCtx(); + + if (target === undefined) target = null; + + for(var idx=0;idx1) args = a_slice.call(arguments, 1); + + this.forEach(function(x, idx) { + var method = x && x[methodName]; + if ('function' === typeof method) { + ret[idx] = args ? apply(x, method, args) : x[methodName](); + } + }, this); + + return ret; + }, + + /** + Simply converts the enumerable into a genuine array. The order is not + guaranteed. Corresponds to the method implemented by Prototype. + + @method toArray + @return {Array} the enumerable as an array. + */ + toArray: function() { + var ret = Ember.A(); + this.forEach(function(o, idx) { ret[idx] = o; }); + return ret; + }, + + /** + Returns a copy of the array with all null and undefined elements removed. + + ```javascript + var arr = ["a", null, "c", undefined]; + arr.compact(); // ["a", "c"] + ``` + + @method compact + @return {Array} the array without null and undefined elements. + */ + compact: function() { + return this.filter(function(value) { return value != null; }); + }, + + /** + Returns a new enumerable that excludes the passed value. The default + implementation returns an array regardless of the receiver type unless + the receiver does not contain the value. + + ```javascript + var arr = ["a", "b", "a", "c"]; + arr.without("a"); // ["b", "c"] + ``` + + @method without + @param {Object} value + @return {Ember.Enumerable} + */ + without: function(value) { + if (!this.contains(value)) return this; // nothing to do + var ret = Ember.A(); + this.forEach(function(k) { + if (k !== value) ret[ret.length] = k; + }) ; + return ret ; + }, + + /** + Returns a new enumerable that contains only unique values. The default + implementation returns an array regardless of the receiver type. + + ```javascript + var arr = ["a", "a", "b", "b"]; + arr.uniq(); // ["a", "b"] + ``` + + @method uniq + @return {Ember.Enumerable} + */ + uniq: function() { + var ret = Ember.A(); + this.forEach(function(k) { + if (indexOf(ret, k)<0) ret.push(k); + }); + return ret; + }, + + /** + This property will trigger anytime the enumerable's content changes. + You can observe this property to be notified of changes to the enumerables + content. + + For plain enumerables, this property is read only. `Array` overrides + this method. + + @property [] + @type Array + @return this + */ + '[]': computed(function(key, value) { + return this; + }), + + // .......................................................... + // ENUMERABLE OBSERVERS + // + + /** + Registers an enumerable observer. Must implement `Ember.EnumerableObserver` + mixin. + + @method addEnumerableObserver + @param {Object} target + @param {Hash} [opts] + @return this + */ + addEnumerableObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'enumerableWillChange'; + var didChange = (opts && opts.didChange) || 'enumerableDidChange'; + var hasObservers = get(this, 'hasEnumerableObservers'); + + if (!hasObservers) propertyWillChange(this, 'hasEnumerableObservers'); + addListener(this, '@enumerable:before', target, willChange); + addListener(this, '@enumerable:change', target, didChange); + if (!hasObservers) propertyDidChange(this, 'hasEnumerableObservers'); + return this; + }, + + /** + Removes a registered enumerable observer. + + @method removeEnumerableObserver + @param {Object} target + @param {Hash} [opts] + @return this + */ + removeEnumerableObserver: function(target, opts) { + var willChange = (opts && opts.willChange) || 'enumerableWillChange'; + var didChange = (opts && opts.didChange) || 'enumerableDidChange'; + + var hasObservers = get(this, 'hasEnumerableObservers'); + if (hasObservers) propertyWillChange(this, 'hasEnumerableObservers'); + removeListener(this, '@enumerable:before', target, willChange); + removeListener(this, '@enumerable:change', target, didChange); + if (hasObservers) propertyDidChange(this, 'hasEnumerableObservers'); + return this; + }, + + /** + Becomes true whenever the array currently has observers watching changes + on the array. + + @property hasEnumerableObservers + @type Boolean + */ + hasEnumerableObservers: computed(function() { + return hasListeners(this, '@enumerable:change') || hasListeners(this, '@enumerable:before'); + }), + + + /** + Invoke this method just before the contents of your enumerable will + change. You can either omit the parameters completely or pass the objects + to be removed or added if available or just a count. + + @method enumerableContentWillChange + @param {Ember.Enumerable|Number} removing An enumerable of the objects to + be removed or the number of items to be removed. + @param {Ember.Enumerable|Number} adding An enumerable of the objects to be + added or the number of items to be added. + @chainable + */ + enumerableContentWillChange: function(removing, adding) { + + var removeCnt, addCnt, hasDelta; + + if ('number' === typeof removing) removeCnt = removing; + else if (removing) removeCnt = get(removing, 'length'); + else removeCnt = removing = -1; + + if ('number' === typeof adding) addCnt = adding; + else if (adding) addCnt = get(adding,'length'); + else addCnt = adding = -1; + + hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0; + + if (removing === -1) removing = null; + if (adding === -1) adding = null; + + propertyWillChange(this, '[]'); + if (hasDelta) propertyWillChange(this, 'length'); + sendEvent(this, '@enumerable:before', [this, removing, adding]); + + return this; + }, + + /** + Invoke this method when the contents of your enumerable has changed. + This will notify any observers watching for content changes. If you are + implementing an ordered enumerable (such as an array), also pass the + start and end values where the content changed so that it can be used to + notify range observers. + + @method enumerableContentDidChange + @param {Ember.Enumerable|Number} removing An enumerable of the objects to + be removed or the number of items to be removed. + @param {Ember.Enumerable|Number} adding An enumerable of the objects to + be added or the number of items to be added. + @chainable + */ + enumerableContentDidChange: function(removing, adding) { + var removeCnt, addCnt, hasDelta; + + if ('number' === typeof removing) removeCnt = removing; + else if (removing) removeCnt = get(removing, 'length'); + else removeCnt = removing = -1; + + if ('number' === typeof adding) addCnt = adding; + else if (adding) addCnt = get(adding, 'length'); + else addCnt = adding = -1; + + hasDelta = addCnt<0 || removeCnt<0 || addCnt-removeCnt!==0; + + if (removing === -1) removing = null; + if (adding === -1) adding = null; + + sendEvent(this, '@enumerable:change', [this, removing, adding]); + if (hasDelta) propertyDidChange(this, 'length'); + propertyDidChange(this, '[]'); + + return this ; + }, + + /** + Converts the enumerable into an array and sorts by the keys + specified in the argument. + + You may provide multiple arguments to sort by multiple properties. + + @method sortBy + @param {String} property name(s) to sort on + @return {Array} The sorted array. + @since 1.2.0 + */ + sortBy: function() { + var sortKeys = arguments; + return this.toArray().sort(function(a, b){ + for(var i = 0; i < sortKeys.length; i++) { + var key = sortKeys[i]; + var propA = get(a, key); + var propB = get(b, key); + // return 1 or -1 else continue to the next sortKey + var compareValue = compare(propA, propB); + if (compareValue) { return compareValue; } + } + return 0; + }); + } + }); + }); +define("ember-runtime/mixins/evented", + ["ember-metal/mixin","ember-metal/events","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var addListener = __dependency2__.addListener; + var removeListener = __dependency2__.removeListener; + var hasListeners = __dependency2__.hasListeners; + var sendEvent = __dependency2__.sendEvent; + + /** + @module ember + @submodule ember-runtime + */ + + /** + This mixin allows for Ember objects to subscribe to and emit events. + + ```javascript + App.Person = Ember.Object.extend(Ember.Evented, { + greet: function() { + // ... + this.trigger('greet'); + } + }); + + var person = App.Person.create(); + + person.on('greet', function() { + console.log('Our person has greeted'); + }); + + person.greet(); + + // outputs: 'Our person has greeted' + ``` + + You can also chain multiple event subscriptions: + + ```javascript + person.on('greet', function() { + console.log('Our person has greeted'); + }).one('greet', function() { + console.log('Offer one-time special'); + }).off('event', this, forgetThis); + ``` + + @class Evented + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + + /** + Subscribes to a named event with given function. + + ```javascript + person.on('didLoad', function() { + // fired once the person has loaded + }); + ``` + + An optional target can be passed in as the 2nd argument that will + be set as the "this" for the callback. This is a good way to give your + function access to the object triggering the event. When the target + parameter is used the callback becomes the third argument. + + @method on + @param {String} name The name of the event + @param {Object} [target] The "this" binding for the callback + @param {Function} method The callback to execute + @return this + */ + on: function(name, target, method) { + addListener(this, name, target, method); + return this; + }, + + /** + Subscribes a function to a named event and then cancels the subscription + after the first time the event is triggered. It is good to use ``one`` when + you only care about the first time an event has taken place. + + This function takes an optional 2nd argument that will become the "this" + value for the callback. If this argument is passed then the 3rd argument + becomes the function. + + @method one + @param {String} name The name of the event + @param {Object} [target] The "this" binding for the callback + @param {Function} method The callback to execute + @return this + */ + one: function(name, target, method) { + if (!method) { + method = target; + target = null; + } + + addListener(this, name, target, method, true); + return this; + }, + + /** + Triggers a named event for the object. Any additional arguments + will be passed as parameters to the functions that are subscribed to the + event. + + ```javascript + person.on('didEat', function(food) { + console.log('person ate some ' + food); + }); + + person.trigger('didEat', 'broccoli'); + + // outputs: person ate some broccoli + ``` + @method trigger + @param {String} name The name of the event + @param {Object...} args Optional arguments to pass on + */ + trigger: function(name) { + var length = arguments.length; + var args = new Array(length - 1); + + for (var i = 1; i < length; i++) { + args[i - 1] = arguments[i]; + } + + sendEvent(this, name, args); + }, + + /** + Cancels subscription for given name, target, and method. + + @method off + @param {String} name The name of the event + @param {Object} target The target of the subscription + @param {Function} method The function of the subscription + @return this + */ + off: function(name, target, method) { + removeListener(this, name, target, method); + return this; + }, + + /** + Checks to see if object has any subscriptions for named event. + + @method has + @param {String} name The name of the event + @return {Boolean} does the object have a subscription for event + */ + has: function(name) { + return hasListeners(this, name); + } + }); + }); +define("ember-runtime/mixins/freezable", + ["ember-metal/mixin","ember-metal/property_get","ember-metal/property_set","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Mixin = __dependency1__.Mixin; + var get = __dependency2__.get; + var set = __dependency3__.set; + + /** + The `Ember.Freezable` mixin implements some basic methods for marking an + object as frozen. Once an object is frozen it should be read only. No changes + may be made the internal state of the object. + + ## Enforcement + + To fully support freezing in your subclass, you must include this mixin and + override any method that might alter any property on the object to instead + raise an exception. You can check the state of an object by checking the + `isFrozen` property. + + Although future versions of JavaScript may support language-level freezing + object objects, that is not the case today. Even if an object is freezable, + it is still technically possible to modify the object, even though it could + break other parts of your application that do not expect a frozen object to + change. It is, therefore, very important that you always respect the + `isFrozen` property on all freezable objects. + + ## Example Usage + + The example below shows a simple object that implement the `Ember.Freezable` + protocol. + + ```javascript + Contact = Ember.Object.extend(Ember.Freezable, { + firstName: null, + lastName: null, + + // swaps the names + swapNames: function() { + if (this.get('isFrozen')) throw Ember.FROZEN_ERROR; + var tmp = this.get('firstName'); + this.set('firstName', this.get('lastName')); + this.set('lastName', tmp); + return this; + } + + }); + + c = Contact.create({ firstName: "John", lastName: "Doe" }); + c.swapNames(); // returns c + c.freeze(); + c.swapNames(); // EXCEPTION + ``` + + ## Copying + + Usually the `Ember.Freezable` protocol is implemented in cooperation with the + `Ember.Copyable` protocol, which defines a `frozenCopy()` method that will + return a frozen object, if the object implements this method as well. + + @class Freezable + @namespace Ember + @since Ember 0.9 + */ + var Freezable = Mixin.create({ + + /** + Set to `true` when the object is frozen. Use this property to detect + whether your object is frozen or not. + + @property isFrozen + @type Boolean + */ + isFrozen: false, + + /** + Freezes the object. Once this method has been called the object should + no longer allow any properties to be edited. + + @method freeze + @return {Object} receiver + */ + freeze: function() { + if (get(this, 'isFrozen')) return this; + set(this, 'isFrozen', true); + return this; + } + + }); + __exports__.Freezable = Freezable; + var FROZEN_ERROR = "Frozen object cannot be modified."; + __exports__.FROZEN_ERROR = FROZEN_ERROR; + }); +define("ember-runtime/mixins/mutable_array", + ["ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/error","ember-metal/mixin","ember-runtime/mixins/array","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + + // require('ember-runtime/mixins/array'); + // require('ember-runtime/mixins/mutable_enumerable'); + + // .......................................................... + // CONSTANTS + // + + var OUT_OF_RANGE_EXCEPTION = "Index out of range"; + var EMPTY = []; + + // .......................................................... + // HELPERS + // + + var get = __dependency1__.get; + var set = __dependency2__.set; + var isArray = __dependency3__.isArray; + var EmberError = __dependency4__["default"]; + var Mixin = __dependency5__.Mixin; + var required = __dependency5__.required; + var EmberArray = __dependency6__["default"]; + var MutableEnumerable = __dependency7__["default"]; + var Enumerable = __dependency8__["default"]; + /** + This mixin defines the API for modifying array-like objects. These methods + can be applied only to a collection that keeps its items in an ordered set. + It builds upon the Array mixin and adds methods to modify the array. + Concrete implementations of this class include ArrayProxy and ArrayController. + + It is important to use the methods in this class to modify arrays so that + changes are observable. This allows the binding system in Ember to function + correctly. + + + Note that an Array can change even if it does not implement this mixin. + For example, one might implement a SparseArray that cannot be directly + modified, but if its underlying enumerable changes, it will change also. + + @class MutableArray + @namespace Ember + @uses Ember.Array + @uses Ember.MutableEnumerable + */ + __exports__["default"] = Mixin.create(EmberArray, MutableEnumerable, { + + /** + __Required.__ You must implement this method to apply this mixin. + + This is one of the primitives you must implement to support `Ember.Array`. + You should replace amt objects started at idx with the objects in the + passed array. You should also call `this.enumerableContentDidChange()` + + @method replace + @param {Number} idx Starting index in the array to replace. If + idx >= length, then append to the end of the array. + @param {Number} amt Number of elements that should be removed from + the array, starting at *idx*. + @param {Array} objects An array of zero or more objects that should be + inserted into the array at *idx* + */ + replace: required(), + + /** + Remove all elements from the array. This is useful if you + want to reuse an existing array without having to recreate it. + + ```javascript + var colors = ["red", "green", "blue"]; + color.length(); // 3 + colors.clear(); // [] + colors.length(); // 0 + ``` + + @method clear + @return {Ember.Array} An empty Array. + */ + clear: function () { + var len = get(this, 'length'); + if (len === 0) return this; + this.replace(0, len, EMPTY); + return this; + }, + + /** + This will use the primitive `replace()` method to insert an object at the + specified index. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.insertAt(2, "yellow"); // ["red", "green", "yellow", "blue"] + colors.insertAt(5, "orange"); // Error: Index out of range + ``` + + @method insertAt + @param {Number} idx index of insert the object at. + @param {Object} object object to insert + @return {Ember.Array} receiver + */ + insertAt: function(idx, object) { + if (idx > get(this, 'length')) throw new EmberError(OUT_OF_RANGE_EXCEPTION); + this.replace(idx, 0, [object]); + return this; + }, + + /** + Remove an object at the specified index using the `replace()` primitive + method. You can pass either a single index, or a start and a length. + + If you pass a start and length that is beyond the + length this method will throw an `OUT_OF_RANGE_EXCEPTION`. + + ```javascript + var colors = ["red", "green", "blue", "yellow", "orange"]; + colors.removeAt(0); // ["green", "blue", "yellow", "orange"] + colors.removeAt(2, 2); // ["green", "blue"] + colors.removeAt(4, 2); // Error: Index out of range + ``` + + @method removeAt + @param {Number} start index, start of range + @param {Number} len length of passing range + @return {Ember.Array} receiver + */ + removeAt: function(start, len) { + if ('number' === typeof start) { + + if ((start < 0) || (start >= get(this, 'length'))) { + throw new EmberError(OUT_OF_RANGE_EXCEPTION); + } + + // fast case + if (len === undefined) len = 1; + this.replace(start, len, EMPTY); + } + + return this; + }, + + /** + Push the object onto the end of the array. Works just like `push()` but it + is KVO-compliant. + + ```javascript + var colors = ["red", "green"]; + colors.pushObject("black"); // ["red", "green", "black"] + colors.pushObject(["yellow"]); // ["red", "green", ["yellow"]] + ``` + + @method pushObject + @param {*} obj object to push + @return object same object passed as a param + */ + pushObject: function(obj) { + this.insertAt(get(this, 'length'), obj); + return obj; + }, + + /** + Add the objects in the passed numerable to the end of the array. Defers + notifying observers of the change until all objects are added. + + ```javascript + var colors = ["red"]; + colors.pushObjects(["yellow", "orange"]); // ["red", "yellow", "orange"] + ``` + + @method pushObjects + @param {Ember.Enumerable} objects the objects to add + @return {Ember.Array} receiver + */ + pushObjects: function(objects) { + if (!(Enumerable.detect(objects) || isArray(objects))) { + throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects"); + } + this.replace(get(this, 'length'), 0, objects); + return this; + }, + + /** + Pop object from array or nil if none are left. Works just like `pop()` but + it is KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.popObject(); // "blue" + console.log(colors); // ["red", "green"] + ``` + + @method popObject + @return object + */ + popObject: function() { + var len = get(this, 'length'); + if (len === 0) return null; + + var ret = this.objectAt(len-1); + this.removeAt(len-1, 1); + return ret; + }, + + /** + Shift an object from start of array or nil if none are left. Works just + like `shift()` but it is KVO-compliant. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.shiftObject(); // "red" + console.log(colors); // ["green", "blue"] + ``` + + @method shiftObject + @return object + */ + shiftObject: function() { + if (get(this, 'length') === 0) return null; + var ret = this.objectAt(0); + this.removeAt(0); + return ret; + }, + + /** + Unshift an object to start of array. Works just like `unshift()` but it is + KVO-compliant. + + ```javascript + var colors = ["red"]; + colors.unshiftObject("yellow"); // ["yellow", "red"] + colors.unshiftObject(["black"]); // [["black"], "yellow", "red"] + ``` + + @method unshiftObject + @param {*} obj object to unshift + @return object same object passed as a param + */ + unshiftObject: function(obj) { + this.insertAt(0, obj); + return obj; + }, + + /** + Adds the named objects to the beginning of the array. Defers notifying + observers until all objects have been added. + + ```javascript + var colors = ["red"]; + colors.unshiftObjects(["black", "white"]); // ["black", "white", "red"] + colors.unshiftObjects("yellow"); // Type Error: 'undefined' is not a function + ``` + + @method unshiftObjects + @param {Ember.Enumerable} objects the objects to add + @return {Ember.Array} receiver + */ + unshiftObjects: function(objects) { + this.replace(0, 0, objects); + return this; + }, + + /** + Reverse objects in the array. Works just like `reverse()` but it is + KVO-compliant. + + @method reverseObjects + @return {Ember.Array} receiver + */ + reverseObjects: function() { + var len = get(this, 'length'); + if (len === 0) return this; + var objects = this.toArray().reverse(); + this.replace(0, len, objects); + return this; + }, + + /** + Replace all the the receiver's content with content of the argument. + If argument is an empty array receiver will be cleared. + + ```javascript + var colors = ["red", "green", "blue"]; + colors.setObjects(["black", "white"]); // ["black", "white"] + colors.setObjects([]); // [] + ``` + + @method setObjects + @param {Ember.Array} objects array whose content will be used for replacing + the content of the receiver + @return {Ember.Array} receiver with the new content + */ + setObjects: function(objects) { + if (objects.length === 0) return this.clear(); + + var len = get(this, 'length'); + this.replace(0, len, objects); + return this; + }, + + // .......................................................... + // IMPLEMENT Ember.MutableEnumerable + // + + /** + Remove all occurances of an object in the array. + + ```javascript + var cities = ["Chicago", "Berlin", "Lima", "Chicago"]; + cities.removeObject("Chicago"); // ["Berlin", "Lima"] + cities.removeObject("Lima"); // ["Berlin"] + cities.removeObject("Tokyo") // ["Berlin"] + ``` + + @method removeObject + @param {*} obj object to remove + @return {Ember.Array} receiver + */ + removeObject: function(obj) { + var loc = get(this, 'length') || 0; + while(--loc >= 0) { + var curObject = this.objectAt(loc); + if (curObject === obj) this.removeAt(loc); + } + return this; + }, + + /** + Push the object onto the end of the array if it is not already + present in the array. + + ```javascript + var cities = ["Chicago", "Berlin"]; + cities.addObject("Lima"); // ["Chicago", "Berlin", "Lima"] + cities.addObject("Berlin"); // ["Chicago", "Berlin", "Lima"] + ``` + + @method addObject + @param {*} obj object to add, if not already present + @return {Ember.Array} receiver + */ + addObject: function(obj) { + if (!this.contains(obj)) this.pushObject(obj); + return this; + } + + }); + }); +define("ember-runtime/mixins/mutable_enumerable", + ["ember-metal/enumerable_utils","ember-runtime/mixins/enumerable","ember-metal/mixin","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var forEach = __dependency1__.forEach; + var Enumerable = __dependency2__["default"]; + var Mixin = __dependency3__.Mixin; + var required = __dependency3__.required; + var beginPropertyChanges = __dependency4__.beginPropertyChanges; + var endPropertyChanges = __dependency4__.endPropertyChanges; + + /** + @module ember + @submodule ember-runtime + */ + + /** + This mixin defines the API for modifying generic enumerables. These methods + can be applied to an object regardless of whether it is ordered or + unordered. + + Note that an Enumerable can change even if it does not implement this mixin. + For example, a MappedEnumerable cannot be directly modified but if its + underlying enumerable changes, it will change also. + + ## Adding Objects + + To add an object to an enumerable, use the `addObject()` method. This + method will only add the object to the enumerable if the object is not + already present and is of a type supported by the enumerable. + + ```javascript + set.addObject(contact); + ``` + + ## Removing Objects + + To remove an object from an enumerable, use the `removeObject()` method. This + will only remove the object if it is present in the enumerable, otherwise + this method has no effect. + + ```javascript + set.removeObject(contact); + ``` + + ## Implementing In Your Own Code + + If you are implementing an object and want to support this API, just include + this mixin in your class and implement the required methods. In your unit + tests, be sure to apply the Ember.MutableEnumerableTests to your object. + + @class MutableEnumerable + @namespace Ember + @uses Ember.Enumerable + */ + __exports__["default"] = Mixin.create(Enumerable, { + + /** + __Required.__ You must implement this method to apply this mixin. + + Attempts to add the passed object to the receiver if the object is not + already present in the collection. If the object is present, this method + has no effect. + + If the passed object is of a type not supported by the receiver, + then this method should raise an exception. + + @method addObject + @param {Object} object The object to add to the enumerable. + @return {Object} the passed object + */ + addObject: required(Function), + + /** + Adds each object in the passed enumerable to the receiver. + + @method addObjects + @param {Ember.Enumerable} objects the objects to add. + @return {Object} receiver + */ + addObjects: function(objects) { + beginPropertyChanges(this); + forEach(objects, function(obj) { this.addObject(obj); }, this); + endPropertyChanges(this); + return this; + }, + + /** + __Required.__ You must implement this method to apply this mixin. + + Attempts to remove the passed object from the receiver collection if the + object is present in the collection. If the object is not present, + this method has no effect. + + If the passed object is of a type not supported by the receiver, + then this method should raise an exception. + + @method removeObject + @param {Object} object The object to remove from the enumerable. + @return {Object} the passed object + */ + removeObject: required(Function), + + + /** + Removes each object in the passed enumerable from the receiver. + + @method removeObjects + @param {Ember.Enumerable} objects the objects to remove + @return {Object} receiver + */ + removeObjects: function(objects) { + beginPropertyChanges(this); + for (var i = objects.length - 1; i >= 0; i--) { + this.removeObject(objects[i]); + } + endPropertyChanges(this); + return this; + } + }); + }); +define("ember-runtime/mixins/observable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/get_properties","ember-metal/set_properties","ember-metal/mixin","ember-metal/events","ember-metal/property_events","ember-metal/observer","ember-metal/computed","ember-metal/is_none","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var getWithDefault = __dependency2__.getWithDefault; + var set = __dependency3__.set; + var apply = __dependency4__.apply; + var getProperties = __dependency5__["default"]; + var setProperties = __dependency6__["default"]; + var Mixin = __dependency7__.Mixin; + var hasListeners = __dependency8__.hasListeners; + var beginPropertyChanges = __dependency9__.beginPropertyChanges; + var propertyWillChange = __dependency9__.propertyWillChange; + var propertyDidChange = __dependency9__.propertyDidChange; + var endPropertyChanges = __dependency9__.endPropertyChanges; + var addObserver = __dependency10__.addObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeObserver = __dependency10__.removeObserver; + var observersFor = __dependency10__.observersFor; + var cacheFor = __dependency11__.cacheFor; + var isNone = __dependency12__.isNone; + + + var slice = Array.prototype.slice; + /** + ## Overview + + This mixin provides properties and property observing functionality, core + features of the Ember object model. + + Properties and observers allow one object to observe changes to a + property on another object. This is one of the fundamental ways that + models, controllers and views communicate with each other in an Ember + application. + + Any object that has this mixin applied can be used in observer + operations. That includes `Ember.Object` and most objects you will + interact with as you write your Ember application. + + Note that you will not generally apply this mixin to classes yourself, + but you will use the features provided by this module frequently, so it + is important to understand how to use it. + + ## Using `get()` and `set()` + + Because of Ember's support for bindings and observers, you will always + access properties using the get method, and set properties using the + set method. This allows the observing objects to be notified and + computed properties to be handled properly. + + More documentation about `get` and `set` are below. + + ## Observing Property Changes + + You typically observe property changes simply by adding the `observes` + call to the end of your method declarations in classes that you write. + For example: + + ```javascript + Ember.Object.extend({ + valueObserver: function() { + // Executes whenever the "value" property changes + }.observes('value') + }); + ``` + + Although this is the most common way to add an observer, this capability + is actually built into the `Ember.Object` class on top of two methods + defined in this mixin: `addObserver` and `removeObserver`. You can use + these two methods to add and remove observers yourself if you need to + do so at runtime. + + To add an observer for a property, call: + + ```javascript + object.addObserver('propertyKey', targetObject, targetAction) + ``` + + This will call the `targetAction` method on the `targetObject` whenever + the value of the `propertyKey` changes. + + Note that if `propertyKey` is a computed property, the observer will be + called when any of the property dependencies are changed, even if the + resulting value of the computed property is unchanged. This is necessary + because computed properties are not computed until `get` is called. + + @class Observable + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + + /** + Retrieves the value of a property from the object. + + This method is usually similar to using `object[keyName]` or `object.keyName`, + however it supports both computed properties and the unknownProperty + handler. + + Because `get` unifies the syntax for accessing all these kinds + of properties, it can make many refactorings easier, such as replacing a + simple property with a computed property, or vice versa. + + ### Computed Properties + + Computed properties are methods defined with the `property` modifier + declared at the end, such as: + + ```javascript + fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); + }.property('firstName', 'lastName') + ``` + + When you call `get` on a computed property, the function will be + called and the return value will be returned instead of the function + itself. + + ### Unknown Properties + + Likewise, if you try to call `get` on a property whose value is + `undefined`, the `unknownProperty()` method will be called on the object. + If this method returns any value other than `undefined`, it will be returned + instead. This allows you to implement "virtual" properties that are + not defined upfront. + + @method get + @param {String} keyName The property to retrieve + @return {Object} The property value or undefined. + */ + get: function(keyName) { + return get(this, keyName); + }, + + /** + To get the values of multiple properties at once, call `getProperties` + with a list of strings or an array: + + ```javascript + record.getProperties('firstName', 'lastName', 'zipCode'); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + is equivalent to: + + ```javascript + record.getProperties(['firstName', 'lastName', 'zipCode']); + // { firstName: 'John', lastName: 'Doe', zipCode: '10011' } + ``` + + @method getProperties + @param {String...|Array} list of keys to get + @return {Hash} + */ + getProperties: function() { + return apply(null, getProperties, [this].concat(slice.call(arguments))); + }, + + /** + Sets the provided key or path to the value. + + This method is generally very similar to calling `object[key] = value` or + `object.key = value`, except that it provides support for computed + properties, the `setUnknownProperty()` method and property observers. + + ### Computed Properties + + If you try to set a value on a key that has a computed property handler + defined (see the `get()` method for an example), then `set()` will call + that method, passing both the value and key instead of simply changing + the value itself. This is useful for those times when you need to + implement a property that is composed of one or more member + properties. + + ### Unknown Properties + + If you try to set a value on a key that is undefined in the target + object, then the `setUnknownProperty()` handler will be called instead. This + gives you an opportunity to implement complex "virtual" properties that + are not predefined on the object. If `setUnknownProperty()` returns + undefined, then `set()` will simply set the value on the object. + + ### Property Observers + + In addition to changing the property, `set()` will also register a property + change with the object. Unless you have placed this call inside of a + `beginPropertyChanges()` and `endPropertyChanges(),` any "local" observers + (i.e. observer methods declared on the same object), will be called + immediately. Any "remote" observers (i.e. observer methods declared on + another object) will be placed in a queue and called at a later time in a + coalesced manner. + + ### Chaining + + In addition to property changes, `set()` returns the value of the object + itself so you can do chaining like this: + + ```javascript + record.set('firstName', 'Charles').set('lastName', 'Jolley'); + ``` + + @method set + @param {String} keyName The property to set + @param {Object} value The value to set or `null`. + @return {Ember.Observable} + */ + set: function(keyName, value) { + set(this, keyName, value); + return this; + }, + + + /** + Sets a list of properties at once. These properties are set inside + a single `beginPropertyChanges` and `endPropertyChanges` batch, so + observers will be buffered. + + ```javascript + record.setProperties({ firstName: 'Charles', lastName: 'Jolley' }); + ``` + + @method setProperties + @param {Hash} hash the hash of keys and values to set + @return {Ember.Observable} + */ + setProperties: function(hash) { + return setProperties(this, hash); + }, + + /** + Begins a grouping of property changes. + + You can use this method to group property changes so that notifications + will not be sent until the changes are finished. If you plan to make a + large number of changes to an object at one time, you should call this + method at the beginning of the changes to begin deferring change + notifications. When you are done making changes, call + `endPropertyChanges()` to deliver the deferred change notifications and end + deferring. + + @method beginPropertyChanges + @return {Ember.Observable} + */ + beginPropertyChanges: function() { + beginPropertyChanges(); + return this; + }, + + /** + Ends a grouping of property changes. + + You can use this method to group property changes so that notifications + will not be sent until the changes are finished. If you plan to make a + large number of changes to an object at one time, you should call + `beginPropertyChanges()` at the beginning of the changes to defer change + notifications. When you are done making changes, call this method to + deliver the deferred change notifications and end deferring. + + @method endPropertyChanges + @return {Ember.Observable} + */ + endPropertyChanges: function() { + endPropertyChanges(); + return this; + }, + + /** + Notify the observer system that a property is about to change. + + Sometimes you need to change a value directly or indirectly without + actually calling `get()` or `set()` on it. In this case, you can use this + method and `propertyDidChange()` instead. Calling these two methods + together will notify all observers that the property has potentially + changed value. + + Note that you must always call `propertyWillChange` and `propertyDidChange` + as a pair. If you do not, it may get the property change groups out of + order and cause notifications to be delivered more often than you would + like. + + @method propertyWillChange + @param {String} keyName The property key that is about to change. + @return {Ember.Observable} + */ + propertyWillChange: function(keyName) { + propertyWillChange(this, keyName); + return this; + }, + + /** + Notify the observer system that a property has just changed. + + Sometimes you need to change a value directly or indirectly without + actually calling `get()` or `set()` on it. In this case, you can use this + method and `propertyWillChange()` instead. Calling these two methods + together will notify all observers that the property has potentially + changed value. + + Note that you must always call `propertyWillChange` and `propertyDidChange` + as a pair. If you do not, it may get the property change groups out of + order and cause notifications to be delivered more often than you would + like. + + @method propertyDidChange + @param {String} keyName The property key that has just changed. + @return {Ember.Observable} + */ + propertyDidChange: function(keyName) { + propertyDidChange(this, keyName); + return this; + }, + + /** + Convenience method to call `propertyWillChange` and `propertyDidChange` in + succession. + + @method notifyPropertyChange + @param {String} keyName The property key to be notified about. + @return {Ember.Observable} + */ + notifyPropertyChange: function(keyName) { + this.propertyWillChange(keyName); + this.propertyDidChange(keyName); + return this; + }, + + addBeforeObserver: function(key, target, method) { + addBeforeObserver(this, key, target, method); + }, + + /** + Adds an observer on a property. + + This is the core method used to register an observer for a property. + + Once you call this method, any time the key's value is set, your observer + will be notified. Note that the observers are triggered any time the + value is set, regardless of whether it has actually changed. Your + observer should be prepared to handle that. + + You can also pass an optional context parameter to this method. The + context will be passed to your observer method whenever it is triggered. + Note that if you add the same target/method pair on a key multiple times + with different context parameters, your observer will only be called once + with the last context you passed. + + ### Observer Methods + + Observer methods you pass should generally have the following signature if + you do not pass a `context` parameter: + + ```javascript + fooDidChange: function(sender, key, value, rev) { }; + ``` + + The sender is the object that changed. The key is the property that + changes. The value property is currently reserved and unused. The rev + is the last property revision of the object when it changed, which you can + use to detect if the key value has really changed or not. + + If you pass a `context` parameter, the context will be passed before the + revision like so: + + ```javascript + fooDidChange: function(sender, key, value, context, rev) { }; + ``` + + Usually you will not need the value, context or revision parameters at + the end. In this case, it is common to write observer methods that take + only a sender and key value as parameters or, if you aren't interested in + any of these values, to write an observer that has no parameters at all. + + @method addObserver + @param {String} key The key to observer + @param {Object} target The target object to invoke + @param {String|Function} method The method to invoke. + */ + addObserver: function(key, target, method) { + addObserver(this, key, target, method); + }, + + /** + Remove an observer you have previously registered on this object. Pass + the same key, target, and method you passed to `addObserver()` and your + target will no longer receive notifications. + + @method removeObserver + @param {String} key The key to observer + @param {Object} target The target object to invoke + @param {String|Function} method The method to invoke. + */ + removeObserver: function(key, target, method) { + removeObserver(this, key, target, method); + }, + + /** + Returns `true` if the object currently has observers registered for a + particular key. You can use this method to potentially defer performing + an expensive action until someone begins observing a particular property + on the object. + + @method hasObserverFor + @param {String} key Key to check + @return {Boolean} + */ + hasObserverFor: function(key) { + return hasListeners(this, key+':change'); + }, + + /** + Retrieves the value of a property, or a default value in the case that the + property returns `undefined`. + + ```javascript + person.getWithDefault('lastName', 'Doe'); + ``` + + @method getWithDefault + @param {String} keyName The name of the property to retrieve + @param {Object} defaultValue The value to return if the property value is undefined + @return {Object} The property value or the defaultValue. + */ + getWithDefault: function(keyName, defaultValue) { + return getWithDefault(this, keyName, defaultValue); + }, + + /** + Set the value of a property to the current value plus some amount. + + ```javascript + person.incrementProperty('age'); + team.incrementProperty('score', 2); + ``` + + @method incrementProperty + @param {String} keyName The name of the property to increment + @param {Number} increment The amount to increment by. Defaults to 1 + @return {Number} The new property value + */ + incrementProperty: function(keyName, increment) { + if (isNone(increment)) { increment = 1; } + set(this, keyName, (parseFloat(get(this, keyName)) || 0) + increment); + return get(this, keyName); + }, + + /** + Set the value of a property to the current value minus some amount. + + ```javascript + player.decrementProperty('lives'); + orc.decrementProperty('health', 5); + ``` + + @method decrementProperty + @param {String} keyName The name of the property to decrement + @param {Number} decrement The amount to decrement by. Defaults to 1 + @return {Number} The new property value + */ + decrementProperty: function(keyName, decrement) { + if (isNone(decrement)) { decrement = 1; } + set(this, keyName, (get(this, keyName) || 0) - decrement); + return get(this, keyName); + }, + + /** + Set the value of a boolean property to the opposite of it's + current value. + + ```javascript + starship.toggleProperty('warpDriveEngaged'); + ``` + + @method toggleProperty + @param {String} keyName The name of the property to toggle + @return {Object} The new property value + */ + toggleProperty: function(keyName) { + set(this, keyName, !get(this, keyName)); + return get(this, keyName); + }, + + /** + Returns the cached value of a computed property, if it exists. + This allows you to inspect the value of a computed property + without accidentally invoking it if it is intended to be + generated lazily. + + @method cacheFor + @param {String} keyName + @return {Object} The cached value of the computed property, if any + */ + cacheFor: function(keyName) { + return cacheFor(this, keyName); + }, + + // intended for debugging purposes + observersForKey: function(keyName) { + return observersFor(this, keyName); + } + }); + }); +define("ember-runtime/mixins/promise_proxy", + ["ember-metal/property_get","ember-metal/set_properties","ember-metal/computed","ember-metal/mixin","ember-metal/error","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var setProperties = __dependency2__["default"]; + var computed = __dependency3__.computed; + var Mixin = __dependency4__.Mixin; + var EmberError = __dependency5__["default"]; + + var not = computed.not; + var or = computed.or; + + /** + @module ember + @submodule ember-runtime + */ + + function tap(proxy, promise) { + setProperties(proxy, { + isFulfilled: false, + isRejected: false + }); + + return promise.then(function(value) { + setProperties(proxy, { + content: value, + isFulfilled: true + }); + return value; + }, function(reason) { + setProperties(proxy, { + reason: reason, + isRejected: true + }); + throw reason; + }, "Ember: PromiseProxy"); + } + + /** + A low level mixin making ObjectProxy, ObjectController or ArrayController's promise aware. + + ```javascript + var ObjectPromiseController = Ember.ObjectController.extend(Ember.PromiseProxyMixin); + + var controller = ObjectPromiseController.create({ + promise: $.getJSON('/some/remote/data.json') + }); + + controller.then(function(json){ + // the json + }, function(reason) { + // the reason why you have no json + }); + ``` + + the controller has bindable attributes which + track the promises life cycle + + ```javascript + controller.get('isPending') //=> true + controller.get('isSettled') //=> false + controller.get('isRejected') //=> false + controller.get('isFulfilled') //=> false + ``` + + When the the $.getJSON completes, and the promise is fulfilled + with json, the life cycle attributes will update accordingly. + + ```javascript + controller.get('isPending') //=> false + controller.get('isSettled') //=> true + controller.get('isRejected') //=> false + controller.get('isFulfilled') //=> true + ``` + + As the controller is an ObjectController, and the json now its content, + all the json properties will be available directly from the controller. + + ```javascript + // Assuming the following json: + { + firstName: 'Stefan', + lastName: 'Penner' + } + + // both properties will accessible on the controller + controller.get('firstName') //=> 'Stefan' + controller.get('lastName') //=> 'Penner' + ``` + + If the controller is backing a template, the attributes are + bindable from within that template + + ```handlebars + {{#if isPending}} + loading... + {{else}} + firstName: {{firstName}} + lastName: {{lastName}} + {{/if}} + ``` + @class Ember.PromiseProxyMixin + */ + __exports__["default"] = Mixin.create({ + /** + If the proxied promise is rejected this will contain the reason + provided. + + @property reason + @default null + */ + reason: null, + + /** + Once the proxied promise has settled this will become `false`. + + @property isPending + @default true + */ + isPending: not('isSettled').readOnly(), + + /** + Once the proxied promise has settled this will become `true`. + + @property isSettled + @default false + */ + isSettled: or('isRejected', 'isFulfilled').readOnly(), + + /** + Will become `true` if the proxied promise is rejected. + + @property isRejected + @default false + */ + isRejected: false, + + /** + Will become `true` if the proxied promise is fulfilled. + + @property isFulfilled + @default false + */ + isFulfilled: false, + + /** + The promise whose fulfillment value is being proxied by this object. + + This property must be specified upon creation, and should not be + changed once created. + + Example: + + ```javascript + Ember.ObjectController.extend(Ember.PromiseProxyMixin).create({ + promise: + }); + ``` + + @property promise + */ + promise: computed(function(key, promise) { + if (arguments.length === 2) { + return tap(this, promise); + } else { + throw new EmberError("PromiseProxy's promise must be set"); + } + }), + + /** + An alias to the proxied promise's `then`. + + See RSVP.Promise.then. + + @method then + @param {Function} callback + @return {RSVP.Promise} + */ + then: promiseAlias('then'), + + /** + An alias to the proxied promise's `catch`. + + See RSVP.Promise.catch. + + @method catch + @param {Function} callback + @return {RSVP.Promise} + @since 1.3.0 + */ + 'catch': promiseAlias('catch'), + + /** + An alias to the proxied promise's `finally`. + + See RSVP.Promise.finally. + + @method finally + @param {Function} callback + @return {RSVP.Promise} + @since 1.3.0 + */ + 'finally': promiseAlias('finally') + + }); + + function promiseAlias(name) { + return function () { + var promise = get(this, 'promise'); + return promise[name].apply(promise, arguments); + }; + } + }); +define("ember-runtime/mixins/sortable", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/enumerable_utils","ember-metal/mixin","ember-runtime/mixins/mutable_enumerable","ember-runtime/compare","ember-metal/observer","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert, Ember.A + + var get = __dependency2__.get; + var set = __dependency3__.set; + var forEach = __dependency4__.forEach; + var Mixin = __dependency5__.Mixin; + var MutableEnumerable = __dependency6__["default"]; + var compare = __dependency7__["default"]; + var addObserver = __dependency8__.addObserver; + var removeObserver = __dependency8__.removeObserver; + var computed = __dependency9__.computed; + var beforeObserver = __dependency5__.beforeObserver; + var observer = __dependency5__.observer; + //ES6TODO: should we access these directly from their package or from how thier exposed in ember-metal? + + /** + `Ember.SortableMixin` provides a standard interface for array proxies + to specify a sort order and maintain this sorting when objects are added, + removed, or updated without changing the implicit order of their underlying + modelarray: + + ```javascript + songs = [ + {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'}, + {trackNumber: 2, title: 'Back in the U.S.S.R.'}, + {trackNumber: 3, title: 'Glass Onion'}, + ]; + + songsController = Ember.ArrayController.create({ + model: songs, + sortProperties: ['trackNumber'], + sortAscending: true + }); + + songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} + + songsController.addObject({trackNumber: 1, title: 'Dear Prudence'}); + songsController.get('firstObject'); // {trackNumber: 1, title: 'Dear Prudence'} + ``` + + If you add or remove the properties to sort by or change the sort direction the model + sort order will be automatically updated. + + ```javascript + songsController.set('sortProperties', ['title']); + songsController.get('firstObject'); // {trackNumber: 2, title: 'Back in the U.S.S.R.'} + + songsController.toggleProperty('sortAscending'); + songsController.get('firstObject'); // {trackNumber: 4, title: 'Ob-La-Di, Ob-La-Da'} + ``` + + SortableMixin works by sorting the arrangedContent array, which is the array that + arrayProxy displays. Due to the fact that the underlying 'content' array is not changed, that + array will not display the sorted list: + + ```javascript + songsController.get('content').get('firstObject'); // Returns the unsorted original content + songsController.get('firstObject'); // Returns the sorted content. + ``` + + Although the sorted content can also be accessed through the arrangedContent property, + it is preferable to use the proxied class and not the arrangedContent array directly. + + @class SortableMixin + @namespace Ember + @uses Ember.MutableEnumerable + */ + __exports__["default"] = Mixin.create(MutableEnumerable, { + + /** + Specifies which properties dictate the arrangedContent's sort order. + + When specifying multiple properties the sorting will use properties + from the `sortProperties` array prioritized from first to last. + + @property {Array} sortProperties + */ + sortProperties: null, + + /** + Specifies the arrangedContent's sort direction. + Sorts the content in ascending order by default. Set to `false` to + use descending order. + + @property {Boolean} sortAscending + @default true + */ + sortAscending: true, + + /** + The function used to compare two values. You can override this if you + want to do custom comparisons. Functions must be of the type expected by + Array#sort, i.e. + return 0 if the two parameters are equal, + return a negative value if the first parameter is smaller than the second or + return a positive value otherwise: + + ```javascript + function(x,y) { // These are assumed to be integers + if (x === y) + return 0; + return x < y ? -1 : 1; + } + ``` + + @property sortFunction + @type {Function} + @default Ember.compare + */ + sortFunction: compare, + + orderBy: function(item1, item2) { + var result = 0; + var sortProperties = get(this, 'sortProperties'); + var sortAscending = get(this, 'sortAscending'); + var sortFunction = get(this, 'sortFunction'); + + + forEach(sortProperties, function(propertyName) { + if (result === 0) { + result = sortFunction.call(this, get(item1, propertyName), get(item2, propertyName)); + if ((result !== 0) && !sortAscending) { + result = (-1) * result; + } + } + }, this); + + return result; + }, + + destroy: function() { + var content = get(this, 'content'); + var sortProperties = get(this, 'sortProperties'); + + if (content && sortProperties) { + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(); + }, + + isSorted: computed.notEmpty('sortProperties'), + + /** + Overrides the default arrangedContent from arrayProxy in order to sort by sortFunction. + Also sets up observers for each sortProperty on each item in the content Array. + + @property arrangedContent + */ + + arrangedContent: computed('content', 'sortProperties.@each', function(key, value) { + var content = get(this, 'content'); + var isSorted = get(this, 'isSorted'); + var sortProperties = get(this, 'sortProperties'); + var self = this; + + if (content && isSorted) { + content = content.slice(); + content.sort(function(item1, item2) { + return self.orderBy(item1, item2); + }); + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + return Ember.A(content); + } + + return content; + }), + + _contentWillChange: beforeObserver('content', function() { + var content = get(this, 'content'); + var sortProperties = get(this, 'sortProperties'); + + if (content && sortProperties) { + forEach(content, function(item) { + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + this._super(); + }), + + sortPropertiesWillChange: beforeObserver('sortProperties', function() { + this._lastSortAscending = undefined; + }), + + sortPropertiesDidChange: observer('sortProperties', function() { + this._lastSortAscending = undefined; + }), + + sortAscendingWillChange: beforeObserver('sortAscending', function() { + this._lastSortAscending = get(this, 'sortAscending'); + }), + + sortAscendingDidChange: observer('sortAscending', function() { + if (this._lastSortAscending !== undefined && get(this, 'sortAscending') !== this._lastSortAscending) { + var arrangedContent = get(this, 'arrangedContent'); + arrangedContent.reverseObjects(); + } + }), + + contentArrayWillChange: function(array, idx, removedCount, addedCount) { + var isSorted = get(this, 'isSorted'); + + if (isSorted) { + var arrangedContent = get(this, 'arrangedContent'); + var removedObjects = array.slice(idx, idx+removedCount); + var sortProperties = get(this, 'sortProperties'); + + forEach(removedObjects, function(item) { + arrangedContent.removeObject(item); + + forEach(sortProperties, function(sortProperty) { + removeObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(array, idx, removedCount, addedCount); + }, + + contentArrayDidChange: function(array, idx, removedCount, addedCount) { + var isSorted = get(this, 'isSorted'); + var sortProperties = get(this, 'sortProperties'); + + if (isSorted) { + var addedObjects = array.slice(idx, idx+addedCount); + + forEach(addedObjects, function(item) { + this.insertItemSorted(item); + + forEach(sortProperties, function(sortProperty) { + addObserver(item, sortProperty, this, 'contentItemSortPropertyDidChange'); + }, this); + }, this); + } + + return this._super(array, idx, removedCount, addedCount); + }, + + insertItemSorted: function(item) { + var arrangedContent = get(this, 'arrangedContent'); + var length = get(arrangedContent, 'length'); + + var idx = this._binarySearch(item, 0, length); + arrangedContent.insertAt(idx, item); + }, + + contentItemSortPropertyDidChange: function(item) { + var arrangedContent = get(this, 'arrangedContent'); + var oldIndex = arrangedContent.indexOf(item); + var leftItem = arrangedContent.objectAt(oldIndex - 1); + var rightItem = arrangedContent.objectAt(oldIndex + 1); + var leftResult = leftItem && this.orderBy(item, leftItem); + var rightResult = rightItem && this.orderBy(item, rightItem); + + if (leftResult < 0 || rightResult > 0) { + arrangedContent.removeObject(item); + this.insertItemSorted(item); + } + }, + + _binarySearch: function(item, low, high) { + var mid, midItem, res, arrangedContent; + + if (low === high) { + return low; + } + + arrangedContent = get(this, 'arrangedContent'); + + mid = low + Math.floor((high - low) / 2); + midItem = arrangedContent.objectAt(mid); + + res = this.orderBy(midItem, item); + + if (res < 0) { + return this._binarySearch(item, mid+1, high); + } else if (res > 0) { + return this._binarySearch(item, low, mid); + } + + return mid; + } + }); + }); +define("ember-runtime/mixins/target_action_support", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/mixin","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.lookup, Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var typeOf = __dependency4__.typeOf; + var Mixin = __dependency5__.Mixin; + var computed = __dependency6__.computed; + + /** + `Ember.TargetActionSupport` is a mixin that can be included in a class + to add a `triggerAction` method with semantics similar to the Handlebars + `{{action}}` helper. In normal Ember usage, the `{{action}}` helper is + usually the best choice. This mixin is most often useful when you are + doing more complex event handling in View objects. + + See also `Ember.ViewTargetActionSupport`, which has + view-aware defaults for target and actionContext. + + @class TargetActionSupport + @namespace Ember + @extends Ember.Mixin + */ + var TargetActionSupport = Mixin.create({ + target: null, + action: null, + actionContext: null, + + targetObject: computed(function() { + var target = get(this, 'target'); + + if (typeOf(target) === "string") { + var value = get(this, target); + if (value === undefined) { value = get(Ember.lookup, target); } + return value; + } else { + return target; + } + }).property('target'), + + actionContextObject: computed(function() { + var actionContext = get(this, 'actionContext'); + + if (typeOf(actionContext) === "string") { + var value = get(this, actionContext); + if (value === undefined) { value = get(Ember.lookup, actionContext); } + return value; + } else { + return actionContext; + } + }).property('actionContext'), + + /** + Send an `action` with an `actionContext` to a `target`. The action, actionContext + and target will be retrieved from properties of the object. For example: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + target: Ember.computed.alias('controller'), + action: 'save', + actionContext: Ember.computed.alias('context'), + click: function() { + this.triggerAction(); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `target`, `action`, and `actionContext` can be provided as properties of + an optional object argument to `triggerAction` as well. + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + click: function() { + this.triggerAction({ + action: 'save', + target: this.get('controller'), + actionContext: this.get('context') + }); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `actionContext` defaults to the object you are mixing `TargetActionSupport` into. + But `target` and `action` must be specified either as properties or with the argument + to `triggerAction`, or a combination: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.TargetActionSupport, { + target: Ember.computed.alias('controller'), + click: function() { + this.triggerAction({ + action: 'save' + }); // Sends the `save` action, along with a reference to `this`, + // to the current controller + } + }); + ``` + + @method triggerAction + @param opts {Hash} (optional, with the optional keys action, target and/or actionContext) + @return {Boolean} true if the action was sent successfully and did not return false + */ + triggerAction: function(opts) { + opts = opts || {}; + var action = opts.action || get(this, 'action'); + var target = opts.target || get(this, 'targetObject'); + var actionContext = opts.actionContext; + + function args(options, actionName) { + var ret = []; + if (actionName) { ret.push(actionName); } + + return ret.concat(options); + } + + if (typeof actionContext === 'undefined') { + actionContext = get(this, 'actionContextObject') || this; + } + + if (target && action) { + var ret; + + if (target.send) { + ret = target.send.apply(target, args(actionContext, action)); + } else { + ret = target[action].apply(target, args(actionContext)); + } + + if (ret !== false) ret = true; + + return ret; + } else { + return false; + } + } + }); + + __exports__["default"] = TargetActionSupport; + }); +define("ember-runtime/system/application", + ["ember-runtime/system/namespace","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Namespace = __dependency1__["default"]; + + __exports__["default"] = Namespace.extend(); + }); +define("ember-runtime/system/array_proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/computed","ember-metal/mixin","ember-metal/property_events","ember-metal/error","ember-runtime/system/object","ember-runtime/mixins/mutable_array","ember-runtime/mixins/enumerable","ember-runtime/system/string","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.K, Ember.assert + var get = __dependency2__.get; + var set = __dependency3__.set; + var isArray = __dependency4__.isArray; + var apply = __dependency4__.apply; + var computed = __dependency5__.computed; + var beforeObserver = __dependency6__.beforeObserver; + var observer = __dependency6__.observer; + var beginPropertyChanges = __dependency7__.beginPropertyChanges; + var endPropertyChanges = __dependency7__.endPropertyChanges; + var EmberError = __dependency8__["default"]; + var EmberObject = __dependency9__["default"]; + var MutableArray = __dependency10__["default"]; + var Enumerable = __dependency11__["default"]; + var fmt = __dependency12__.fmt; + + /** + @module ember + @submodule ember-runtime + */ + + var OUT_OF_RANGE_EXCEPTION = "Index out of range"; + var EMPTY = []; + var alias = computed.alias; + var K = Ember.K; + + /** + An ArrayProxy wraps any other object that implements `Ember.Array` and/or + `Ember.MutableArray,` forwarding all requests. This makes it very useful for + a number of binding use cases or other cases where being able to swap + out the underlying array is useful. + + A simple example of usage: + + ```javascript + var pets = ['dog', 'cat', 'fish']; + var ap = Ember.ArrayProxy.create({ content: Ember.A(pets) }); + + ap.get('firstObject'); // 'dog' + ap.set('content', ['amoeba', 'paramecium']); + ap.get('firstObject'); // 'amoeba' + ``` + + This class can also be useful as a layer to transform the contents of + an array, as they are accessed. This can be done by overriding + `objectAtContent`: + + ```javascript + var pets = ['dog', 'cat', 'fish']; + var ap = Ember.ArrayProxy.create({ + content: Ember.A(pets), + objectAtContent: function(idx) { + return this.get('content').objectAt(idx).toUpperCase(); + } + }); + + ap.get('firstObject'); // . 'DOG' + ``` + + @class ArrayProxy + @namespace Ember + @extends Ember.Object + @uses Ember.MutableArray + */ + var ArrayProxy = EmberObject.extend(MutableArray, { + + /** + The content array. Must be an object that implements `Ember.Array` and/or + `Ember.MutableArray.` + + @property content + @type Ember.Array + */ + content: null, + + /** + The array that the proxy pretends to be. In the default `ArrayProxy` + implementation, this and `content` are the same. Subclasses of `ArrayProxy` + can override this property to provide things like sorting and filtering. + + @property arrangedContent + */ + arrangedContent: alias('content'), + + /** + Should actually retrieve the object at the specified index from the + content. You can override this method in subclasses to transform the + content item to something new. + + This method will only be called if content is non-`null`. + + @method objectAtContent + @param {Number} idx The index to retrieve. + @return {Object} the value or undefined if none found + */ + objectAtContent: function(idx) { + return get(this, 'arrangedContent').objectAt(idx); + }, + + /** + Should actually replace the specified objects on the content array. + You can override this method in subclasses to transform the content item + into something new. + + This method will only be called if content is non-`null`. + + @method replaceContent + @param {Number} idx The starting index + @param {Number} amt The number of items to remove from the content. + @param {Array} objects Optional array of objects to insert or null if no + objects. + @return {void} + */ + replaceContent: function(idx, amt, objects) { + get(this, 'content').replace(idx, amt, objects); + }, + + /** + Invoked when the content property is about to change. Notifies observers that the + entire array content will change. + + @private + @method _contentWillChange + */ + _contentWillChange: beforeObserver('content', function() { + this._teardownContent(); + }), + + _teardownContent: function() { + var content = get(this, 'content'); + + if (content) { + content.removeArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + } + }, + + /** + Override to implement content array `willChange` observer. + + @method contentArrayWillChange + + @param {Ember.Array} contentArray the content array + @param {Number} start starting index of the change + @param {Number} removeCount count of items removed + @param {Number} addCount count of items added + + */ + contentArrayWillChange: K, + /** + Override to implement content array `didChange` observer. + + @method contentArrayDidChange + + @param {Ember.Array} contentArray the content array + @param {Number} start starting index of the change + @param {Number} removeCount count of items removed + @param {Number} addCount count of items added + */ + contentArrayDidChange: K, + + /** + Invoked when the content property changes. Notifies observers that the + entire array content has changed. + + @private + @method _contentDidChange + */ + _contentDidChange: observer('content', function() { + var content = get(this, 'content'); + + + this._setupContent(); + }), + + _setupContent: function() { + var content = get(this, 'content'); + + if (content) { + + content.addArrayObserver(this, { + willChange: 'contentArrayWillChange', + didChange: 'contentArrayDidChange' + }); + } + }, + + _arrangedContentWillChange: beforeObserver('arrangedContent', function() { + var arrangedContent = get(this, 'arrangedContent'); + var len = arrangedContent ? get(arrangedContent, 'length') : 0; + + this.arrangedContentArrayWillChange(this, 0, len, undefined); + this.arrangedContentWillChange(this); + + this._teardownArrangedContent(arrangedContent); + }), + + _arrangedContentDidChange: observer('arrangedContent', function() { + var arrangedContent = get(this, 'arrangedContent'); + var len = arrangedContent ? get(arrangedContent, 'length') : 0; + + + this._setupArrangedContent(); + + this.arrangedContentDidChange(this); + this.arrangedContentArrayDidChange(this, 0, undefined, len); + }), + + _setupArrangedContent: function() { + var arrangedContent = get(this, 'arrangedContent'); + + if (arrangedContent) { + + arrangedContent.addArrayObserver(this, { + willChange: 'arrangedContentArrayWillChange', + didChange: 'arrangedContentArrayDidChange' + }); + } + }, + + _teardownArrangedContent: function() { + var arrangedContent = get(this, 'arrangedContent'); + + if (arrangedContent) { + arrangedContent.removeArrayObserver(this, { + willChange: 'arrangedContentArrayWillChange', + didChange: 'arrangedContentArrayDidChange' + }); + } + }, + + arrangedContentWillChange: K, + arrangedContentDidChange: K, + + objectAt: function(idx) { + return get(this, 'content') && this.objectAtContent(idx); + }, + + length: computed(function() { + var arrangedContent = get(this, 'arrangedContent'); + return arrangedContent ? get(arrangedContent, 'length') : 0; + // No dependencies since Enumerable notifies length of change + }), + + _replace: function(idx, amt, objects) { + var content = get(this, 'content'); + if (content) this.replaceContent(idx, amt, objects); + return this; + }, + + replace: function() { + if (get(this, 'arrangedContent') === get(this, 'content')) { + apply(this, this._replace, arguments); + } else { + throw new EmberError("Using replace on an arranged ArrayProxy is not allowed."); + } + }, + + _insertAt: function(idx, object) { + if (idx > get(this, 'content.length')) throw new EmberError(OUT_OF_RANGE_EXCEPTION); + this._replace(idx, 0, [object]); + return this; + }, + + insertAt: function(idx, object) { + if (get(this, 'arrangedContent') === get(this, 'content')) { + return this._insertAt(idx, object); + } else { + throw new EmberError("Using insertAt on an arranged ArrayProxy is not allowed."); + } + }, + + removeAt: function(start, len) { + if ('number' === typeof start) { + var content = get(this, 'content'); + var arrangedContent = get(this, 'arrangedContent'); + var indices = []; + var i; + + if ((start < 0) || (start >= get(this, 'length'))) { + throw new EmberError(OUT_OF_RANGE_EXCEPTION); + } + + if (len === undefined) len = 1; + + // Get a list of indices in original content to remove + for (i=start; i= 0) { + var baseValue = this[keyName]; + + if (baseValue) { + if ('function' === typeof baseValue.concat) { + value = baseValue.concat(value); + } else { + value = makeArray(baseValue).concat(value); + } + } else { + value = makeArray(value); + } + } + + if (desc) { + desc.set(this, keyName, value); + } else { + if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { + this.setUnknownProperty(keyName, value); + } else { + + this[keyName] = value; + + } + } + } + } + } + finishPartial(this, m); + var length = arguments.length; + var args = new Array(length); + for (var x = 0; x < length; x++) { + args[x] = arguments[x]; + } + apply(this, this.init, args); + m.proto = proto; + finishChains(this); + sendEvent(this, "init"); + }; + + Class.toString = Mixin.prototype.toString; + Class.willReopen = function() { + if (wasApplied) { + Class.PrototypeMixin = Mixin.create(Class.PrototypeMixin); + } + + wasApplied = false; + }; + Class._initMixins = function(args) { initMixins = args; }; + Class._initProperties = function(args) { initProperties = args; }; + + Class.proto = function() { + var superclass = Class.superclass; + if (superclass) { superclass.proto(); } + + if (!wasApplied) { + wasApplied = true; + Class.PrototypeMixin.applyPartial(Class.prototype); + rewatch(Class.prototype); + } + + return this.prototype; + }; + + return Class; + + } + + /** + @class CoreObject + @namespace Ember + */ + var CoreObject = makeCtor(); + CoreObject.toString = function() { return "Ember.CoreObject"; }; + CoreObject.PrototypeMixin = Mixin.create({ + reopen: function() { + var length = arguments.length; + var args = new Array(length); + for (var i = 0; i < length; i++) { + args[i] = arguments[i]; + } + applyMixin(this, args, true); + return this; + }, + + /** + An overridable method called when objects are instantiated. By default, + does nothing unless it is overridden during class definition. + + Example: + + ```javascript + App.Person = Ember.Object.extend({ + init: function() { + alert('Name is ' + this.get('name')); + } + }); + + var steve = App.Person.create({ + name: "Steve" + }); + + // alerts 'Name is Steve'. + ``` + + NOTE: If you do override `init` for a framework class like `Ember.View` or + `Ember.ArrayController`, be sure to call `this._super()` in your + `init` declaration! If you don't, Ember may not have an opportunity to + do important setup work, and you'll see strange behavior in your + application. + + @method init + */ + init: function() {}, + + /** + Defines the properties that will be concatenated from the superclass + (instead of overridden). + + By default, when you extend an Ember class a property defined in + the subclass overrides a property with the same name that is defined + in the superclass. However, there are some cases where it is preferable + to build up a property's value by combining the superclass' property + value with the subclass' value. An example of this in use within Ember + is the `classNames` property of `Ember.View`. + + Here is some sample code showing the difference between a concatenated + property and a normal one: + + ```javascript + App.BarView = Ember.View.extend({ + someNonConcatenatedProperty: ['bar'], + classNames: ['bar'] + }); + + App.FooBarView = App.BarView.extend({ + someNonConcatenatedProperty: ['foo'], + classNames: ['foo'] + }); + + var fooBarView = App.FooBarView.create(); + fooBarView.get('someNonConcatenatedProperty'); // ['foo'] + fooBarView.get('classNames'); // ['ember-view', 'bar', 'foo'] + ``` + + This behavior extends to object creation as well. Continuing the + above example: + + ```javascript + var view = App.FooBarView.create({ + someNonConcatenatedProperty: ['baz'], + classNames: ['baz'] + }) + view.get('someNonConcatenatedProperty'); // ['baz'] + view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] + ``` + Adding a single property that is not an array will just add it in the array: + + ```javascript + var view = App.FooBarView.create({ + classNames: 'baz' + }) + view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] + ``` + + Using the `concatenatedProperties` property, we can tell to Ember that mix + the content of the properties. + + In `Ember.View` the `classNameBindings` and `attributeBindings` properties + are also concatenated, in addition to `classNames`. + + This feature is available for you to use throughout the Ember object model, + although typical app developers are likely to use it infrequently. Since + it changes expectations about behavior of properties, you should properly + document its usage in each individual concatenated property (to not + mislead your users to think they can override the property in a subclass). + + @property concatenatedProperties + @type Array + @default null + */ + concatenatedProperties: null, + + /** + Destroyed object property flag. + + if this property is `true` the observers and bindings were already + removed by the effect of calling the `destroy()` method. + + @property isDestroyed + @default false + */ + isDestroyed: false, + + /** + Destruction scheduled flag. The `destroy()` method has been called. + + The object stays intact until the end of the run loop at which point + the `isDestroyed` flag is set. + + @property isDestroying + @default false + */ + isDestroying: false, + + /** + Destroys an object by setting the `isDestroyed` flag and removing its + metadata, which effectively destroys observers and bindings. + + If you try to set a property on a destroyed object, an exception will be + raised. + + Note that destruction is scheduled for the end of the run loop and does not + happen immediately. It will set an isDestroying flag immediately. + + @method destroy + @return {Ember.Object} receiver + */ + destroy: function() { + if (this.isDestroying) { return; } + this.isDestroying = true; + + schedule('actions', this, this.willDestroy); + schedule('destroy', this, this._scheduledDestroy); + return this; + }, + + /** + Override to implement teardown. + + @method willDestroy + */ + willDestroy: K, + + /** + Invoked by the run loop to actually destroy the object. This is + scheduled for execution by the `destroy` method. + + @private + @method _scheduledDestroy + */ + _scheduledDestroy: function() { + if (this.isDestroyed) { return; } + destroy(this); + this.isDestroyed = true; + }, + + bind: function(to, from) { + if (!(from instanceof Binding)) { from = Binding.from(from); } + from.to(to).connect(this); + return from; + }, + + /** + Returns a string representation which attempts to provide more information + than Javascript's `toString` typically does, in a generic way for all Ember + objects. + + ```javascript + App.Person = Em.Object.extend() + person = App.Person.create() + person.toString() //=> "" + ``` + + If the object's class is not defined on an Ember namespace, it will + indicate it is a subclass of the registered superclass: + + ```javascript + Student = App.Person.extend() + student = Student.create() + student.toString() //=> "<(subclass of App.Person):ember1025>" + ``` + + If the method `toStringExtension` is defined, its return value will be + included in the output. + + ```javascript + App.Teacher = App.Person.extend({ + toStringExtension: function() { + return this.get('fullName'); + } + }); + teacher = App.Teacher.create() + teacher.toString(); //=> "" + ``` + + @method toString + @return {String} string representation + */ + toString: function toString() { + var hasToStringExtension = typeof this.toStringExtension === 'function'; + var extension = hasToStringExtension ? ":" + this.toStringExtension() : ''; + var ret = '<'+this.constructor.toString()+':'+guidFor(this)+extension+'>'; + + this.toString = makeToString(ret); + return ret; + } + }); + + CoreObject.PrototypeMixin.ownerConstructor = CoreObject; + + function makeToString(ret) { + return function() { return ret; }; + } + + if (Ember.config.overridePrototypeMixin) { + Ember.config.overridePrototypeMixin(CoreObject.PrototypeMixin); + } + + CoreObject.__super__ = null; + + var ClassMixin = Mixin.create({ + + ClassMixin: required(), + + PrototypeMixin: required(), + + isClass: true, + + isMethod: false, + + /** + Creates a new subclass. + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + alert(thing); + } + }); + ``` + + This defines a new subclass of Ember.Object: `App.Person`. It contains one method: `say()`. + + You can also create a subclass from any existing class by calling its `extend()` method. For example, you might want to create a subclass of Ember's built-in `Ember.View` class: + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li', + classNameBindings: ['isAdministrator'] + }); + ``` + + When defining a subclass, you can override methods but still access the implementation of your parent class by calling the special `_super()` method: + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + var name = this.get('name'); + alert(name + ' says: ' + thing); + } + }); + + App.Soldier = App.Person.extend({ + say: function(thing) { + this._super(thing + ", sir!"); + }, + march: function(numberOfHours) { + alert(this.get('name') + ' marches for ' + numberOfHours + ' hours.') + } + }); + + var yehuda = App.Soldier.create({ + name: "Yehuda Katz" + }); + + yehuda.say("Yes"); // alerts "Yehuda Katz says: Yes, sir!" + ``` + + The `create()` on line #17 creates an *instance* of the `App.Soldier` class. The `extend()` on line #8 creates a *subclass* of `App.Person`. Any instance of the `App.Person` class will *not* have the `march()` method. + + You can also pass `Mixin` classes to add additional properties to the subclass. + + ```javascript + App.Person = Ember.Object.extend({ + say: function(thing) { + alert(this.get('name') + ' says: ' + thing); + } + }); + + App.SingingMixin = Mixin.create({ + sing: function(thing){ + alert(this.get('name') + ' sings: la la la ' + thing); + } + }); + + App.BroadwayStar = App.Person.extend(App.SingingMixin, { + dance: function() { + alert(this.get('name') + ' dances: tap tap tap tap '); + } + }); + ``` + + The `App.BroadwayStar` class contains three methods: `say()`, `sing()`, and `dance()`. + + @method extend + @static + + @param {Mixin} [mixins]* One or more Mixin classes + @param {Object} [arguments]* Object containing values to use within the new class + */ + extend: function extend() { + var Class = makeCtor(); + var proto; + Class.ClassMixin = Mixin.create(this.ClassMixin); + Class.PrototypeMixin = Mixin.create(this.PrototypeMixin); + + Class.ClassMixin.ownerConstructor = Class; + Class.PrototypeMixin.ownerConstructor = Class; + + reopen.apply(Class.PrototypeMixin, arguments); + + Class.superclass = this; + Class.__super__ = this.prototype; + + proto = Class.prototype = o_create(this.prototype); + proto.constructor = Class; + generateGuid(proto); + meta(proto).proto = proto; // this will disable observers on prototype + + Class.ClassMixin.apply(Class); + return Class; + }, + + /** + Equivalent to doing `extend(arguments).create()`. + If possible use the normal `create` method instead. + + @method createWithMixins + @static + @param [arguments]* + */ + createWithMixins: function() { + var C = this; + var l= arguments.length; + if (l > 0) { + var args = new Array(l); + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + this._initMixins(args); + } + return new C(); + }, + + /** + Creates an instance of a class. Accepts either no arguments, or an object + containing values to initialize the newly instantiated object with. + + ```javascript + App.Person = Ember.Object.extend({ + helloWorld: function() { + alert("Hi, my name is " + this.get('name')); + } + }); + + var tom = App.Person.create({ + name: 'Tom Dale' + }); + + tom.helloWorld(); // alerts "Hi, my name is Tom Dale". + ``` + + `create` will call the `init` function if defined during + `Ember.AnyObject.extend` + + If no arguments are passed to `create`, it will not set values to the new + instance during initialization: + + ```javascript + var noName = App.Person.create(); + noName.helloWorld(); // alerts undefined + ``` + + NOTE: For performance reasons, you cannot declare methods or computed + properties during `create`. You should instead declare methods and computed + properties when using `extend` or use the `createWithMixins` shorthand. + + @method create + @static + @param [arguments]* + */ + create: function() { + var C = this; + var l = arguments.length; + if (l > 0) { + var args = new Array(l); + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + this._initProperties(args); + } + return new C(); + }, + + /** + Augments a constructor's prototype with additional + properties and functions: + + ```javascript + MyObject = Ember.Object.extend({ + name: 'an object' + }); + + o = MyObject.create(); + o.get('name'); // 'an object' + + MyObject.reopen({ + say: function(msg){ + console.log(msg); + } + }) + + o2 = MyObject.create(); + o2.say("hello"); // logs "hello" + + o.say("goodbye"); // logs "goodbye" + ``` + + To add functions and properties to the constructor itself, + see `reopenClass` + + @method reopen + */ + reopen: function() { + this.willReopen(); + + var l = arguments.length; + var args = new Array(l); + if (l > 0) { + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + } + + apply(this.PrototypeMixin, reopen, args); + return this; + }, + + /** + Augments a constructor's own properties and functions: + + ```javascript + MyObject = Ember.Object.extend({ + name: 'an object' + }); + + MyObject.reopenClass({ + canBuild: false + }); + + MyObject.canBuild; // false + o = MyObject.create(); + ``` + + In other words, this creates static properties and functions for the class. These are only available on the class + and not on any instance of that class. + + ```javascript + App.Person = Ember.Object.extend({ + name : "", + sayHello : function(){ + alert("Hello. My name is " + this.get('name')); + } + }); + + App.Person.reopenClass({ + species : "Homo sapiens", + createPerson: function(newPersonsName){ + return App.Person.create({ + name:newPersonsName + }); + } + }); + + var tom = App.Person.create({ + name : "Tom Dale" + }); + var yehuda = App.Person.createPerson("Yehuda Katz"); + + tom.sayHello(); // "Hello. My name is Tom Dale" + yehuda.sayHello(); // "Hello. My name is Yehuda Katz" + alert(App.Person.species); // "Homo sapiens" + ``` + + Note that `species` and `createPerson` are *not* valid on the `tom` and `yehuda` + variables. They are only valid on `App.Person`. + + To add functions and properties to instances of + a constructor by extending the constructor's prototype + see `reopen` + + @method reopenClass + */ + reopenClass: function() { + var l = arguments.length; + var args = new Array(l); + if (l > 0) { + for (var i = 0; i < l; i++) { + args[i] = arguments[i]; + } + } + + apply(this.ClassMixin, reopen, args); + applyMixin(this, arguments, false); + return this; + }, + + detect: function(obj) { + if ('function' !== typeof obj) { return false; } + while(obj) { + if (obj===this) { return true; } + obj = obj.superclass; + } + return false; + }, + + detectInstance: function(obj) { + return obj instanceof this; + }, + + /** + In some cases, you may want to annotate computed properties with additional + metadata about how they function or what values they operate on. For + example, computed property functions may close over variables that are then + no longer available for introspection. + + You can pass a hash of these values to a computed property like this: + + ```javascript + person: function() { + var personId = this.get('personId'); + return App.Person.create({ id: personId }); + }.property().meta({ type: App.Person }) + ``` + + Once you've done this, you can retrieve the values saved to the computed + property from your class like this: + + ```javascript + MyClass.metaForProperty('person'); + ``` + + This will return the original hash that was passed to `meta()`. + + @method metaForProperty + @param key {String} property name + */ + metaForProperty: function(key) { + var meta = this.proto()['__ember_meta__']; + var desc = meta && meta.descs[key]; + + return desc._meta || {}; + }, + + _computedProperties: Ember.computed(function() { + hasCachedComputedProperties = true; + var proto = this.proto(); + var descs = meta(proto).descs; + var property; + var properties = []; + + for (var name in descs) { + property = descs[name]; + + if (property instanceof ComputedProperty) { + properties.push({ + name: name, + meta: property._meta + }); + } + } + return properties; + }).readOnly(), + + /** + Iterate over each computed property for the class, passing its name + and any associated metadata (see `metaForProperty`) to the callback. + + @method eachComputedProperty + @param {Function} callback + @param {Object} binding + */ + eachComputedProperty: function(callback, binding) { + var property, name; + var empty = {}; + + var properties = get(this, '_computedProperties'); + + for (var i = 0, length = properties.length; i < length; i++) { + property = properties[i]; + name = property.name; + callback.call(binding || this, property.name, property.meta || empty); + } + } + }); + + ClassMixin.ownerConstructor = CoreObject; + + if (Ember.config.overrideClassMixin) { + Ember.config.overrideClassMixin(ClassMixin); + } + + CoreObject.ClassMixin = ClassMixin; + + ClassMixin.apply(CoreObject); + + CoreObject.reopen({ + didDefineProperty: function(proto, key, value) { + if (hasCachedComputedProperties === false) { return; } + if (value instanceof Ember.ComputedProperty) { + var cache = Ember.meta(this.constructor).cache; + + if (cache._computedProperties !== undefined) { + cache._computedProperties = undefined; + } + } + } + }); + + __exports__["default"] = CoreObject; + }); +define("ember-runtime/system/deferred", + ["ember-metal/core","ember-runtime/mixins/deferred","ember-metal/property_get","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var DeferredMixin = __dependency2__["default"]; + var get = __dependency3__.get; + var EmberObject = __dependency4__["default"]; + + var Deferred = EmberObject.extend(DeferredMixin, { + init: function() { + this._super(); + } + }); + + Deferred.reopenClass({ + promise: function(callback, binding) { + var deferred = Deferred.create(); + callback.call(binding, deferred); + return deferred; + } + }); + + __exports__["default"] = Deferred; + }); +define("ember-runtime/system/each_proxy", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/enumerable_utils","ember-metal/array","ember-runtime/mixins/array","ember-runtime/system/object","ember-metal/computed","ember-metal/observer","ember-metal/events","ember-metal/properties","ember-metal/property_events","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var forEach = __dependency5__.forEach; + var indexOf = __dependency6__.indexOf; + var EmberArray = __dependency7__["default"]; + // ES6TODO: WAT? Circular dep? + var EmberObject = __dependency8__["default"]; + var computed = __dependency9__.computed; + var addObserver = __dependency10__.addObserver; + var addBeforeObserver = __dependency10__.addBeforeObserver; + var removeBeforeObserver = __dependency10__.removeBeforeObserver; + var removeObserver = __dependency10__.removeObserver; + var typeOf = __dependency4__.typeOf; + var watchedEvents = __dependency11__.watchedEvents; + var defineProperty = __dependency12__.defineProperty; + var beginPropertyChanges = __dependency13__.beginPropertyChanges; + var propertyDidChange = __dependency13__.propertyDidChange; + var propertyWillChange = __dependency13__.propertyWillChange; + var endPropertyChanges = __dependency13__.endPropertyChanges; + var changeProperties = __dependency13__.changeProperties; + + var EachArray = EmberObject.extend(EmberArray, { + + init: function(content, keyName, owner) { + this._super(); + this._keyName = keyName; + this._owner = owner; + this._content = content; + }, + + objectAt: function(idx) { + var item = this._content.objectAt(idx); + return item && get(item, this._keyName); + }, + + length: computed(function() { + var content = this._content; + return content ? get(content, 'length') : 0; + }) + + }); + + var IS_OBSERVER = /^.+:(before|change)$/; + + function addObserverForContentKey(content, keyName, proxy, idx, loc) { + var objects = proxy._objects; + var guid; + if (!objects) objects = proxy._objects = {}; + + while(--loc>=idx) { + var item = content.objectAt(loc); + if (item) { + addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + addObserver(item, keyName, proxy, 'contentKeyDidChange'); + + // keep track of the index each item was found at so we can map + // it back when the obj changes. + guid = guidFor(item); + if (!objects[guid]) objects[guid] = []; + objects[guid].push(loc); + } + } + } + + function removeObserverForContentKey(content, keyName, proxy, idx, loc) { + var objects = proxy._objects; + if (!objects) objects = proxy._objects = {}; + var indicies, guid; + + while(--loc>=idx) { + var item = content.objectAt(loc); + if (item) { + removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + removeObserver(item, keyName, proxy, 'contentKeyDidChange'); + + guid = guidFor(item); + indicies = objects[guid]; + indicies[indexOf.call(indicies, loc)] = null; + } + } + } + + /** + This is the object instance returned when you get the `@each` property on an + array. It uses the unknownProperty handler to automatically create + EachArray instances for property names. + + @private + @class EachProxy + @namespace Ember + @extends Ember.Object + */ + var EachProxy = EmberObject.extend({ + + init: function(content) { + this._super(); + this._content = content; + content.addArrayObserver(this); + + // in case someone is already observing some keys make sure they are + // added + forEach(watchedEvents(this), function(eventName) { + this.didAddListener(eventName); + }, this); + }, + + /** + You can directly access mapped properties by simply requesting them. + The `unknownProperty` handler will generate an EachArray of each item. + + @method unknownProperty + @param keyName {String} + @param value {*} + */ + unknownProperty: function(keyName, value) { + var ret; + ret = new EachArray(this._content, keyName, this); + defineProperty(this, keyName, null, ret); + this.beginObservingContentKey(keyName); + return ret; + }, + + // .......................................................... + // ARRAY CHANGES + // Invokes whenever the content array itself changes. + + arrayWillChange: function(content, idx, removedCnt, addedCnt) { + var keys = this._keys; + var key, lim; + + lim = removedCnt>0 ? idx+removedCnt : -1; + beginPropertyChanges(this); + + for(key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } + + if (lim>0) { removeObserverForContentKey(content, key, this, idx, lim); } + + propertyWillChange(this, key); + } + + propertyWillChange(this._content, '@each'); + endPropertyChanges(this); + }, + + arrayDidChange: function(content, idx, removedCnt, addedCnt) { + var keys = this._keys; + var lim; + + lim = addedCnt>0 ? idx+addedCnt : -1; + changeProperties(function() { + for(var key in keys) { + if (!keys.hasOwnProperty(key)) { continue; } + + if (lim>0) { addObserverForContentKey(content, key, this, idx, lim); } + + propertyDidChange(this, key); + } + + propertyDidChange(this._content, '@each'); + }, this); + }, + + // .......................................................... + // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS + // Start monitoring keys based on who is listening... + + didAddListener: function(eventName) { + if (IS_OBSERVER.test(eventName)) { + this.beginObservingContentKey(eventName.slice(0, -7)); + } + }, + + didRemoveListener: function(eventName) { + if (IS_OBSERVER.test(eventName)) { + this.stopObservingContentKey(eventName.slice(0, -7)); + } + }, + + // .......................................................... + // CONTENT KEY OBSERVING + // Actual watch keys on the source content. + + beginObservingContentKey: function(keyName) { + var keys = this._keys; + if (!keys) keys = this._keys = {}; + if (!keys[keyName]) { + keys[keyName] = 1; + var content = this._content; + var len = get(content, 'length'); + + addObserverForContentKey(content, keyName, this, 0, len); + } else { + keys[keyName]++; + } + }, + + stopObservingContentKey: function(keyName) { + var keys = this._keys; + if (keys && (keys[keyName]>0) && (--keys[keyName]<=0)) { + var content = this._content; + var len = get(content, 'length'); + + removeObserverForContentKey(content, keyName, this, 0, len); + } + }, + + contentKeyWillChange: function(obj, keyName) { + propertyWillChange(this, keyName); + }, + + contentKeyDidChange: function(obj, keyName) { + propertyDidChange(this, keyName); + } + }); + + __exports__.EachArray = EachArray; + __exports__.EachProxy = EachProxy; + }); +define("ember-runtime/system/lazy_load", + ["ember-metal/core","ember-metal/array","ember-runtime/system/native_array","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /*globals CustomEvent */ + + var Ember = __dependency1__["default"]; + // Ember.ENV.EMBER_LOAD_HOOKS + var forEach = __dependency2__.forEach; + // make sure Ember.A is setup. + + /** + @module ember + @submodule ember-runtime + */ + + var loadHooks = Ember.ENV.EMBER_LOAD_HOOKS || {}; + var loaded = {}; + + /** + Detects when a specific package of Ember (e.g. 'Ember.Handlebars') + has fully loaded and is available for extension. + + The provided `callback` will be called with the `name` passed + resolved from a string into the object: + + ``` javascript + Ember.onLoad('Ember.Handlebars' function(hbars) { + hbars.registerHelper(...); + }); + ``` + + @method onLoad + @for Ember + @param name {String} name of hook + @param callback {Function} callback to be called + */ + function onLoad(name, callback) { + var object; + + loadHooks[name] = loadHooks[name] || Ember.A(); + loadHooks[name].pushObject(callback); + + if (object = loaded[name]) { + callback(object); + } + } + + __exports__.onLoad = onLoad;/** + Called when an Ember.js package (e.g Ember.Handlebars) has finished + loading. Triggers any callbacks registered for this event. + + @method runLoadHooks + @for Ember + @param name {String} name of hook + @param object {Object} object to pass to callbacks + */ + function runLoadHooks(name, object) { + loaded[name] = object; + + if (typeof window === 'object' && typeof window.dispatchEvent === 'function' && typeof CustomEvent === "function") { + var event = new CustomEvent(name, {detail: object, name: name}); + window.dispatchEvent(event); + } + + if (loadHooks[name]) { + forEach.call(loadHooks[name], function(callback) { + callback(object); + }); + } + } + + __exports__.runLoadHooks = runLoadHooks; + }); +define("ember-runtime/system/namespace", + ["ember-metal/core","ember-metal/property_get","ember-metal/array","ember-metal/utils","ember-metal/mixin","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + // Ember.lookup, Ember.BOOTED, Ember.deprecate, Ember.NAME_KEY, Ember.anyUnprocessedMixins + var Ember = __dependency1__["default"]; + var get = __dependency2__.get; + var indexOf = __dependency3__.indexOf; + var GUID_KEY = __dependency4__.GUID_KEY; + var guidFor = __dependency4__.guidFor; + var Mixin = __dependency5__.Mixin; + + var EmberObject = __dependency6__["default"]; + + /** + A Namespace is an object usually used to contain other objects or methods + such as an application or framework. Create a namespace anytime you want + to define one of these new containers. + + # Example Usage + + ```javascript + MyFramework = Ember.Namespace.create({ + VERSION: '1.0.0' + }); + ``` + + @class Namespace + @namespace Ember + @extends Ember.Object + */ + var Namespace = EmberObject.extend({ + isNamespace: true, + + init: function() { + Namespace.NAMESPACES.push(this); + Namespace.PROCESSED = false; + }, + + toString: function() { + var name = get(this, 'name'); + if (name) { return name; } + + findNamespaces(); + return this[NAME_KEY]; + }, + + nameClasses: function() { + processNamespace([this.toString()], this, {}); + }, + + destroy: function() { + var namespaces = Namespace.NAMESPACES; + var toString = this.toString(); + + if (toString) { + Ember.lookup[toString] = undefined; + delete Namespace.NAMESPACES_BY_ID[toString]; + } + namespaces.splice(indexOf.call(namespaces, this), 1); + this._super(); + } + }); + + Namespace.reopenClass({ + NAMESPACES: [Ember], + NAMESPACES_BY_ID: {}, + PROCESSED: false, + processAll: processAllNamespaces, + byName: function(name) { + if (!Ember.BOOTED) { + processAllNamespaces(); + } + + return NAMESPACES_BY_ID[name]; + } + }); + + var NAMESPACES_BY_ID = Namespace.NAMESPACES_BY_ID; + + var hasOwnProp = ({}).hasOwnProperty; + + function processNamespace(paths, root, seen) { + var idx = paths.length; + + NAMESPACES_BY_ID[paths.join('.')] = root; + + // Loop over all of the keys in the namespace, looking for classes + for(var key in root) { + if (!hasOwnProp.call(root, key)) { continue; } + var obj = root[key]; + + // If we are processing the `Ember` namespace, for example, the + // `paths` will start with `["Ember"]`. Every iteration through + // the loop will update the **second** element of this list with + // the key, so processing `Ember.View` will make the Array + // `['Ember', 'View']`. + paths[idx] = key; + + // If we have found an unprocessed class + if (obj && obj.toString === classToString) { + // Replace the class' `toString` with the dot-separated path + // and set its `NAME_KEY` + obj.toString = makeToString(paths.join('.')); + obj[NAME_KEY] = paths.join('.'); + + // Support nested namespaces + } else if (obj && obj.isNamespace) { + // Skip aliased namespaces + if (seen[guidFor(obj)]) { continue; } + seen[guidFor(obj)] = true; + + // Process the child namespace + processNamespace(paths, obj, seen); + } + } + + paths.length = idx; // cut out last item + } + + var STARTS_WITH_UPPERCASE = /^[A-Z]/; + + function tryIsNamespace(lookup, prop) { + try { + var obj = lookup[prop]; + return obj && obj.isNamespace && obj; + } catch (e) { + // continue + } + } + + function findNamespaces() { + var lookup = Ember.lookup; + var obj, isNamespace; + + if (Namespace.PROCESSED) { return; } + + for (var prop in lookup) { + // Only process entities that start with uppercase A-Z + if (!STARTS_WITH_UPPERCASE.test(prop)) { continue; } + + // Unfortunately, some versions of IE don't support window.hasOwnProperty + if (lookup.hasOwnProperty && !lookup.hasOwnProperty(prop)) { continue; } + + // At times we are not allowed to access certain properties for security reasons. + // There are also times where even if we can access them, we are not allowed to access their properties. + obj = tryIsNamespace(lookup, prop); + if (obj) { + obj[NAME_KEY] = prop; + } + } + } + + var NAME_KEY = Ember.NAME_KEY = GUID_KEY + '_name'; + + function superClassString(mixin) { + var superclass = mixin.superclass; + if (superclass) { + if (superclass[NAME_KEY]) { return superclass[NAME_KEY]; } + else { return superClassString(superclass); } + } else { + return; + } + } + + function classToString() { + if (!Ember.BOOTED && !this[NAME_KEY]) { + processAllNamespaces(); + } + + var ret; + + if (this[NAME_KEY]) { + ret = this[NAME_KEY]; + } else if (this._toString) { + ret = this._toString; + } else { + var str = superClassString(this); + if (str) { + ret = "(subclass of " + str + ")"; + } else { + ret = "(unknown mixin)"; + } + this.toString = makeToString(ret); + } + + return ret; + } + + function processAllNamespaces() { + var unprocessedNamespaces = !Namespace.PROCESSED; + var unprocessedMixins = Ember.anyUnprocessedMixins; + + if (unprocessedNamespaces) { + findNamespaces(); + Namespace.PROCESSED = true; + } + + if (unprocessedNamespaces || unprocessedMixins) { + var namespaces = Namespace.NAMESPACES; + var namespace; + + for (var i=0, l=namespaces.length; i 0) { + NativeArray = NativeArray.without.apply(NativeArray, ignore); + } + + /** + Creates an `Ember.NativeArray` from an Array like object. + Does not modify the original object. Ember.A is not needed if + `Ember.EXTEND_PROTOTYPES` is `true` (the default value). However, + it is recommended that you use Ember.A when creating addons for + ember or when you can not guarantee that `Ember.EXTEND_PROTOTYPES` + will be `true`. + + Example + + ```js + var Pagination = Ember.CollectionView.extend({ + tagName: 'ul', + classNames: ['pagination'], + + init: function() { + this._super(); + if (!this.get('content')) { + this.set('content', Ember.A()); + } + } + }); + ``` + + @method A + @for Ember + @return {Ember.NativeArray} + */ + var A = function(arr) { + if (arr === undefined) { arr = []; } + return EmberArray.detect(arr) ? arr : NativeArray.apply(arr); + }; + + /** + Activates the mixin on the Array.prototype if not already applied. Calling + this method more than once is safe. This will be called when ember is loaded + unless you have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` + set to `false`. + + Example + + ```js + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { + Ember.NativeArray.activate(); + } + ``` + + @method activate + @for Ember.NativeArray + @static + @return {void} + */ + NativeArray.activate = function() { + NativeArray.apply(Array.prototype); + + A = function(arr) { return arr || []; }; + }; + + if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Array) { + NativeArray.activate(); + } + + Ember.A = A; // ES6TODO: Setting A onto the object returned by ember-metal/core to avoid circles + __exports__.A = A; + __exports__.NativeArray = NativeArray; + __exports__["default"] = NativeArray; + }); +define("ember-runtime/system/object", + ["ember-runtime/system/core_object","ember-runtime/mixins/observable","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + + var CoreObject = __dependency1__["default"]; + var Observable = __dependency2__["default"]; + + /** + `Ember.Object` is the main base class for all Ember objects. It is a subclass + of `Ember.CoreObject` with the `Ember.Observable` mixin applied. For details, + see the documentation for each of these. + + @class Object + @namespace Ember + @extends Ember.CoreObject + @uses Ember.Observable + */ + var EmberObject = CoreObject.extend(Observable); + EmberObject.toString = function() { + return "Ember.Object"; + }; + + __exports__["default"] = EmberObject; + }); +define("ember-runtime/system/object_proxy", + ["ember-runtime/system/object","ember-runtime/mixins/-proxy","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var EmberObject = __dependency1__["default"]; + var _ProxyMixin = __dependency2__["default"]; + + /** + `Ember.ObjectProxy` forwards all properties not defined by the proxy itself + to a proxied `content` object. + + ```javascript + object = Ember.Object.create({ + name: 'Foo' + }); + + proxy = Ember.ObjectProxy.create({ + content: object + }); + + // Access and change existing properties + proxy.get('name') // 'Foo' + proxy.set('name', 'Bar'); + object.get('name') // 'Bar' + + // Create new 'description' property on `object` + proxy.set('description', 'Foo is a whizboo baz'); + object.get('description') // 'Foo is a whizboo baz' + ``` + + While `content` is unset, setting a property to be delegated will throw an + Error. + + ```javascript + proxy = Ember.ObjectProxy.create({ + content: null, + flag: null + }); + proxy.set('flag', true); + proxy.get('flag'); // true + proxy.get('foo'); // undefined + proxy.set('foo', 'data'); // throws Error + ``` + + Delegated properties can be bound to and will change when content is updated. + + Computed properties on the proxy itself can depend on delegated properties. + + ```javascript + ProxyWithComputedProperty = Ember.ObjectProxy.extend({ + fullName: function () { + var firstName = this.get('firstName'), + lastName = this.get('lastName'); + if (firstName && lastName) { + return firstName + ' ' + lastName; + } + return firstName || lastName; + }.property('firstName', 'lastName') + }); + + proxy = ProxyWithComputedProperty.create(); + + proxy.get('fullName'); // undefined + proxy.set('content', { + firstName: 'Tom', lastName: 'Dale' + }); // triggers property change for fullName on proxy + + proxy.get('fullName'); // 'Tom Dale' + ``` + + @class ObjectProxy + @namespace Ember + @extends Ember.Object + @extends Ember._ProxyMixin + */ + + __exports__["default"] = EmberObject.extend(_ProxyMixin); + }); +define("ember-runtime/system/set", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/utils","ember-metal/is_none","ember-runtime/system/string","ember-runtime/system/core_object","ember-runtime/mixins/mutable_enumerable","ember-runtime/mixins/enumerable","ember-runtime/mixins/copyable","ember-runtime/mixins/freezable","ember-metal/error","ember-metal/property_events","ember-metal/mixin","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.isNone, Ember.A + + var get = __dependency2__.get; + var set = __dependency3__.set; + var guidFor = __dependency4__.guidFor; + var isNone = __dependency5__.isNone; + var fmt = __dependency6__.fmt; + var CoreObject = __dependency7__["default"]; + var MutableEnumerable = __dependency8__["default"]; + var Enumerable = __dependency9__["default"]; + var Copyable = __dependency10__["default"]; + var Freezable = __dependency11__.Freezable; + var FROZEN_ERROR = __dependency11__.FROZEN_ERROR; + var EmberError = __dependency12__["default"]; + var propertyWillChange = __dependency13__.propertyWillChange; + var propertyDidChange = __dependency13__.propertyDidChange; + var aliasMethod = __dependency14__.aliasMethod; + var computed = __dependency15__.computed; + + /** + An unordered collection of objects. + + A Set works a bit like an array except that its items are not ordered. You + can create a set to efficiently test for membership for an object. You can + also iterate through a set just like an array, even accessing objects by + index, however there is no guarantee as to their order. + + All Sets are observable via the Enumerable Observer API - which works + on any enumerable object including both Sets and Arrays. + + ## Creating a Set + + You can create a set like you would most objects using + `new Ember.Set()`. Most new sets you create will be empty, but you can + also initialize the set with some content by passing an array or other + enumerable of objects to the constructor. + + Finally, you can pass in an existing set and the set will be copied. You + can also create a copy of a set by calling `Ember.Set#copy()`. + + ```javascript + // creates a new empty set + var foundNames = new Ember.Set(); + + // creates a set with four names in it. + var names = new Ember.Set(["Charles", "Tom", "Juan", "Alex"]); // :P + + // creates a copy of the names set. + var namesCopy = new Ember.Set(names); + + // same as above. + var anotherNamesCopy = names.copy(); + ``` + + ## Adding/Removing Objects + + You generally add or remove objects from a set using `add()` or + `remove()`. You can add any type of object including primitives such as + numbers, strings, and booleans. + + Unlike arrays, objects can only exist one time in a set. If you call `add()` + on a set with the same object multiple times, the object will only be added + once. Likewise, calling `remove()` with the same object multiple times will + remove the object the first time and have no effect on future calls until + you add the object to the set again. + + NOTE: You cannot add/remove `null` or `undefined` to a set. Any attempt to do + so will be ignored. + + In addition to add/remove you can also call `push()`/`pop()`. Push behaves + just like `add()` but `pop()`, unlike `remove()` will pick an arbitrary + object, remove it and return it. This is a good way to use a set as a job + queue when you don't care which order the jobs are executed in. + + ## Testing for an Object + + To test for an object's presence in a set you simply call + `Ember.Set#contains()`. + + ## Observing changes + + When using `Ember.Set`, you can observe the `"[]"` property to be + alerted whenever the content changes. You can also add an enumerable + observer to the set to be notified of specific objects that are added and + removed from the set. See [Ember.Enumerable](/api/classes/Ember.Enumerable.html) + for more information on enumerables. + + This is often unhelpful. If you are filtering sets of objects, for instance, + it is very inefficient to re-filter all of the items each time the set + changes. It would be better if you could just adjust the filtered set based + on what was changed on the original set. The same issue applies to merging + sets, as well. + + ## Other Methods + + `Ember.Set` primary implements other mixin APIs. For a complete reference + on the methods you will use with `Ember.Set`, please consult these mixins. + The most useful ones will be `Ember.Enumerable` and + `Ember.MutableEnumerable` which implement most of the common iterator + methods you are used to on Array. + + Note that you can also use the `Ember.Copyable` and `Ember.Freezable` + APIs on `Ember.Set` as well. Once a set is frozen it can no longer be + modified. The benefit of this is that when you call `frozenCopy()` on it, + Ember will avoid making copies of the set. This allows you to write + code that can know with certainty when the underlying set data will or + will not be modified. + + @class Set + @namespace Ember + @extends Ember.CoreObject + @uses Ember.MutableEnumerable + @uses Ember.Copyable + @uses Ember.Freezable + @since Ember 0.9 + */ + __exports__["default"] = CoreObject.extend(MutableEnumerable, Copyable, Freezable, { + + // .......................................................... + // IMPLEMENT ENUMERABLE APIS + // + + /** + This property will change as the number of objects in the set changes. + + @property length + @type number + @default 0 + */ + length: 0, + + /** + Clears the set. This is useful if you want to reuse an existing set + without having to recreate it. + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.length; // 3 + colors.clear(); + colors.length; // 0 + ``` + + @method clear + @return {Ember.Set} An empty Set + */ + clear: function() { + if (this.isFrozen) { throw new EmberError(FROZEN_ERROR); } + + var len = get(this, 'length'); + if (len === 0) { return this; } + + var guid; + + this.enumerableContentWillChange(len, 0); + propertyWillChange(this, 'firstObject'); + propertyWillChange(this, 'lastObject'); + + for (var i=0; i < len; i++) { + guid = guidFor(this[i]); + delete this[guid]; + delete this[i]; + } + + set(this, 'length', 0); + + propertyDidChange(this, 'firstObject'); + propertyDidChange(this, 'lastObject'); + this.enumerableContentDidChange(len, 0); + + return this; + }, + + /** + Returns true if the passed object is also an enumerable that contains the + same objects as the receiver. + + ```javascript + var colors = ["red", "green", "blue"], + same_colors = new Ember.Set(colors); + + same_colors.isEqual(colors); // true + same_colors.isEqual(["purple", "brown"]); // false + ``` + + @method isEqual + @param {Ember.Set} obj the other object. + @return {Boolean} + */ + isEqual: function(obj) { + // fail fast + if (!Enumerable.detect(obj)) return false; + + var loc = get(this, 'length'); + if (get(obj, 'length') !== loc) return false; + + while(--loc >= 0) { + if (!obj.contains(this[loc])) return false; + } + + return true; + }, + + /** + Adds an object to the set. Only non-`null` objects can be added to a set + and those can only be added once. If the object is already in the set or + the passed value is null this method will have no effect. + + This is an alias for `Ember.MutableEnumerable.addObject()`. + + ```javascript + var colors = new Ember.Set(); + colors.add("blue"); // ["blue"] + colors.add("blue"); // ["blue"] + colors.add("red"); // ["blue", "red"] + colors.add(null); // ["blue", "red"] + colors.add(undefined); // ["blue", "red"] + ``` + + @method add + @param {Object} obj The object to add. + @return {Ember.Set} The set itself. + */ + add: aliasMethod('addObject'), + + /** + Removes the object from the set if it is found. If you pass a `null` value + or an object that is already not in the set, this method will have no + effect. This is an alias for `Ember.MutableEnumerable.removeObject()`. + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.remove("red"); // ["blue", "green"] + colors.remove("purple"); // ["blue", "green"] + colors.remove(null); // ["blue", "green"] + ``` + + @method remove + @param {Object} obj The object to remove + @return {Ember.Set} The set itself. + */ + remove: aliasMethod('removeObject'), + + /** + Removes the last element from the set and returns it, or `null` if it's empty. + + ```javascript + var colors = new Ember.Set(["green", "blue"]); + colors.pop(); // "blue" + colors.pop(); // "green" + colors.pop(); // null + ``` + + @method pop + @return {Object} The removed object from the set or null. + */ + pop: function() { + if (get(this, 'isFrozen')) throw new EmberError(FROZEN_ERROR); + var obj = this.length > 0 ? this[this.length-1] : null; + this.remove(obj); + return obj; + }, + + /** + Inserts the given object on to the end of the set. It returns + the set itself. + + This is an alias for `Ember.MutableEnumerable.addObject()`. + + ```javascript + var colors = new Ember.Set(); + colors.push("red"); // ["red"] + colors.push("green"); // ["red", "green"] + colors.push("blue"); // ["red", "green", "blue"] + ``` + + @method push + @return {Ember.Set} The set itself. + */ + push: aliasMethod('addObject'), + + /** + Removes the last element from the set and returns it, or `null` if it's empty. + + This is an alias for `Ember.Set.pop()`. + + ```javascript + var colors = new Ember.Set(["green", "blue"]); + colors.shift(); // "blue" + colors.shift(); // "green" + colors.shift(); // null + ``` + + @method shift + @return {Object} The removed object from the set or null. + */ + shift: aliasMethod('pop'), + + /** + Inserts the given object on to the end of the set. It returns + the set itself. + + This is an alias of `Ember.Set.push()` + + ```javascript + var colors = new Ember.Set(); + colors.unshift("red"); // ["red"] + colors.unshift("green"); // ["red", "green"] + colors.unshift("blue"); // ["red", "green", "blue"] + ``` + + @method unshift + @return {Ember.Set} The set itself. + */ + unshift: aliasMethod('push'), + + /** + Adds each object in the passed enumerable to the set. + + This is an alias of `Ember.MutableEnumerable.addObjects()` + + ```javascript + var colors = new Ember.Set(); + colors.addEach(["red", "green", "blue"]); // ["red", "green", "blue"] + ``` + + @method addEach + @param {Ember.Enumerable} objects the objects to add. + @return {Ember.Set} The set itself. + */ + addEach: aliasMethod('addObjects'), + + /** + Removes each object in the passed enumerable to the set. + + This is an alias of `Ember.MutableEnumerable.removeObjects()` + + ```javascript + var colors = new Ember.Set(["red", "green", "blue"]); + colors.removeEach(["red", "blue"]); // ["green"] + ``` + + @method removeEach + @param {Ember.Enumerable} objects the objects to remove. + @return {Ember.Set} The set itself. + */ + removeEach: aliasMethod('removeObjects'), + + // .......................................................... + // PRIVATE ENUMERABLE SUPPORT + // + + init: function(items) { + this._super(); + if (items) this.addObjects(items); + }, + + // implement Ember.Enumerable + nextObject: function(idx) { + return this[idx]; + }, + + // more optimized version + firstObject: computed(function() { + return this.length > 0 ? this[0] : undefined; + }), + + // more optimized version + lastObject: computed(function() { + return this.length > 0 ? this[this.length-1] : undefined; + }), + + // implements Ember.MutableEnumerable + addObject: function(obj) { + if (get(this, 'isFrozen')) throw new EmberError(FROZEN_ERROR); + if (isNone(obj)) return this; // nothing to do + + var guid = guidFor(obj); + var idx = this[guid]; + var len = get(this, 'length'); + var added; + + if (idx>=0 && idx=0 && idx=0; + }, + + copy: function() { + var C = this.constructor, ret = new C(), loc = get(this, 'length'); + set(ret, 'length', loc); + while(--loc>=0) { + ret[loc] = this[loc]; + ret[guidFor(this[loc])] = loc; + } + return ret; + }, + + toString: function() { + var len = this.length, idx, array = []; + for(idx = 0; idx < len; idx++) { + array[idx] = this[idx]; + } + return fmt("Ember.Set<%@>", [array.join(',')]); + } + }); + }); +define("ember-runtime/system/string", + ["ember-metal/core","ember-metal/utils","ember-metal/cache","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-runtime + */ + var Ember = __dependency1__["default"]; + // Ember.STRINGS, Ember.FEATURES + var isArray = __dependency2__.isArray; + var emberInspect = __dependency2__.inspect; + + var Cache = __dependency3__["default"]; + + var STRING_DASHERIZE_REGEXP = (/[ _]/g); + + var STRING_DASHERIZE_CACHE = new Cache(1000, function(key) { + return decamelize(key).replace(STRING_DASHERIZE_REGEXP, '-'); + }); + + var CAMELIZE_CACHE = new Cache(1000, function(key) { + return key.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) { + return chr ? chr.toUpperCase() : ''; + }).replace(/^([A-Z])/, function(match, separator, chr) { + return match.toLowerCase(); + }); + }); + + var CLASSIFY_CACHE = new Cache(1000, function(str) { + var parts = str.split("."); + var out = []; + + for (var i=0, l=parts.length; i 2) { + cachedFormats = new Array(arguments.length - 1); + + for (var i = 1, l = arguments.length; i < l; i++) { + cachedFormats[i - 1] = arguments[i]; + } + } + + // first, replace any ORDERED replacements. + var idx = 0; // the current index for non-numerical replacements + return str.replace(/%@([0-9]+)?/g, function(s, argIndex) { + argIndex = (argIndex) ? parseInt(argIndex, 10) - 1 : idx++; + s = cachedFormats[argIndex]; + return (s === null) ? '(null)' : (s === undefined) ? '' : emberInspect(s); + }); + } + + function loc(str, formats) { + if (!isArray(formats) || arguments.length > 2) { + formats = Array.prototype.slice.call(arguments, 1); + } + + str = Ember.STRINGS[str] || str; + return fmt(str, formats); + } + + function w(str) { + return str.split(/\s+/); + } + + function decamelize(str) { + return DECAMELIZE_CACHE.get(str); + } + + function dasherize(str) { + return STRING_DASHERIZE_CACHE.get(str); + } + + function camelize(str) { + return CAMELIZE_CACHE.get(str); + } + + function classify(str) { + return CLASSIFY_CACHE.get(str); + } + + function underscore(str) { + return UNDERSCORE_CACHE.get(str); + } + + function capitalize(str) { + return CAPITALIZE_CACHE.get(str); + } + + /** + Defines the hash of localized strings for the current language. Used by + the `Ember.String.loc()` helper. To localize, add string values to this + hash. + + @property STRINGS + @for Ember + @type Hash + */ + Ember.STRINGS = {}; + + /** + Defines string helper methods including string formatting and localization. + Unless `Ember.EXTEND_PROTOTYPES.String` is `false` these methods will also be + added to the `String.prototype` as well. + + @class String + @namespace Ember + @static + */ + __exports__["default"] = { + /** + Apply formatting options to the string. This will look for occurrences + of "%@" in your string and substitute them with the arguments you pass into + this method. If you want to control the specific order of replacement, + you can add a number after the key as well to indicate which argument + you want to insert. + + Ordered insertions are most useful when building loc strings where values + you need to insert may appear in different orders. + + ```javascript + "Hello %@ %@".fmt('John', 'Doe'); // "Hello John Doe" + "Hello %@2, %@1".fmt('John', 'Doe'); // "Hello Doe, John" + ``` + + @method fmt + @param {String} str The string to format + @param {Array} formats An array of parameters to interpolate into string. + @return {String} formatted string + */ + fmt: fmt, + + /** + Formats the passed string, but first looks up the string in the localized + strings hash. This is a convenient way to localize text. See + `Ember.String.fmt()` for more information on formatting. + + Note that it is traditional but not required to prefix localized string + keys with an underscore or other character so you can easily identify + localized strings. + + ```javascript + Ember.STRINGS = { + '_Hello World': 'Bonjour le monde', + '_Hello %@ %@': 'Bonjour %@ %@' + }; + + Ember.String.loc("_Hello World"); // 'Bonjour le monde'; + Ember.String.loc("_Hello %@ %@", ["John", "Smith"]); // "Bonjour John Smith"; + ``` + + @method loc + @param {String} str The string to format + @param {Array} formats Optional array of parameters to interpolate into string. + @return {String} formatted string + */ + loc: loc, + + /** + Splits a string into separate units separated by spaces, eliminating any + empty strings in the process. This is a convenience method for split that + is mostly useful when applied to the `String.prototype`. + + ```javascript + Ember.String.w("alpha beta gamma").forEach(function(key) { + console.log(key); + }); + + // > alpha + // > beta + // > gamma + ``` + + @method w + @param {String} str The string to split + @return {Array} array containing the split strings + */ + w: w, + + /** + Converts a camelized string into all lower case separated by underscores. + + ```javascript + 'innerHTML'.decamelize(); // 'inner_html' + 'action_name'.decamelize(); // 'action_name' + 'css-class-name'.decamelize(); // 'css-class-name' + 'my favorite items'.decamelize(); // 'my favorite items' + ``` + + @method decamelize + @param {String} str The string to decamelize. + @return {String} the decamelized string. + */ + decamelize: decamelize, + + /** + Replaces underscores, spaces, or camelCase with dashes. + + ```javascript + 'innerHTML'.dasherize(); // 'inner-html' + 'action_name'.dasherize(); // 'action-name' + 'css-class-name'.dasherize(); // 'css-class-name' + 'my favorite items'.dasherize(); // 'my-favorite-items' + ``` + + @method dasherize + @param {String} str The string to dasherize. + @return {String} the dasherized string. + */ + dasherize: dasherize, + + /** + Returns the lowerCamelCase form of a string. + + ```javascript + 'innerHTML'.camelize(); // 'innerHTML' + 'action_name'.camelize(); // 'actionName' + 'css-class-name'.camelize(); // 'cssClassName' + 'my favorite items'.camelize(); // 'myFavoriteItems' + 'My Favorite Items'.camelize(); // 'myFavoriteItems' + ``` + + @method camelize + @param {String} str The string to camelize. + @return {String} the camelized string. + */ + camelize: camelize, + + /** + Returns the UpperCamelCase form of a string. + + ```javascript + 'innerHTML'.classify(); // 'InnerHTML' + 'action_name'.classify(); // 'ActionName' + 'css-class-name'.classify(); // 'CssClassName' + 'my favorite items'.classify(); // 'MyFavoriteItems' + ``` + + @method classify + @param {String} str the string to classify + @return {String} the classified string + */ + classify: classify, + + /** + More general than decamelize. Returns the lower\_case\_and\_underscored + form of a string. + + ```javascript + 'innerHTML'.underscore(); // 'inner_html' + 'action_name'.underscore(); // 'action_name' + 'css-class-name'.underscore(); // 'css_class_name' + 'my favorite items'.underscore(); // 'my_favorite_items' + ``` + + @method underscore + @param {String} str The string to underscore. + @return {String} the underscored string. + */ + underscore: underscore, + + /** + Returns the Capitalized form of a string + + ```javascript + 'innerHTML'.capitalize() // 'InnerHTML' + 'action_name'.capitalize() // 'Action_name' + 'css-class-name'.capitalize() // 'Css-class-name' + 'my favorite items'.capitalize() // 'My favorite items' + ``` + + @method capitalize + @param {String} str The string to capitalize. + @return {String} The capitalized string. + */ + capitalize: capitalize + }; + + __exports__.fmt = fmt; + __exports__.loc = loc; + __exports__.w = w; + __exports__.decamelize = decamelize; + __exports__.dasherize = dasherize; + __exports__.camelize = camelize; + __exports__.classify = classify; + __exports__.underscore = underscore; + __exports__.capitalize = capitalize; + }); +define("ember-runtime/system/subarray", + ["ember-metal/property_get","ember-metal/error","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var EmberError = __dependency2__["default"]; + var EnumerableUtils = __dependency3__["default"]; + + var RETAIN = 'r'; + var FILTER = 'f'; + + function Operation(type, count) { + this.type = type; + this.count = count; + } + + __exports__["default"] = SubArray; + + /** + An `Ember.SubArray` tracks an array in a way similar to, but more specialized + than, `Ember.TrackedArray`. It is useful for keeping track of the indexes of + items within a filtered array. + + @class SubArray + @namespace Ember + */ + function SubArray (length) { + if (arguments.length < 1) { length = 0; } + + if (length > 0) { + this._operations = [new Operation(RETAIN, length)]; + } else { + this._operations = []; + } + } + + + SubArray.prototype = { + /** + Track that an item was added to the tracked array. + + @method addItem + + @param {Number} index The index of the item in the tracked array. + @param {Boolean} match `true` iff the item is included in the subarray. + + @return {number} The index of the item in the subarray. + */ + addItem: function(index, match) { + var returnValue = -1; + var itemType = match ? RETAIN : FILTER; + var self = this; + + this._findOperation(index, function(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { + var newOperation, splitOperation; + + if (itemType === operation.type) { + ++operation.count; + } else if (index === rangeStart) { + // insert to the left of `operation` + self._operations.splice(operationIndex, 0, new Operation(itemType, 1)); + } else { + newOperation = new Operation(itemType, 1); + splitOperation = new Operation(operation.type, rangeEnd - index + 1); + operation.count = index - rangeStart; + + self._operations.splice(operationIndex + 1, 0, newOperation, splitOperation); + } + + if (match) { + if (operation.type === RETAIN) { + returnValue = seenInSubArray + (index - rangeStart); + } else { + returnValue = seenInSubArray; + } + } + + self._composeAt(operationIndex); + }, function(seenInSubArray) { + self._operations.push(new Operation(itemType, 1)); + + if (match) { + returnValue = seenInSubArray; + } + + self._composeAt(self._operations.length-1); + }); + + return returnValue; + }, + + /** + Track that an item was removed from the tracked array. + + @method removeItem + + @param {Number} index The index of the item in the tracked array. + + @return {number} The index of the item in the subarray, or `-1` if the item + was not in the subarray. + */ + removeItem: function(index) { + var returnValue = -1; + var self = this; + + this._findOperation(index, function (operation, operationIndex, rangeStart, rangeEnd, seenInSubArray) { + if (operation.type === RETAIN) { + returnValue = seenInSubArray + (index - rangeStart); + } + + if (operation.count > 1) { + --operation.count; + } else { + self._operations.splice(operationIndex, 1); + self._composeAt(operationIndex); + } + }, function() { + throw new EmberError("Can't remove an item that has never been added."); + }); + + return returnValue; + }, + + + _findOperation: function (index, foundCallback, notFoundCallback) { + var seenInSubArray = 0; + var operationIndex, len, operation, rangeStart, rangeEnd; + + // OPTIMIZE: change to balanced tree + // find leftmost operation to the right of `index` + for (operationIndex = rangeStart = 0, len = this._operations.length; operationIndex < len; rangeStart = rangeEnd + 1, ++operationIndex) { + operation = this._operations[operationIndex]; + rangeEnd = rangeStart + operation.count - 1; + + if (index >= rangeStart && index <= rangeEnd) { + foundCallback(operation, operationIndex, rangeStart, rangeEnd, seenInSubArray); + return; + } else if (operation.type === RETAIN) { + seenInSubArray += operation.count; + } + } + + notFoundCallback(seenInSubArray); + }, + + _composeAt: function(index) { + var op = this._operations[index]; + var otherOp; + + if (!op) { + // Composing out of bounds is a no-op, as when removing the last operation + // in the list. + return; + } + + if (index > 0) { + otherOp = this._operations[index-1]; + if (otherOp.type === op.type) { + op.count += otherOp.count; + this._operations.splice(index-1, 1); + --index; + } + } + + if (index < this._operations.length-1) { + otherOp = this._operations[index+1]; + if (otherOp.type === op.type) { + op.count += otherOp.count; + this._operations.splice(index+1, 1); + } + } + }, + + toString: function () { + var str = ""; + EnumerableUtils.forEach(this._operations, function (operation) { + str += " " + operation.type + ":" + operation.count; + }); + return str.substring(1); + } + }; + }); +define("ember-runtime/system/tracked_array", + ["ember-metal/property_get","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var get = __dependency1__.get; + var forEach = __dependency2__.forEach; + + var RETAIN = 'r'; + var INSERT = 'i'; + var DELETE = 'd'; + + __exports__["default"] = TrackedArray; + + /** + An `Ember.TrackedArray` tracks array operations. It's useful when you want to + lazily compute the indexes of items in an array after they've been shifted by + subsequent operations. + + @class TrackedArray + @namespace Ember + @param {Array} [items=[]] The array to be tracked. This is used just to get + the initial items for the starting state of retain:n. + */ + function TrackedArray(items) { + if (arguments.length < 1) { items = []; } + + var length = get(items, 'length'); + + if (length) { + this._operations = [new ArrayOperation(RETAIN, length, items)]; + } else { + this._operations = []; + } + } + + TrackedArray.RETAIN = RETAIN; + TrackedArray.INSERT = INSERT; + TrackedArray.DELETE = DELETE; + + TrackedArray.prototype = { + + /** + Track that `newItems` were added to the tracked array at `index`. + + @method addItems + @param index + @param newItems + */ + addItems: function (index, newItems) { + var count = get(newItems, 'length'); + if (count < 1) { return; } + + var match = this._findArrayOperation(index); + var arrayOperation = match.operation; + var arrayOperationIndex = match.index; + var arrayOperationRangeStart = match.rangeStart; + var composeIndex, splitIndex, splitItems, splitArrayOperation, newArrayOperation; + + newArrayOperation = new ArrayOperation(INSERT, count, newItems); + + if (arrayOperation) { + if (!match.split) { + // insert left of arrayOperation + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); + composeIndex = arrayOperationIndex; + } else { + this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); + composeIndex = arrayOperationIndex + 1; + } + } else { + // insert at end + this._operations.push(newArrayOperation); + composeIndex = arrayOperationIndex; + } + + this._composeInsert(composeIndex); + }, + + /** + Track that `count` items were removed at `index`. + + @method removeItems + @param index + @param count + */ + removeItems: function (index, count) { + if (count < 1) { return; } + + var match = this._findArrayOperation(index); + var arrayOperation = match.operation; + var arrayOperationIndex = match.index; + var arrayOperationRangeStart = match.rangeStart; + var newArrayOperation, composeIndex; + + newArrayOperation = new ArrayOperation(DELETE, count); + if (!match.split) { + // insert left of arrayOperation + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); + composeIndex = arrayOperationIndex; + } else { + this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); + composeIndex = arrayOperationIndex + 1; + } + + return this._composeDelete(composeIndex); + }, + + /** + Apply all operations, reducing them to retain:n, for `n`, the number of + items in the array. + + `callback` will be called for each operation and will be passed the following arguments: + + * {array} items The items for the given operation + * {number} offset The computed offset of the items, ie the index in the + array of the first item for this operation. + * {string} operation The type of the operation. One of + `Ember.TrackedArray.{RETAIN, DELETE, INSERT}` + + @method apply + @param {Function} callback + */ + apply: function (callback) { + var items = []; + var offset = 0; + + forEach(this._operations, function (arrayOperation, operationIndex) { + callback(arrayOperation.items, offset, arrayOperation.type, operationIndex); + + if (arrayOperation.type !== DELETE) { + offset += arrayOperation.count; + items = items.concat(arrayOperation.items); + } + }); + + this._operations = [new ArrayOperation(RETAIN, items.length, items)]; + }, + + /** + Return an `ArrayOperationMatch` for the operation that contains the item at `index`. + + @method _findArrayOperation + + @param {Number} index the index of the item whose operation information + should be returned. + @private + */ + _findArrayOperation: function (index) { + var split = false; + var arrayOperationIndex, arrayOperation, + arrayOperationRangeStart, arrayOperationRangeEnd, + len; + + // OPTIMIZE: we could search these faster if we kept a balanced tree. + // find leftmost arrayOperation to the right of `index` + for (arrayOperationIndex = arrayOperationRangeStart = 0, len = this._operations.length; arrayOperationIndex < len; ++arrayOperationIndex) { + arrayOperation = this._operations[arrayOperationIndex]; + + if (arrayOperation.type === DELETE) { continue; } + + arrayOperationRangeEnd = arrayOperationRangeStart + arrayOperation.count - 1; + + if (index === arrayOperationRangeStart) { + break; + } else if (index > arrayOperationRangeStart && index <= arrayOperationRangeEnd) { + split = true; + break; + } else { + arrayOperationRangeStart = arrayOperationRangeEnd + 1; + } + } + + return new ArrayOperationMatch(arrayOperation, arrayOperationIndex, split, arrayOperationRangeStart); + }, + + _split: function (arrayOperationIndex, splitIndex, newArrayOperation) { + var arrayOperation = this._operations[arrayOperationIndex]; + var splitItems = arrayOperation.items.slice(splitIndex); + var splitArrayOperation = new ArrayOperation(arrayOperation.type, splitItems.length, splitItems); + + // truncate LHS + arrayOperation.count = splitIndex; + arrayOperation.items = arrayOperation.items.slice(0, splitIndex); + + this._operations.splice(arrayOperationIndex + 1, 0, newArrayOperation, splitArrayOperation); + }, + + // see SubArray for a better implementation. + _composeInsert: function (index) { + var newArrayOperation = this._operations[index]; + var leftArrayOperation = this._operations[index-1]; // may be undefined + var rightArrayOperation = this._operations[index+1]; // may be undefined + var leftOp = leftArrayOperation && leftArrayOperation.type; + var rightOp = rightArrayOperation && rightArrayOperation.type; + + if (leftOp === INSERT) { + // merge left + leftArrayOperation.count += newArrayOperation.count; + leftArrayOperation.items = leftArrayOperation.items.concat(newArrayOperation.items); + + if (rightOp === INSERT) { + // also merge right (we have split an insert with an insert) + leftArrayOperation.count += rightArrayOperation.count; + leftArrayOperation.items = leftArrayOperation.items.concat(rightArrayOperation.items); + this._operations.splice(index, 2); + } else { + // only merge left + this._operations.splice(index, 1); + } + } else if (rightOp === INSERT) { + // merge right + newArrayOperation.count += rightArrayOperation.count; + newArrayOperation.items = newArrayOperation.items.concat(rightArrayOperation.items); + this._operations.splice(index + 1, 1); + } + }, + + _composeDelete: function (index) { + var arrayOperation = this._operations[index]; + var deletesToGo = arrayOperation.count; + var leftArrayOperation = this._operations[index-1]; // may be undefined + var leftOp = leftArrayOperation && leftArrayOperation.type; + var nextArrayOperation; + var nextOp; + var nextCount; + var removeNewAndNextOp = false; + var removedItems = []; + + if (leftOp === DELETE) { + arrayOperation = leftArrayOperation; + index -= 1; + } + + for (var i = index + 1; deletesToGo > 0; ++i) { + nextArrayOperation = this._operations[i]; + nextOp = nextArrayOperation.type; + nextCount = nextArrayOperation.count; + + if (nextOp === DELETE) { + arrayOperation.count += nextCount; + continue; + } + + if (nextCount > deletesToGo) { + // d:2 {r,i}:5 we reduce the retain or insert, but it stays + removedItems = removedItems.concat(nextArrayOperation.items.splice(0, deletesToGo)); + nextArrayOperation.count -= deletesToGo; + + // In the case where we truncate the last arrayOperation, we don't need to + // remove it; also the deletesToGo reduction is not the entirety of + // nextCount + i -= 1; + nextCount = deletesToGo; + + deletesToGo = 0; + } else { + if (nextCount === deletesToGo) { + // Handle edge case of d:2 i:2 in which case both operations go away + // during composition. + removeNewAndNextOp = true; + } + removedItems = removedItems.concat(nextArrayOperation.items); + deletesToGo -= nextCount; + } + + if (nextOp === INSERT) { + // d:2 i:3 will result in delete going away + arrayOperation.count -= nextCount; + } + } + + if (arrayOperation.count > 0) { + // compose our new delete with possibly several operations to the right of + // disparate types + this._operations.splice(index+1, i-1-index); + } else { + // The delete operation can go away; it has merely reduced some other + // operation, as in d:3 i:4; it may also have eliminated that operation, + // as in d:3 i:3. + this._operations.splice(index, removeNewAndNextOp ? 2 : 1); + } + + return removedItems; + }, + + toString: function () { + var str = ""; + forEach(this._operations, function (operation) { + str += " " + operation.type + ":" + operation.count; + }); + return str.substring(1); + } + }; + + /** + Internal data structure to represent an array operation. + + @method ArrayOperation + @private + @param {String} type The type of the operation. One of + `Ember.TrackedArray.{RETAIN, INSERT, DELETE}` + @param {Number} count The number of items in this operation. + @param {Array} items The items of the operation, if included. RETAIN and + INSERT include their items, DELETE does not. + */ + function ArrayOperation (operation, count, items) { + this.type = operation; // RETAIN | INSERT | DELETE + this.count = count; + this.items = items; + } + + /** + Internal data structure used to include information when looking up operations + by item index. + + @method ArrayOperationMatch + @private + @param {ArrayOperation} operation + @param {Number} index The index of `operation` in the array of operations. + @param {Boolean} split Whether or not the item index searched for would + require a split for a new operation type. + @param {Number} rangeStart The index of the first item in the operation, + with respect to the tracked array. The index of the last item can be computed + from `rangeStart` and `operation.count`. + */ + function ArrayOperationMatch(operation, index, split, rangeStart) { + this.operation = operation; + this.index = index; + this.split = split; + this.rangeStart = rangeStart; + } + }); +define("ember-testing", + ["ember-metal/core","ember-testing/initializers","ember-testing/support","ember-testing/setup_for_testing","ember-testing/test","ember-testing/adapters/adapter","ember-testing/adapters/qunit","ember-testing/helpers"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { + "use strict"; + var Ember = __dependency1__["default"]; + + // to setup initializer + // to handle various edge cases + + var setupForTesting = __dependency4__["default"]; + var Test = __dependency5__["default"]; + var Adapter = __dependency6__["default"]; + var QUnitAdapter = __dependency7__["default"]; + // adds helpers to helpers object in Test + + /** + Ember Testing + + @module ember + @submodule ember-testing + @requires ember-application + */ + + Ember.Test = Test; + Ember.Test.Adapter = Adapter; + Ember.Test.QUnitAdapter = QUnitAdapter; + Ember.setupForTesting = setupForTesting; + }); +define("ember-testing/adapters/adapter", + ["ember-metal/core","ember-metal/utils","ember-runtime/system/object","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.K + var inspect = __dependency2__.inspect; + var EmberObject = __dependency3__["default"]; + + /** + @module ember + @submodule ember-testing + */ + + /** + The primary purpose of this class is to create hooks that can be implemented + by an adapter for various test frameworks. + + @class Adapter + @namespace Ember.Test + */ + var Adapter = EmberObject.extend({ + /** + This callback will be called whenever an async operation is about to start. + + Override this to call your framework's methods that handle async + operations. + + @public + @method asyncStart + */ + asyncStart: Ember.K, + + /** + This callback will be called whenever an async operation has completed. + + @public + @method asyncEnd + */ + asyncEnd: Ember.K, + + /** + Override this method with your testing framework's false assertion. + This function is called whenever an exception occurs causing the testing + promise to fail. + + QUnit example: + + ```javascript + exception: function(error) { + ok(false, error); + }; + ``` + + @public + @method exception + @param {String} error The exception to be raised. + */ + exception: function(error) { + throw error; + } + }); + + __exports__["default"] = Adapter; + }); +define("ember-testing/adapters/qunit", + ["ember-testing/adapters/adapter","ember-metal/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Adapter = __dependency1__["default"]; + var inspect = __dependency2__.inspect; + + /** + This class implements the methods defined by Ember.Test.Adapter for the + QUnit testing framework. + + @class QUnitAdapter + @namespace Ember.Test + @extends Ember.Test.Adapter + */ + __exports__["default"] = Adapter.extend({ + asyncStart: function() { + QUnit.stop(); + }, + asyncEnd: function() { + QUnit.start(); + }, + exception: function(error) { + ok(false, inspect(error)); + } + }); + }); +define("ember-testing/helpers", + ["ember-metal/property_get","ember-metal/error","ember-metal/run_loop","ember-views/system/jquery","ember-testing/test"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) { + "use strict"; + var get = __dependency1__.get; + var EmberError = __dependency2__["default"]; + var run = __dependency3__["default"]; + var jQuery = __dependency4__["default"]; + var Test = __dependency5__["default"]; + + /** + * @module ember + * @submodule ember-testing + */ + + var helper = Test.registerHelper; + var asyncHelper = Test.registerAsyncHelper; + var countAsync = 0; + + function currentRouteName(app){ + var appController = app.__container__.lookup('controller:application'); + + return get(appController, 'currentRouteName'); + } + + function currentPath(app){ + var appController = app.__container__.lookup('controller:application'); + + return get(appController, 'currentPath'); + } + + function currentURL(app){ + var router = app.__container__.lookup('router:main'); + + return get(router, 'location').getURL(); + } + + function visit(app, url) { + var router = app.__container__.lookup('router:main'); + router.location.setURL(url); + + if (app._readinessDeferrals > 0) { + router['initialURL'] = url; + run(app, 'advanceReadiness'); + delete router['initialURL']; + } else { + run(app, app.handleURL, url); + } + + return app.testHelpers.wait(); + } + + function click(app, selector, context) { + var $el = app.testHelpers.findWithAssert(selector, context); + run($el, 'mousedown'); + + if ($el.is(':input')) { + var type = $el.prop('type'); + if (type !== 'checkbox' && type !== 'radio' && type !== 'hidden') { + run($el, function(){ + // Firefox does not trigger the `focusin` event if the window + // does not have focus. If the document doesn't have focus just + // use trigger('focusin') instead. + if (!document.hasFocus || document.hasFocus()) { + this.focus(); + } else { + this.trigger('focusin'); + } + }); + } + } + + run($el, 'mouseup'); + run($el, 'click'); + + return app.testHelpers.wait(); + } + + function triggerEvent(app, selector, contextOrType, typeOrOptions, possibleOptions){ + var arity = arguments.length; + var context, type, options; + + if (arity === 3) { + // context and options are optional, so this is + // app, selector, type + context = null; + type = contextOrType; + options = {}; + } else if (arity === 4) { + // context and options are optional, so this is + if (typeof typeOrOptions === "object") { // either + // app, selector, type, options + context = null; + type = contextOrType; + options = typeOrOptions; + } else { // or + // app, selector, context, type + context = contextOrType; + type = typeOrOptions; + options = {}; + } + } else { + context = contextOrType; + type = typeOrOptions; + options = possibleOptions; + } + + var $el = app.testHelpers.findWithAssert(selector, context); + + var event = jQuery.Event(type, options); + + run($el, 'trigger', event); + + return app.testHelpers.wait(); + } + + function keyEvent(app, selector, contextOrType, typeOrKeyCode, keyCode) { + var context, type; + + if (typeof keyCode === 'undefined') { + context = null; + keyCode = typeOrKeyCode; + type = contextOrType; + } else { + context = contextOrType; + type = typeOrKeyCode; + } + + return app.testHelpers.triggerEvent(selector, context, type, { keyCode: keyCode, which: keyCode }); + } + + function fillIn(app, selector, contextOrText, text) { + var $el, context; + if (typeof text === 'undefined') { + text = contextOrText; + } else { + context = contextOrText; + } + $el = app.testHelpers.findWithAssert(selector, context); + run(function() { + $el.val(text).change(); + }); + return app.testHelpers.wait(); + } + + function findWithAssert(app, selector, context) { + var $el = app.testHelpers.find(selector, context); + if ($el.length === 0) { + throw new EmberError("Element " + selector + " not found."); + } + return $el; + } + + function find(app, selector, context) { + var $el; + context = context || get(app, 'rootElement'); + $el = app.$(selector, context); + + return $el; + } + + function andThen(app, callback) { + return app.testHelpers.wait(callback(app)); + } + + function wait(app, value) { + return Test.promise(function(resolve) { + // If this is the first async promise, kick off the async test + if (++countAsync === 1) { + Test.adapter.asyncStart(); + } + + // Every 10ms, poll for the async thing to have finished + var watcher = setInterval(function() { + // 1. If the router is loading, keep polling + var routerIsLoading = !!app.__container__.lookup('router:main').router.activeTransition; + if (routerIsLoading) { return; } + + // 2. If there are pending Ajax requests, keep polling + if (Test.pendingAjaxRequests) { return; } + + // 3. If there are scheduled timers or we are inside of a run loop, keep polling + if (run.hasScheduledTimers() || run.currentRunLoop) { return; } + if (Test.waiters && Test.waiters.any(function(waiter) { + var context = waiter[0]; + var callback = waiter[1]; + return !callback.call(context); + })) { return; } + // Stop polling + clearInterval(watcher); + + // If this is the last async promise, end the async test + if (--countAsync === 0) { + Test.adapter.asyncEnd(); + } + + // Synchronously resolve the promise + run(null, resolve, value); + }, 10); + }); + + } + + + /** + * Loads a route, sets up any controllers, and renders any templates associated + * with the route as though a real user had triggered the route change while + * using your app. + * + * Example: + * + * ```javascript + * visit('posts/index').then(function() { + * // assert something + * }); + * ``` + * + * @method visit + * @param {String} url the name of the route + * @return {RSVP.Promise} + */ + asyncHelper('visit', visit); + + /** + * Clicks an element and triggers any actions triggered by the element's `click` + * event. + * + * Example: + * + * ```javascript + * click('.some-jQuery-selector').then(function() { + * // assert something + * }); + * ``` + * + * @method click + * @param {String} selector jQuery selector for finding element on the DOM + * @return {RSVP.Promise} + */ + asyncHelper('click', click); + + /** + * Simulates a key event, e.g. `keypress`, `keydown`, `keyup` with the desired keyCode + * + * Example: + * + * ```javascript + * keyEvent('.some-jQuery-selector', 'keypress', 13).then(function() { + * // assert something + * }); + * ``` + * + * @method keyEvent + * @param {String} selector jQuery selector for finding element on the DOM + * @param {String} type the type of key event, e.g. `keypress`, `keydown`, `keyup` + * @param {Number} keyCode the keyCode of the simulated key event + * @return {RSVP.Promise} + * @since 1.5.0 + */ + asyncHelper('keyEvent', keyEvent); + + /** + * Fills in an input element with some text. + * + * Example: + * + * ```javascript + * fillIn('#email', 'you@example.com').then(function() { + * // assert something + * }); + * ``` + * + * @method fillIn + * @param {String} selector jQuery selector finding an input element on the DOM + * to fill text with + * @param {String} text text to place inside the input element + * @return {RSVP.Promise} + */ + asyncHelper('fillIn', fillIn); + + /** + * Finds an element in the context of the app's container element. A simple alias + * for `app.$(selector)`. + * + * Example: + * + * ```javascript + * var $el = find('.my-selector'); + * ``` + * + * @method find + * @param {String} selector jQuery string selector for element lookup + * @return {Object} jQuery object representing the results of the query + */ + helper('find', find); + + /** + * Like `find`, but throws an error if the element selector returns no results. + * + * Example: + * + * ```javascript + * var $el = findWithAssert('.doesnt-exist'); // throws error + * ``` + * + * @method findWithAssert + * @param {String} selector jQuery selector string for finding an element within + * the DOM + * @return {Object} jQuery object representing the results of the query + * @throws {Error} throws error if jQuery object returned has a length of 0 + */ + helper('findWithAssert', findWithAssert); + + /** + Causes the run loop to process any pending events. This is used to ensure that + any async operations from other helpers (or your assertions) have been processed. + + This is most often used as the return value for the helper functions (see 'click', + 'fillIn','visit',etc). + + Example: + + ```javascript + Ember.Test.registerAsyncHelper('loginUser', function(app, username, password) { + visit('secured/path/here') + .fillIn('#username', username) + .fillIn('#password', username) + .click('.submit') + + return app.testHelpers.wait(); + }); + + @method wait + @param {Object} value The value to be returned. + @return {RSVP.Promise} + */ + asyncHelper('wait', wait); + asyncHelper('andThen', andThen); + + + /** + Returns the currently active route name. + + Example: + + ```javascript + function validateRouteName(){ + equal(currentRouteName(), 'some.path', "correct route was transitioned into."); + } + + visit('/some/path').then(validateRouteName) + ``` + + @method currentRouteName + @return {Object} The name of the currently active route. + @since 1.5.0 + */ + helper('currentRouteName', currentRouteName); + + /** + Returns the current path. + + Example: + + ```javascript + function validateURL(){ + equal(currentPath(), 'some.path.index', "correct path was transitioned into."); + } + + click('#some-link-id').then(validateURL); + ``` + + @method currentPath + @return {Object} The currently active path. + @since 1.5.0 + */ + helper('currentPath', currentPath); + + /** + Returns the current URL. + + Example: + + ```javascript + function validateURL(){ + equal(currentURL(), '/some/path', "correct URL was transitioned into."); + } + + click('#some-link-id').then(validateURL); + ``` + + @method currentURL + @return {Object} The currently active URL. + @since 1.5.0 + */ + helper('currentURL', currentURL); + + /** + Triggers the given DOM event on the element identified by the provided selector. + + Example: + + ```javascript + triggerEvent('#some-elem-id', 'blur'); + ``` + + This is actually used internally by the `keyEvent` helper like so: + + ```javascript + triggerEvent('#some-elem-id', 'keypress', { keyCode: 13 }); + ``` + + @method triggerEvent + @param {String} selector jQuery selector for finding element on the DOM + @param {String} [context] jQuery selector that will limit the selector + argument to find only within the context's children + @param {String} type The event type to be triggered. + @param {Object} [options] The options to be passed to jQuery.Event. + @return {RSVP.Promise} + @since 1.5.0 + */ + asyncHelper('triggerEvent', triggerEvent); + }); +define("ember-testing/initializers", + ["ember-runtime/system/lazy_load"], + function(__dependency1__) { + "use strict"; + var onLoad = __dependency1__.onLoad; + + var name = 'deferReadiness in `testing` mode'; + + onLoad('Ember.Application', function(Application) { + if (!Application.initializers[name]) { + Application.initializer({ + name: name, + + initialize: function(container, application){ + if (application.testing) { + application.deferReadiness(); + } + } + }); + } + }); + }); +define("ember-testing/setup_for_testing", + ["ember-metal/core","ember-testing/adapters/qunit","ember-views/system/jquery","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // import Test from "ember-testing/test"; // ES6TODO: fix when cycles are supported + var QUnitAdapter = __dependency2__["default"]; + var jQuery = __dependency3__["default"]; + + var Test, requests; + + function incrementAjaxPendingRequests(_, xhr){ + requests.push(xhr); + Test.pendingAjaxRequests = requests.length; + } + + function decrementAjaxPendingRequests(_, xhr){ + for (var i=0;i') + .css({ position: 'absolute', left: '-1000px', top: '-1000px' }) + .appendTo('body') + .on('click', handler) + .trigger('click') + .remove(); + } + + $(function() { + /* + Determine whether a checkbox checked using jQuery's "click" method will have + the correct value for its checked property. + + If we determine that the current jQuery version exhibits this behavior, + patch it to work correctly as in the commit for the actual fix: + https://github.com/jquery/jquery/commit/1fb2f92. + */ + testCheckboxClick(function() { + if (!this.checked && !$.event.special.click) { + $.event.special.click = { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ($.nodeName( this, "input" ) && this.type === "checkbox" && this.click) { + this.click(); + return false; + } + } + }; + } + }); + + // Try again to verify that the patch took effect or blow up. + testCheckboxClick(function() { + }); + }); + }); +define("ember-testing/test", + ["ember-metal/core","ember-metal/run_loop","ember-metal/platform","ember-runtime/compare","ember-runtime/ext/rsvp","ember-testing/setup_for_testing","ember-application/system/application","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var emberRun = __dependency2__["default"]; + var create = __dependency3__.create; + var compare = __dependency4__["default"]; + var RSVP = __dependency5__["default"]; + var setupForTesting = __dependency6__["default"]; + var EmberApplication = __dependency7__["default"]; + + /** + @module ember + @submodule ember-testing + */ + var slice = [].slice; + var helpers = {}; + var injectHelpersCallbacks = []; + + /** + This is a container for an assortment of testing related functionality: + + * Choose your default test adapter (for your framework of choice). + * Register/Unregister additional test helpers. + * Setup callbacks to be fired when the test helpers are injected into + your application. + + @class Test + @namespace Ember + */ + var Test = { + /** + Hash containing all known test helpers. + + @property _helpers + @private + @since 1.7.0 + */ + _helpers: helpers, + + /** + `registerHelper` is used to register a test helper that will be injected + when `App.injectTestHelpers` is called. + + The helper method will always be called with the current Application as + the first parameter. + + For example: + + ```javascript + Ember.Test.registerHelper('boot', function(app) { + Ember.run(app, app.advanceReadiness); + }); + ``` + + This helper can later be called without arguments because it will be + called with `app` as the first parameter. + + ```javascript + App = Ember.Application.create(); + App.injectTestHelpers(); + boot(); + ``` + + @public + @method registerHelper + @param {String} name The name of the helper method to add. + @param {Function} helperMethod + @param options {Object} + */ + registerHelper: function(name, helperMethod) { + helpers[name] = { + method: helperMethod, + meta: { wait: false } + }; + }, + + /** + `registerAsyncHelper` is used to register an async test helper that will be injected + when `App.injectTestHelpers` is called. + + The helper method will always be called with the current Application as + the first parameter. + + For example: + + ```javascript + Ember.Test.registerAsyncHelper('boot', function(app) { + Ember.run(app, app.advanceReadiness); + }); + ``` + + The advantage of an async helper is that it will not run + until the last async helper has completed. All async helpers + after it will wait for it complete before running. + + + For example: + + ```javascript + Ember.Test.registerAsyncHelper('deletePost', function(app, postId) { + click('.delete-' + postId); + }); + + // ... in your test + visit('/post/2'); + deletePost(2); + visit('/post/3'); + deletePost(3); + ``` + + @public + @method registerAsyncHelper + @param {String} name The name of the helper method to add. + @param {Function} helperMethod + @since 1.2.0 + */ + registerAsyncHelper: function(name, helperMethod) { + helpers[name] = { + method: helperMethod, + meta: { wait: true } + }; + }, + + /** + Remove a previously added helper method. + + Example: + + ```javascript + Ember.Test.unregisterHelper('wait'); + ``` + + @public + @method unregisterHelper + @param {String} name The helper to remove. + */ + unregisterHelper: function(name) { + delete helpers[name]; + delete Test.Promise.prototype[name]; + }, + + /** + Used to register callbacks to be fired whenever `App.injectTestHelpers` + is called. + + The callback will receive the current application as an argument. + + Example: + + ```javascript + Ember.Test.onInjectHelpers(function() { + Ember.$(document).ajaxSend(function() { + Test.pendingAjaxRequests++; + }); + + Ember.$(document).ajaxComplete(function() { + Test.pendingAjaxRequests--; + }); + }); + ``` + + @public + @method onInjectHelpers + @param {Function} callback The function to be called. + */ + onInjectHelpers: function(callback) { + injectHelpersCallbacks.push(callback); + }, + + /** + This returns a thenable tailored for testing. It catches failed + `onSuccess` callbacks and invokes the `Ember.Test.adapter.exception` + callback in the last chained then. + + This method should be returned by async helpers such as `wait`. + + @public + @method promise + @param {Function} resolver The function used to resolve the promise. + */ + promise: function(resolver) { + return new Test.Promise(resolver); + }, + + /** + Used to allow ember-testing to communicate with a specific testing + framework. + + You can manually set it before calling `App.setupForTesting()`. + + Example: + + ```javascript + Ember.Test.adapter = MyCustomAdapter.create() + ``` + + If you do not set it, ember-testing will default to `Ember.Test.QUnitAdapter`. + + @public + @property adapter + @type {Class} The adapter to be used. + @default Ember.Test.QUnitAdapter + */ + adapter: null, + + /** + Replacement for `Ember.RSVP.resolve` + The only difference is this uses + an instance of `Ember.Test.Promise` + + @public + @method resolve + @param {Mixed} The value to resolve + @since 1.2.0 + */ + resolve: function(val) { + return Test.promise(function(resolve) { + return resolve(val); + }); + }, + + /** + This allows ember-testing to play nicely with other asynchronous + events, such as an application that is waiting for a CSS3 + transition or an IndexDB transaction. + + For example: + + ```javascript + Ember.Test.registerWaiter(function() { + return myPendingTransactions() == 0; + }); + ``` + The `context` argument allows you to optionally specify the `this` + with which your callback will be invoked. + + For example: + + ```javascript + Ember.Test.registerWaiter(MyDB, MyDB.hasPendingTransactions); + ``` + + @public + @method registerWaiter + @param {Object} context (optional) + @param {Function} callback + @since 1.2.0 + */ + registerWaiter: function(context, callback) { + if (arguments.length === 1) { + callback = context; + context = null; + } + if (!this.waiters) { + this.waiters = Ember.A(); + } + this.waiters.push([context, callback]); + }, + /** + `unregisterWaiter` is used to unregister a callback that was + registered with `registerWaiter`. + + @public + @method unregisterWaiter + @param {Object} context (optional) + @param {Function} callback + @since 1.2.0 + */ + unregisterWaiter: function(context, callback) { + var pair; + if (!this.waiters) { return; } + if (arguments.length === 1) { + callback = context; + context = null; + } + pair = [context, callback]; + this.waiters = Ember.A(this.waiters.filter(function(elt) { + return compare(elt, pair)!==0; + })); + } + }; + + function helper(app, name) { + var fn = helpers[name].method; + var meta = helpers[name].meta; + + return function() { + var args = slice.call(arguments); + var lastPromise = Test.lastPromise; + + args.unshift(app); + + // some helpers are not async and + // need to return a value immediately. + // example: `find` + if (!meta.wait) { + return fn.apply(app, args); + } + + if (!lastPromise) { + // It's the first async helper in current context + lastPromise = fn.apply(app, args); + } else { + // wait for last helper's promise to resolve + // and then execute + run(function() { + lastPromise = Test.resolve(lastPromise).then(function() { + return fn.apply(app, args); + }); + }); + } + + return lastPromise; + }; + } + + function run(fn) { + if (!emberRun.currentRunLoop) { + emberRun(fn); + } else { + fn(); + } + } + + EmberApplication.reopen({ + /** + This property contains the testing helpers for the current application. These + are created once you call `injectTestHelpers` on your `Ember.Application` + instance. The included helpers are also available on the `window` object by + default, but can be used from this object on the individual application also. + + @property testHelpers + @type {Object} + @default {} + */ + testHelpers: {}, + + /** + This property will contain the original methods that were registered + on the `helperContainer` before `injectTestHelpers` is called. + + When `removeTestHelpers` is called, these methods are restored to the + `helperContainer`. + + @property originalMethods + @type {Object} + @default {} + @private + @since 1.3.0 + */ + originalMethods: {}, + + + /** + This property indicates whether or not this application is currently in + testing mode. This is set when `setupForTesting` is called on the current + application. + + @property testing + @type {Boolean} + @default false + @since 1.3.0 + */ + testing: false, + + /** + This hook defers the readiness of the application, so that you can start + the app when your tests are ready to run. It also sets the router's + location to 'none', so that the window's location will not be modified + (preventing both accidental leaking of state between tests and interference + with your testing framework). + + Example: + + ``` + App.setupForTesting(); + ``` + + @method setupForTesting + */ + setupForTesting: function() { + setupForTesting(); + + this.testing = true; + + this.Router.reopen({ + location: 'none' + }); + }, + + /** + This will be used as the container to inject the test helpers into. By + default the helpers are injected into `window`. + + @property helperContainer + @type {Object} The object to be used for test helpers. + @default window + @since 1.2.0 + */ + helperContainer: window, + + /** + This injects the test helpers into the `helperContainer` object. If an object is provided + it will be used as the helperContainer. If `helperContainer` is not set it will default + to `window`. If a function of the same name has already been defined it will be cached + (so that it can be reset if the helper is removed with `unregisterHelper` or + `removeTestHelpers`). + + Any callbacks registered with `onInjectHelpers` will be called once the + helpers have been injected. + + Example: + ``` + App.injectTestHelpers(); + ``` + + @method injectTestHelpers + */ + injectTestHelpers: function(helperContainer) { + if (helperContainer) { this.helperContainer = helperContainer; } + + this.testHelpers = {}; + for (var name in helpers) { + this.originalMethods[name] = this.helperContainer[name]; + this.testHelpers[name] = this.helperContainer[name] = helper(this, name); + protoWrap(Test.Promise.prototype, name, helper(this, name), helpers[name].meta.wait); + } + + for(var i = 0, l = injectHelpersCallbacks.length; i < l; i++) { + injectHelpersCallbacks[i](this); + } + }, + + /** + This removes all helpers that have been registered, and resets and functions + that were overridden by the helpers. + + Example: + + ```javascript + App.removeTestHelpers(); + ``` + + @public + @method removeTestHelpers + */ + removeTestHelpers: function() { + for (var name in helpers) { + this.helperContainer[name] = this.originalMethods[name]; + delete this.testHelpers[name]; + delete this.originalMethods[name]; + } + } + }); + + // This method is no longer needed + // But still here for backwards compatibility + // of helper chaining + function protoWrap(proto, name, callback, isAsync) { + proto[name] = function() { + var args = arguments; + if (isAsync) { + return callback.apply(this, args); + } else { + return this.then(function() { + return callback.apply(this, args); + }); + } + }; + } + + Test.Promise = function() { + RSVP.Promise.apply(this, arguments); + Test.lastPromise = this; + }; + + Test.Promise.prototype = create(RSVP.Promise.prototype); + Test.Promise.prototype.constructor = Test.Promise; + + // Patch `then` to isolate async methods + // specifically `Ember.Test.lastPromise` + var originalThen = RSVP.Promise.prototype.then; + Test.Promise.prototype.then = function(onSuccess, onFailure) { + return originalThen.call(this, function(val) { + return isolate(onSuccess, val); + }, onFailure); + }; + + // This method isolates nested async methods + // so that they don't conflict with other last promises. + // + // 1. Set `Ember.Test.lastPromise` to null + // 2. Invoke method + // 3. Return the last promise created during method + // 4. Restore `Ember.Test.lastPromise` to original value + function isolate(fn, val) { + var value, lastPromise; + + // Reset lastPromise for nested helpers + Test.lastPromise = null; + + value = fn(val); + + lastPromise = Test.lastPromise; + + // If the method returned a promise + // return that promise. If not, + // return the last async helper's promise + if ((value && (value instanceof Test.Promise)) || !lastPromise) { + return value; + } else { + run(function() { + lastPromise = Test.resolve(lastPromise).then(function() { + return value; + }); + }); + return lastPromise; + } + } + + __exports__["default"] = Test; + }); +define("ember-views", + ["ember-runtime","ember-views/system/jquery","ember-views/system/utils","ember-views/system/render_buffer","ember-views/system/ext","ember-views/views/states","ember-views/views/core_view","ember-views/views/view","ember-views/views/container_view","ember-views/views/collection_view","ember-views/views/component","ember-views/system/event_dispatcher","ember-views/mixins/view_target_action_support","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __exports__) { + "use strict"; + /** + Ember Views + + @module ember + @submodule ember-views + @requires ember-runtime + @main ember-views + */ + + // BEGIN IMPORTS + var Ember = __dependency1__["default"]; + var jQuery = __dependency2__["default"]; + var isSimpleClick = __dependency3__.isSimpleClick; + var RenderBuffer = __dependency4__["default"]; + // for the side effect of extending Ember.run.queues + var cloneStates = __dependency6__.cloneStates; + var states = __dependency6__.states; + + var CoreView = __dependency7__["default"]; + var View = __dependency8__["default"]; + var ContainerView = __dependency9__["default"]; + var CollectionView = __dependency10__["default"]; + var Component = __dependency11__["default"]; + + var EventDispatcher = __dependency12__["default"]; + var ViewTargetActionSupport = __dependency13__["default"]; + // END IMPORTS + + /** + Alias for jQuery + + @method $ + @for Ember + */ + + // BEGIN EXPORTS + Ember.$ = jQuery; + + Ember.ViewTargetActionSupport = ViewTargetActionSupport; + Ember.RenderBuffer = RenderBuffer; + + var ViewUtils = Ember.ViewUtils = {}; + ViewUtils.isSimpleClick = isSimpleClick; + + Ember.CoreView = CoreView; + Ember.View = View; + Ember.View.states = states; + Ember.View.cloneStates = cloneStates; + + Ember.ContainerView = ContainerView; + Ember.CollectionView = CollectionView; + Ember.Component = Component; + Ember.EventDispatcher = EventDispatcher; + // END EXPORTS + + __exports__["default"] = Ember; + }); +define("ember-views/mixins/component_template_deprecation", + ["ember-metal/core","ember-metal/property_get","ember-metal/mixin","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.deprecate + var get = __dependency2__.get; + var Mixin = __dependency3__.Mixin; + + /** + The ComponentTemplateDeprecation mixin is used to provide a useful + deprecation warning when using either `template` or `templateName` with + a component. The `template` and `templateName` properties specified at + extend time are moved to `layout` and `layoutName` respectively. + + `Ember.ComponentTemplateDeprecation` is used internally by Ember in + `Ember.Component`. + + @class ComponentTemplateDeprecation + @namespace Ember + */ + __exports__["default"] = Mixin.create({ + /** + @private + + Moves `templateName` to `layoutName` and `template` to `layout` at extend + time if a layout is not also specified. + + Note that this currently modifies the mixin themselves, which is technically + dubious but is practically of little consequence. This may change in the + future. + + @method willMergeMixin + @since 1.4.0 + */ + willMergeMixin: function(props) { + // must call _super here to ensure that the ActionHandler + // mixin is setup properly (moves actions -> _actions) + // + // Calling super is only OK here since we KNOW that + // there is another Mixin loaded first. + this._super.apply(this, arguments); + + var deprecatedProperty, replacementProperty; + var layoutSpecified = (props.layoutName || props.layout || get(this, 'layoutName')); + + if (props.templateName && !layoutSpecified) { + deprecatedProperty = 'templateName'; + replacementProperty = 'layoutName'; + + props.layoutName = props.templateName; + delete props['templateName']; + } + + if (props.template && !layoutSpecified) { + deprecatedProperty = 'template'; + replacementProperty = 'layout'; + + props.layout = props.template; + delete props['template']; + } + + if (deprecatedProperty) { + } + } + }); + }); +define("ember-views/mixins/view_target_action_support", + ["ember-metal/mixin","ember-runtime/mixins/target_action_support","ember-metal/computed","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Mixin = __dependency1__.Mixin; + var TargetActionSupport = __dependency2__["default"]; + + // ES6TODO: computed should have its own export path so you can do import {defaultTo} from computed + var computed = __dependency3__.computed; + var alias = computed.alias; + + /** + `Ember.ViewTargetActionSupport` is a mixin that can be included in a + view class to add a `triggerAction` method with semantics similar to + the Handlebars `{{action}}` helper. It provides intelligent defaults + for the action's target: the view's controller; and the context that is + sent with the action: the view's context. + + Note: In normal Ember usage, the `{{action}}` helper is usually the best + choice. This mixin is most often useful when you are doing more complex + event handling in custom View subclasses. + + For example: + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { + action: 'save', + click: function() { + this.triggerAction(); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + The `action` can be provided as properties of an optional object argument + to `triggerAction` as well. + + ```javascript + App.SaveButtonView = Ember.View.extend(Ember.ViewTargetActionSupport, { + click: function() { + this.triggerAction({ + action: 'save' + }); // Sends the `save` action, along with the current context + // to the current controller + } + }); + ``` + + @class ViewTargetActionSupport + @namespace Ember + @extends Ember.TargetActionSupport + */ + __exports__["default"] = Mixin.create(TargetActionSupport, { + /** + @property target + */ + target: alias('controller'), + /** + @property actionContext + */ + actionContext: alias('context') + }); + }); +define("ember-views/system/action_manager", + ["exports"], + function(__exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + function ActionManager() {} + + /** + Global action id hash. + + @private + @property registeredActions + @type Object + */ + ActionManager.registeredActions = {}; + + __exports__["default"] = ActionManager; + }); +define("ember-views/system/event_dispatcher", + ["ember-metal/core","ember-metal/property_get","ember-metal/property_set","ember-metal/is_none","ember-metal/run_loop","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/object","ember-views/system/jquery","ember-views/system/action_manager","ember-views/views/view","ember-metal/merge","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + var Ember = __dependency1__["default"]; + // Ember.assert + + var get = __dependency2__.get; + var set = __dependency3__.set; + var isNone = __dependency4__.isNone; + var run = __dependency5__["default"]; + var typeOf = __dependency6__.typeOf; + var fmt = __dependency7__.fmt; + var EmberObject = __dependency8__["default"]; + var jQuery = __dependency9__["default"]; + var ActionManager = __dependency10__["default"]; + var View = __dependency11__["default"]; + var merge = __dependency12__["default"]; + + //ES6TODO: + // find a better way to do Ember.View.views without global state + + /** + `Ember.EventDispatcher` handles delegating browser events to their + corresponding `Ember.Views.` For example, when you click on a view, + `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets + called. + + @class EventDispatcher + @namespace Ember + @private + @extends Ember.Object + */ + __exports__["default"] = EmberObject.extend({ + + /** + The set of events names (and associated handler function names) to be setup + and dispatched by the `EventDispatcher`. Custom events can added to this list at setup + time, generally via the `Ember.Application.customEvents` hash. Only override this + default set to prevent the EventDispatcher from listening on some events all together. + + This set will be modified by `setup` to also include any events added at that time. + + @property events + @type Object + */ + events: { + touchstart : 'touchStart', + touchmove : 'touchMove', + touchend : 'touchEnd', + touchcancel : 'touchCancel', + keydown : 'keyDown', + keyup : 'keyUp', + keypress : 'keyPress', + mousedown : 'mouseDown', + mouseup : 'mouseUp', + contextmenu : 'contextMenu', + click : 'click', + dblclick : 'doubleClick', + mousemove : 'mouseMove', + focusin : 'focusIn', + focusout : 'focusOut', + mouseenter : 'mouseEnter', + mouseleave : 'mouseLeave', + submit : 'submit', + input : 'input', + change : 'change', + dragstart : 'dragStart', + drag : 'drag', + dragenter : 'dragEnter', + dragleave : 'dragLeave', + dragover : 'dragOver', + drop : 'drop', + dragend : 'dragEnd' + }, + + /** + The root DOM element to which event listeners should be attached. Event + listeners will be attached to the document unless this is overridden. + + Can be specified as a DOMElement or a selector string. + + The default body is a string since this may be evaluated before document.body + exists in the DOM. + + @private + @property rootElement + @type DOMElement + @default 'body' + */ + rootElement: 'body', + + /** + It enables events to be dispatched to the view's `eventManager.` When present, + this object takes precedence over handling of events on the view itself. + + Note that most Ember applications do not use this feature. If your app also + does not use it, consider setting this property to false to gain some performance + improvement by allowing the EventDispatcher to skip the search for the + `eventManager` on the view tree. + + ```javascript + var EventDispatcher = Em.EventDispatcher.extend({ + events: { + click : 'click', + focusin : 'focusIn', + focusout : 'focusOut', + change : 'change' + }, + canDispatchToEventManager: false + }); + container.register('event_dispatcher:main', EventDispatcher); + ``` + + @property canDispatchToEventManager + @type boolean + @default 'true' + @since 1.7.0 + */ + canDispatchToEventManager: true, + + /** + Sets up event listeners for standard browser events. + + This will be called after the browser sends a `DOMContentReady` event. By + default, it will set up all of the listeners on the document body. If you + would like to register the listeners on a different element, set the event + dispatcher's `root` property. + + @private + @method setup + @param addedEvents {Hash} + */ + setup: function(addedEvents, rootElement) { + var event, events = get(this, 'events'); + + merge(events, addedEvents || {}); + + if (!isNone(rootElement)) { + set(this, 'rootElement', rootElement); + } + + rootElement = jQuery(get(this, 'rootElement')); + + + rootElement.addClass('ember-application'); + + + for (event in events) { + if (events.hasOwnProperty(event)) { + this.setupHandler(rootElement, event, events[event]); + } + } + }, + + /** + Registers an event listener on the rootElement. If the given event is + triggered, the provided event handler will be triggered on the target view. + + If the target view does not implement the event handler, or if the handler + returns `false`, the parent view will be called. The event will continue to + bubble to each successive parent view until it reaches the top. + + @private + @method setupHandler + @param {Element} rootElement + @param {String} event the browser-originated event to listen to + @param {String} eventName the name of the method to call on the view + */ + setupHandler: function(rootElement, event, eventName) { + var self = this; + + rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) { + var view = View.views[this.id]; + var result = true; + + var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null; + + if (manager && manager !== triggeringManager) { + result = self._dispatchEvent(manager, evt, eventName, view); + } else if (view) { + result = self._bubbleEvent(view, evt, eventName); + } + + return result; + }); + + rootElement.on(event + '.ember', '[data-ember-action]', function(evt) { + var actionId = jQuery(evt.currentTarget).attr('data-ember-action'); + var action = ActionManager.registeredActions[actionId]; + + // We have to check for action here since in some cases, jQuery will trigger + // an event on `removeChild` (i.e. focusout) after we've already torn down the + // action handlers for the view. + if (action && action.eventName === eventName) { + return action.handler(evt); + } + }); + }, + + _findNearestEventManager: function(view, eventName) { + var manager = null; + + while (view) { + manager = get(view, 'eventManager'); + if (manager && manager[eventName]) { break; } + + view = get(view, 'parentView'); + } + + return manager; + }, + + _dispatchEvent: function(object, evt, eventName, view) { + var result = true; + + var handler = object[eventName]; + if (typeOf(handler) === 'function') { + result = run(object, handler, evt, view); + // Do not preventDefault in eventManagers. + evt.stopPropagation(); + } + else { + result = this._bubbleEvent(view, evt, eventName); + } + + return result; + }, + + _bubbleEvent: function(view, evt, eventName) { + return run(view, view.handleEvent, eventName, evt); + }, + + destroy: function() { + var rootElement = get(this, 'rootElement'); + jQuery(rootElement).off('.ember', '**').removeClass('ember-application'); + return this._super(); + }, + + toString: function() { + return '(EventDispatcher)'; + } + }); + }); +define("ember-views/system/ext", + ["ember-metal/run_loop"], + function(__dependency1__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + var run = __dependency1__["default"]; + + // Add a new named queue for rendering views that happens + // after bindings have synced, and a queue for scheduling actions + // that that should occur after view rendering. + var queues = run.queues; + run._addQueue('render', 'actions'); + run._addQueue('afterRender', 'render'); + }); +define("ember-views/system/jquery", + ["ember-metal/core","ember-runtime/system/string","ember-metal/enumerable_utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + var w = __dependency2__.w; + + // ES6TODO: the functions on EnumerableUtils need their own exports + var forEach = __dependency3__.forEach; + + /** + Ember Views + + @module ember + @submodule ember-views + @requires ember-runtime + @main ember-views + */ + + var jQuery = (Ember.imports && Ember.imports.jQuery) || (this && this.jQuery); + if (!jQuery && typeof require === 'function') { + jQuery = require('jquery'); + } + + + /** + @module ember + @submodule ember-views + */ + if (jQuery) { + // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents + var dragEvents = w('dragstart drag dragenter dragleave dragover drop dragend'); + + // Copies the `dataTransfer` property from a browser event object onto the + // jQuery event object for the specified events + forEach(dragEvents, function(eventName) { + jQuery.event.fixHooks[eventName] = { props: ['dataTransfer'] }; + }); + } + + __exports__["default"] = jQuery; + }); +define("ember-views/system/render_buffer", + ["ember-views/system/jquery","morph","ember-metal/core","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-views + */ + + var jQuery = __dependency1__["default"]; + var DOMHelper = __dependency2__.DOMHelper; + var Ember = __dependency3__["default"]; + + // The HTML spec allows for "omitted start tags". These tags are optional + // when their intended child is the first thing in the parent tag. For + // example, this is a tbody start tag: + // + // + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
    + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup, but with a special allowance for disregarding + // + ``` + + And associate it by name using a view's `templateName` property: + + ```javascript + AView = Ember.View.extend({ + templateName: 'some-template' + }); + ``` + + If you have nested resources, your Handlebars template will look like this: + + ```html + + ``` + + And `templateName` property: + + ```javascript + AView = Ember.View.extend({ + templateName: 'posts/new' + }); + ``` + + Using a value for `templateName` that does not have a Handlebars template + with a matching `data-template-name` attribute will throw an error. + + For views classes that may have a template later defined (e.g. as the block + portion of a `{{view}}` Handlebars helper call in another template or in + a subclass), you can provide a `defaultTemplate` property set to compiled + template function. If a template is not later provided for the view instance + the `defaultTemplate` value will be used: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default'), + template: null, + templateName: null + }); + ``` + + Will result in instances with an HTML representation of: + + ```html +
    I was the default
    + ``` + + If a `template` or `templateName` is provided it will take precedence over + `defaultTemplate`: + + ```javascript + AView = Ember.View.extend({ + defaultTemplate: Ember.Handlebars.compile('I was the default') + }); + + aView = AView.create({ + template: Ember.Handlebars.compile('I was the template, not default') + }); + ``` + + Will result in the following HTML representation when rendered: + + ```html +
    I was the template, not default
    + ``` + + ## View Context + + The default context of the compiled template is the view's controller: + + ```javascript + AView = Ember.View.extend({ + template: Ember.Handlebars.compile('Hello {{excitedGreeting}}') + }); + + aController = Ember.Object.create({ + firstName: 'Barry', + excitedGreeting: function() { + return this.get("content.firstName") + "!!!" + }.property() + }); + + aView = AView.create({ + controller: aController + }); + ``` + + Will result in an HTML representation of: + + ```html +
    Hello Barry!!!
    + ``` + + A context can also be explicitly supplied through the view's `context` + property. If the view has neither `context` nor `controller` properties, the + `parentView`'s context will be used. + + ## Layouts + + Views can have a secondary template that wraps their main template. Like + primary templates, layouts can be any function that accepts an optional + context parameter and returns a string of HTML that will be inserted inside + view's tag. Views whose HTML element is self closing (e.g. ``) + cannot have a layout and this property will be ignored. + + Most typically in Ember a layout will be a compiled `Ember.Handlebars` + template. + + A view's layout can be set directly with the `layout` property or reference + an existing Handlebars template by name with the `layoutName` property. + + A template used as a layout must contain a single use of the Handlebars + `{{yield}}` helper. The HTML contents of a view's rendered `template` will be + inserted at this location: + + ```javascript + AViewWithLayout = Ember.View.extend({ + layout: Ember.Handlebars.compile("
    {{yield}}
    "), + template: Ember.Handlebars.compile("I got wrapped") + }); + ``` + + Will result in view instances with an HTML representation of: + + ```html +
    +
    + I got wrapped +
    +
    + ``` + + See [Ember.Handlebars.helpers.yield](/api/classes/Ember.Handlebars.helpers.html#method_yield) + for more information. + + ## Responding to Browser Events + + Views can respond to user-initiated events in one of three ways: method + implementation, through an event manager, and through `{{action}}` helper use + in their template or layout. + + ### Method Implementation + + Views can respond to user-initiated events by implementing a method that + matches the event name. A `jQuery.Event` object will be passed as the + argument to this method. + + ```javascript + AView = Ember.View.extend({ + click: function(event) { + // will be called when when an instance's + // rendered element is clicked + } + }); + ``` + + ### Event Managers + + Views can define an object as their `eventManager` property. This object can + then implement methods that match the desired event names. Matching events + that occur on the view's rendered HTML or the rendered HTML of any of its DOM + descendants will trigger this method. A `jQuery.Event` object will be passed + as the first argument to the method and an `Ember.View` object as the + second. The `Ember.View` will be the view whose rendered HTML was interacted + with. This may be the view with the `eventManager` property or one of its + descendent views. + + ```javascript + AView = Ember.View.extend({ + eventManager: Ember.Object.create({ + doubleClick: function(event, view) { + // will be called when when an instance's + // rendered element or any rendering + // of this views's descendent + // elements is clicked + } + }) + }); + ``` + + An event defined for an event manager takes precedence over events of the + same name handled through methods on the view. + + ```javascript + AView = Ember.View.extend({ + mouseEnter: function(event) { + // will never trigger. + }, + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // takes precedence over AView#mouseEnter + } + }) + }); + ``` + + Similarly a view's event manager will take precedence for events of any views + rendered as a descendent. A method name that matches an event name will not + be called if the view instance was rendered inside the HTML representation of + a view that has an `eventManager` property defined that handles events of the + name. Events not handled by the event manager will still trigger method calls + on the descendent. + + ```javascript + var App = Ember.Application.create(); + App.OuterView = Ember.View.extend({ + template: Ember.Handlebars.compile("outer {{#view 'inner'}}inner{{/view}} outer"), + eventManager: Ember.Object.create({ + mouseEnter: function(event, view) { + // view might be instance of either + // OuterView or InnerView depending on + // where on the page the user interaction occured + } + }) + }); + + App.InnerView = Ember.View.extend({ + click: function(event) { + // will be called if rendered inside + // an OuterView because OuterView's + // eventManager doesn't handle click events + }, + mouseEnter: function(event) { + // will never be called if rendered inside + // an OuterView. + } + }); + ``` + + ### Handlebars `{{action}}` Helper + + See [Handlebars.helpers.action](/api/classes/Ember.Handlebars.helpers.html#method_action). + + ### Event Names + + All of the event handling approaches described above respond to the same set + of events. The names of the built-in events are listed below. (The hash of + built-in events exists in `Ember.EventDispatcher`.) Additional, custom events + can be registered by using `Ember.Application.customEvents`. + + Touch events: + + * `touchStart` + * `touchMove` + * `touchEnd` + * `touchCancel` + + Keyboard events + + * `keyDown` + * `keyUp` + * `keyPress` + + Mouse events + + * `mouseDown` + * `mouseUp` + * `contextMenu` + * `click` + * `doubleClick` + * `mouseMove` + * `focusIn` + * `focusOut` + * `mouseEnter` + * `mouseLeave` + + Form events: + + * `submit` + * `change` + * `focusIn` + * `focusOut` + * `input` + + HTML5 drag and drop events: + + * `dragStart` + * `drag` + * `dragEnter` + * `dragLeave` + * `dragOver` + * `dragEnd` + * `drop` + + ## Handlebars `{{view}}` Helper + + Other `Ember.View` instances can be included as part of a view's template by + using the `{{view}}` Handlebars helper. See [Ember.Handlebars.helpers.view](/api/classes/Ember.Handlebars.helpers.html#method_view) + for additional information. + + @class View + @namespace Ember + @extends Ember.CoreView + */ + var View = CoreView.extend({ + + concatenatedProperties: ['classNames', 'classNameBindings', 'attributeBindings'], + + /** + @property isView + @type Boolean + @default true + @static + */ + isView: true, + + // .......................................................... + // TEMPLATE SUPPORT + // + + /** + The name of the template to lookup if no template is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property templateName + @type String + @default null + */ + templateName: null, + + /** + The name of the layout to lookup if no layout is provided. + + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). + + @property layoutName + @type String + @default null + */ + layoutName: null, + + /** + Used to identify this view during debugging + + @property instrumentDisplay + @type String + */ + instrumentDisplay: computed(function() { + if (this.helperName) { + return '{{' + this.helperName + '}}'; + } + }), + + /** + The template used to render the view. This should be a function that + accepts an optional context parameter and returns a string of HTML that + will be inserted into the DOM relative to its parent view. + + In general, you should set the `templateName` property instead of setting + the template yourself. + + @property template + @type Function + */ + template: computed('templateName', function(key, value) { + if (value !== undefined) { return value; } + + var templateName = get(this, 'templateName'); + var template = this.templateForName(templateName, 'template'); + + + return template || get(this, 'defaultTemplate'); + }), + + /** + The controller managing this view. If this property is set, it will be + made available for use by the template. + + @property controller + @type Object + */ + controller: computed('_parentView', function(key) { + var parentView = get(this, '_parentView'); + return parentView ? get(parentView, 'controller') : null; + }), + + /** + A view may contain a layout. A layout is a regular template but + supersedes the `template` property during rendering. It is the + responsibility of the layout template to retrieve the `template` + property from the view (or alternatively, call `Handlebars.helpers.yield`, + `{{yield}}`) to render it in the correct location. + + This is useful for a view that has a shared wrapper, but which delegates + the rendering of the contents of the wrapper to the `template` property + on a subclass. + + @property layout + @type Function + */ + layout: computed(function(key) { + var layoutName = get(this, 'layoutName'); + var layout = this.templateForName(layoutName, 'layout'); + + + return layout || get(this, 'defaultLayout'); + }).property('layoutName'), + + _yield: function(context, options) { + var template = get(this, 'template'); + if (template) { template(context, options); } + }, + + templateForName: function(name, type) { + if (!name) { return; } + + if (!this.container) { + throw new EmberError('Container was not found when looking up a views template. ' + + 'This is most likely due to manually instantiating an Ember.View. ' + + 'See: http://git.io/EKPpnA'); + } + + return this.container.lookup('template:' + name); + }, + + /** + The object from which templates should access properties. + + This object will be passed to the template function each time the render + method is called, but it is up to the individual function to decide what + to do with it. + + By default, this will be the view's controller. + + @property context + @type Object + */ + context: computed(function(key, value) { + if (arguments.length === 2) { + set(this, '_context', value); + return value; + } else { + return get(this, '_context'); + } + })["volatile"](), + + /** + Private copy of the view's template context. This can be set directly + by Handlebars without triggering the observer that causes the view + to be re-rendered. + + The context of a view is looked up as follows: + + 1. Supplied context (usually by Handlebars) + 2. Specified controller + 3. `parentView`'s context (for a child of a ContainerView) + + The code in Handlebars that overrides the `_context` property first + checks to see whether the view has a specified controller. This is + something of a hack and should be revisited. + + @property _context + @private + */ + _context: computed(function(key) { + var parentView, controller; + + if (controller = get(this, 'controller')) { + return controller; + } + + parentView = this._parentView; + if (parentView) { + return get(parentView, '_context'); + } + + return null; + }), + + /** + If a value that affects template rendering changes, the view should be + re-rendered to reflect the new value. + + @method _contextDidChange + @private + */ + _contextDidChange: observer('context', function() { + this.rerender(); + }), + + /** + If `false`, the view will appear hidden in DOM. + + @property isVisible + @type Boolean + @default null + */ + isVisible: true, + + /** + Array of child views. You should never edit this array directly. + Instead, use `appendChild` and `removeFromParent`. + + @property childViews + @type Array + @default [] + @private + */ + childViews: childViewsProperty, + + _childViews: EMPTY_ARRAY, + + // When it's a virtual view, we need to notify the parent that their + // childViews will change. + _childViewsWillChange: beforeObserver('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { propertyWillChange(parentView, 'childViews'); } + } + }), + + // When it's a virtual view, we need to notify the parent that their + // childViews did change. + _childViewsDidChange: observer('childViews', function() { + if (this.isVirtual) { + var parentView = get(this, 'parentView'); + if (parentView) { propertyDidChange(parentView, 'childViews'); } + } + }), + + /** + Return the nearest ancestor that is an instance of the provided + class. + + @method nearestInstanceOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + @deprecated + */ + nearestInstanceOf: function(klass) { + var view = get(this, 'parentView'); + + while (view) { + if (view instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that is an instance of the provided + class or mixin. + + @method nearestOfType + @param {Class,Mixin} klass Subclass of Ember.View (or Ember.View itself), + or an instance of Ember.Mixin. + @return Ember.View + */ + nearestOfType: function(klass) { + var view = get(this, 'parentView'); + var isOfType = klass instanceof Mixin ? + function(view) { return klass.detect(view); } : + function(view) { return klass.detect(view.constructor); }; + + while (view) { + if (isOfType(view)) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor that has a given property. + + @method nearestWithProperty + @param {String} property A property name + @return Ember.View + */ + nearestWithProperty: function(property) { + var view = get(this, 'parentView'); + + while (view) { + if (property in view) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + Return the nearest ancestor whose parent is an instance of + `klass`. + + @method nearestChildOf + @param {Class} klass Subclass of Ember.View (or Ember.View itself) + @return Ember.View + */ + nearestChildOf: function(klass) { + var view = get(this, 'parentView'); + + while (view) { + if (get(view, 'parentView') instanceof klass) { return view; } + view = get(view, 'parentView'); + } + }, + + /** + When the parent view changes, recursively invalidate `controller` + + @method _parentViewDidChange + @private + */ + _parentViewDidChange: observer('_parentView', function() { + if (this.isDestroying) { return; } + + this.trigger('parentViewDidChange'); + + if (get(this, 'parentView.controller') && !get(this, 'controller')) { + this.notifyPropertyChange('controller'); + } + }), + + _controllerDidChange: observer('controller', function() { + if (this.isDestroying) { return; } + + this.rerender(); + + this.forEachChildView(function(view) { + view.propertyDidChange('controller'); + }); + }), + + cloneKeywords: function() { + var templateData = get(this, 'templateData'); + + var keywords = templateData ? copy(templateData.keywords) : {}; + set(keywords, 'view', this.isVirtual ? keywords.view : this); + set(keywords, '_view', this); + set(keywords, 'controller', get(this, 'controller')); + + return keywords; + }, + + /** + Called on your view when it should push strings of HTML into a + `Ember.RenderBuffer`. Most users will want to override the `template` + or `templateName` properties instead of this method. + + By default, `Ember.View` will look for a function in the `template` + property and invoke it with the value of `context`. The value of + `context` will be the view's controller unless you override it. + + @method render + @param {Ember.RenderBuffer} buffer The render buffer + */ + render: function(buffer) { + // If this view has a layout, it is the responsibility of the + // the layout to render the view's template. Otherwise, render the template + // directly. + var template = get(this, 'layout') || get(this, 'template'); + + if (template) { + var context = get(this, 'context'); + var keywords = this.cloneKeywords(); + var output; + + var data = { + view: this, + buffer: buffer, + isRenderData: true, + keywords: keywords, + insideGroup: get(this, 'templateData.insideGroup') + }; + + // Invoke the template with the provided template context, which + // is the view's controller by default. A hash of data is also passed that provides + // the template with access to the view and render buffer. + + // The template should write directly to the render buffer instead + // of returning a string. + output = template(context, { data: data }); + + // If the template returned a string instead of writing to the buffer, + // push the string onto the buffer. + if (output !== undefined) { buffer.push(output); } + } + }, + + /** + Renders the view again. This will work regardless of whether the + view is already in the DOM or not. If the view is in the DOM, the + rendering process will be deferred to give bindings a chance + to synchronize. + + If children were added during the rendering process using `appendChild`, + `rerender` will remove them, because they will be added again + if needed by the next `render`. + + In general, if the display of your view changes, you should modify + the DOM element directly instead of manually calling `rerender`, which can + be slow. + + @method rerender + */ + rerender: function() { + return this.currentState.rerender(this); + }, + + /** + Iterates over the view's `classNameBindings` array, inserts the value + of the specified property into the `classNames` array, then creates an + observer to update the view's element if the bound property ever changes + in the future. + + @method _applyClassNameBindings + @private + */ + _applyClassNameBindings: function(classBindings) { + var classNames = this.classNames; + var elem, newClass, dasherizedClass; + + // Loop through all of the configured bindings. These will be either + // property names ('isUrgent') or property paths relative to the view + // ('content.isUrgent') + forEach(classBindings, function(binding) { + + + // Variable in which the old class value is saved. The observer function + // closes over this variable, so it knows which string to remove when + // the property changes. + var oldClass; + // Extract just the property name from bindings like 'foo:bar' + var parsedPath = View._parsePropertyPath(binding); + + // Set up an observer on the context. If the property changes, toggle the + // class name. + var observer = function() { + // Get the current value of the property + newClass = this._classStringForProperty(binding); + elem = this.$(); + + // If we had previously added a class to the element, remove it. + if (oldClass) { + elem.removeClass(oldClass); + // Also remove from classNames so that if the view gets rerendered, + // the class doesn't get added back to the DOM. + classNames.removeObject(oldClass); + } + + // If necessary, add a new class. Make sure we keep track of it so + // it can be removed in the future. + if (newClass) { + elem.addClass(newClass); + oldClass = newClass; + } else { + oldClass = null; + } + }; + + // Get the class name for the property at its current value + dasherizedClass = this._classStringForProperty(binding); + + if (dasherizedClass) { + // Ensure that it gets into the classNames array + // so it is displayed when we render. + addObject(classNames, dasherizedClass); + + // Save a reference to the class name so we can remove it + // if the observer fires. Remember that this variable has + // been closed over by the observer. + oldClass = dasherizedClass; + } + + this.registerObserver(this, parsedPath.path, observer); + // Remove className so when the view is rerendered, + // the className is added based on binding reevaluation + this.one('willClearRender', function() { + if (oldClass) { + classNames.removeObject(oldClass); + oldClass = null; + } + }); + + }, this); + }, + + _unspecifiedAttributeBindings: null, + + /** + Iterates through the view's attribute bindings, sets up observers for each, + then applies the current value of the attributes to the passed render buffer. + + @method _applyAttributeBindings + @param {Ember.RenderBuffer} buffer + @private + */ + _applyAttributeBindings: function(buffer, attributeBindings) { + var attributeValue; + var unspecifiedAttributeBindings = this._unspecifiedAttributeBindings = this._unspecifiedAttributeBindings || {}; + + forEach(attributeBindings, function(binding) { + var split = binding.split(':'); + var property = split[0]; + var attributeName = split[1] || property; + + if (property in this) { + this._setupAttributeBindingObservation(property, attributeName); + + // Determine the current value and add it to the render buffer + // if necessary. + attributeValue = get(this, property); + View.applyAttributeBindings(buffer, attributeName, attributeValue); + } else { + unspecifiedAttributeBindings[property] = attributeName; + } + }, this); + + // Lazily setup setUnknownProperty after attributeBindings are initially applied + this.setUnknownProperty = this._setUnknownProperty; + }, + + _setupAttributeBindingObservation: function(property, attributeName) { + var attributeValue, elem; + + // Create an observer to add/remove/change the attribute if the + // JavaScript property changes. + var observer = function() { + elem = this.$(); + + attributeValue = get(this, property); + + View.applyAttributeBindings(elem, attributeName, attributeValue); + }; + + this.registerObserver(this, property, observer); + }, + + /** + We're using setUnknownProperty as a hook to setup attributeBinding observers for + properties that aren't defined on a view at initialization time. + + Note: setUnknownProperty will only be called once for each property. + + @method setUnknownProperty + @param key + @param value + @private + */ + setUnknownProperty: null, // Gets defined after initialization by _applyAttributeBindings + + _setUnknownProperty: function(key, value) { + var attributeName = this._unspecifiedAttributeBindings && this._unspecifiedAttributeBindings[key]; + if (attributeName) { + this._setupAttributeBindingObservation(key, attributeName); + } + + defineProperty(this, key); + return set(this, key, value); + }, + + /** + Given a property name, returns a dasherized version of that + property name if the property evaluates to a non-falsy value. + + For example, if the view has property `isUrgent` that evaluates to true, + passing `isUrgent` to this method will return `"is-urgent"`. + + @method _classStringForProperty + @param property + @private + */ + _classStringForProperty: function(property) { + var parsedPath = View._parsePropertyPath(property); + var path = parsedPath.path; + + var val = get(this, path); + if (val === undefined && isGlobalPath(path)) { + val = get(Ember.lookup, path); + } + + return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName); + }, + + // .......................................................... + // ELEMENT SUPPORT + // + + /** + Returns the current DOM element for the view. + + @property element + @type DOMElement + */ + element: null, + + /** + Returns a jQuery object for this view's element. If you pass in a selector + string, this method will return a jQuery object, using the current element + as its buffer. + + For example, calling `view.$('li')` will return a jQuery object containing + all of the `li` elements inside the DOM element of this view. + + @method $ + @param {String} [selector] a jQuery-compatible selector string + @return {jQuery} the jQuery object for the DOM node + */ + $: function(sel) { + return this.currentState.$(this, sel); + }, + + mutateChildViews: function(callback) { + var childViews = this._childViews; + var idx = childViews.length; + var view; + + while(--idx >= 0) { + view = childViews[idx]; + callback(this, view, idx); + } + + return this; + }, + + forEachChildView: function(callback) { + var childViews = this._childViews; + + if (!childViews) { return this; } + + var len = childViews.length; + var view, idx; + + for (idx = 0; idx < len; idx++) { + view = childViews[idx]; + callback(view); + } + + return this; + }, + + /** + Appends the view's element to the specified parent element. + + If the view does not have an HTML representation yet, `createElement()` + will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing. + + This is not typically a function that you will need to call directly when + building your application. You might consider using `Ember.ContainerView` + instead. If you do need to use `appendTo`, be sure that the target element + you are providing is associated with an `Ember.Application` and does not + have an ancestor element that is associated with an Ember view. + + @method appendTo + @param {String|DOMElement|jQuery} A selector, element, HTML string, or jQuery object + @return {Ember.View} receiver + */ + appendTo: function(selector) { + var target = jQuery(selector); + + + this.constructor.renderer.appendTo(this, target[0]); + + return this; + }, + + /** + Replaces the content of the specified parent element with this view's + element. If the view does not have an HTML representation yet, + `createElement()` will be called automatically. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the given element until all bindings have + finished synchronizing + + @method replaceIn + @param {String|DOMElement|jQuery} target A selector, element, HTML string, or jQuery object + @return {Ember.View} received + */ + replaceIn: function(selector) { + var target = jQuery(selector); + + + this.constructor.renderer.replaceIn(this, target[0]); + + return this; + }, + + /** + Appends the view's element to the document body. If the view does + not have an HTML representation yet, `createElement()` will be called + automatically. + + If your application uses the `rootElement` property, you must append + the view within that element. Rendering views outside of the `rootElement` + is not supported. + + Note that this method just schedules the view to be appended; the DOM + element will not be appended to the document body until all bindings have + finished synchronizing. + + @method append + @return {Ember.View} receiver + */ + append: function() { + return this.appendTo(document.body); + }, + + /** + Removes the view's element from the element to which it is attached. + + @method remove + @return {Ember.View} receiver + */ + remove: function() { + // What we should really do here is wait until the end of the run loop + // to determine if the element has been re-appended to a different + // element. + // In the interim, we will just re-render if that happens. It is more + // important than elements get garbage collected. + if (!this.removedFromDOM) { this.destroyElement(); } + }, + + elementId: null, + + /** + Attempts to discover the element in the parent element. The default + implementation looks for an element with an ID of `elementId` (or the + view's guid if `elementId` is null). You can override this method to + provide your own form of lookup. For example, if you want to discover your + element using a CSS class name instead of an ID. + + @method findElementInParentElement + @param {DOMElement} parentElement The parent's DOM element + @return {DOMElement} The discovered element + */ + findElementInParentElement: function(parentElem) { + var id = "#" + this.elementId; + return jQuery(id)[0] || jQuery(id, parentElem)[0]; + }, + + /** + Creates a DOM representation of the view and all of its child views by + recursively calling the `render()` method. + + After the element has been inserted into the DOM, `didInsertElement` will + be called on this view and all of its child views. + + @method createElement + @return {Ember.View} receiver + */ + createElement: function() { + if (this.element) { return this; } + + this._didCreateElementWithoutMorph = true; + this.constructor.renderer.renderTree(this); + + return this; + }, + + /** + Called when a view is going to insert an element into the DOM. + + @event willInsertElement + */ + willInsertElement: Ember.K, + + /** + Called when the element of the view has been inserted into the DOM + or after the view was re-rendered. Override this function to do any + set up that requires an element in the document body. + + When a view has children, didInsertElement will be called on the + child view(s) first, bubbling upwards through the hierarchy. + + @event didInsertElement + */ + didInsertElement: Ember.K, + + /** + Called when the view is about to rerender, but before anything has + been torn down. This is a good opportunity to tear down any manual + observers you have installed based on the DOM state + + @event willClearRender + */ + willClearRender: Ember.K, + + /** + Destroys any existing element along with the element for any child views + as well. If the view does not currently have a element, then this method + will do nothing. + + If you implement `willDestroyElement()` on your view, then this method will + be invoked on your view before your element is destroyed to give you a + chance to clean up any event handlers, etc. + + If you write a `willDestroyElement()` handler, you can assume that your + `didInsertElement()` handler was called earlier for the same element. + + You should not call or override this method yourself, but you may + want to implement the above callbacks. + + @method destroyElement + @return {Ember.View} receiver + */ + destroyElement: function() { + return this.currentState.destroyElement(this); + }, + + /** + Called when the element of the view is going to be destroyed. Override + this function to do any teardown that requires an element, like removing + event listeners. + + Please note: any property changes made during this event will have no + effect on object observers. + + @event willDestroyElement + */ + willDestroyElement: Ember.K, + + /** + Called when the parentView property has changed. + + @event parentViewDidChange + */ + parentViewDidChange: Ember.K, + + instrumentName: 'view', + + instrumentDetails: function(hash) { + hash.template = get(this, 'templateName'); + this._super(hash); + }, + + beforeRender: function(buffer) {}, + + afterRender: function(buffer) {}, + + applyAttributesToBuffer: function(buffer) { + // Creates observers for all registered class name and attribute bindings, + // then adds them to the element. + var classNameBindings = get(this, 'classNameBindings'); + if (classNameBindings.length) { + this._applyClassNameBindings(classNameBindings); + } + + // Pass the render buffer so the method can apply attributes directly. + // This isn't needed for class name bindings because they use the + // existing classNames infrastructure. + var attributeBindings = get(this, 'attributeBindings'); + if (attributeBindings.length) { + this._applyAttributeBindings(buffer, attributeBindings); + } + + buffer.setClasses(this.classNames); + buffer.id(this.elementId); + + var role = get(this, 'ariaRole'); + if (role) { + buffer.attr('role', role); + } + + if (get(this, 'isVisible') === false) { + buffer.style('display', 'none'); + } + }, + + // .......................................................... + // STANDARD RENDER PROPERTIES + // + + /** + Tag name for the view's outer element. The tag name is only used when an + element is first created. If you change the `tagName` for an element, you + must destroy and recreate the view element. + + By default, the render buffer will use a `
    ` tag for views. + + @property tagName + @type String + @default null + */ + + // We leave this null by default so we can tell the difference between + // the default case and a user-specified tag. + tagName: null, + + /** + The WAI-ARIA role of the control represented by this view. For example, a + button may have a role of type 'button', or a pane may have a role of + type 'alertdialog'. This property is used by assistive software to help + visually challenged users navigate rich web applications. + + The full list of valid WAI-ARIA roles is available at: + [http://www.w3.org/TR/wai-aria/roles#roles_categorization](http://www.w3.org/TR/wai-aria/roles#roles_categorization) + + @property ariaRole + @type String + @default null + */ + ariaRole: null, + + /** + Standard CSS class names to apply to the view's outer element. This + property automatically inherits any class names defined by the view's + superclasses as well. + + @property classNames + @type Array + @default ['ember-view'] + */ + classNames: ['ember-view'], + + /** + A list of properties of the view to apply as class names. If the property + is a string value, the value of that string will be applied as a class + name. + + ```javascript + // Applies the 'high' class to the view element + Ember.View.extend({ + classNameBindings: ['priority'] + priority: 'high' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as a dasherized class name. + + ```javascript + // Applies the 'is-urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent'] + isUrgent: true + }); + ``` + + If you would prefer to use a custom value instead of the dasherized + property name, you can pass a binding like this: + + ```javascript + // Applies the 'urgent' class to the view element + Ember.View.extend({ + classNameBindings: ['isUrgent:urgent'] + isUrgent: true + }); + ``` + + This list of properties is inherited from the view's superclasses as well. + + @property classNameBindings + @type Array + @default [] + */ + classNameBindings: EMPTY_ARRAY, + + /** + A list of properties of the view to apply as attributes. If the property is + a string value, the value of that string will be applied as the attribute. + + ```javascript + // Applies the type attribute to the element + // with the value "button", like
    + Ember.View.extend({ + attributeBindings: ['type'], + type: 'button' + }); + ``` + + If the value of the property is a Boolean, the name of that property is + added as an attribute. + + ```javascript + // Renders something like
    + Ember.View.extend({ + attributeBindings: ['enabled'], + enabled: true + }); + ``` + + @property attributeBindings + */ + attributeBindings: EMPTY_ARRAY, + + // ....................................................... + // CORE DISPLAY METHODS + // + + /** + Setup a view, but do not finish waking it up. + + * configure `childViews` + * register the view with the global views hash, which is used for event + dispatch + + @method init + @private + */ + init: function() { + if (!this.isVirtual && !this.elementId) { + this.elementId = guidFor(this); + } + + this._super(); + + // setup child views. be sure to clone the child views array first + this._childViews = this._childViews.slice(); + + this.classNameBindings = emberA(this.classNameBindings.slice()); + + this.classNames = emberA(this.classNames.slice()); + }, + + appendChild: function(view, options) { + return this.currentState.appendChild(this, view, options); + }, + + /** + Removes the child view from the parent view. + + @method removeChild + @param {Ember.View} view + @return {Ember.View} receiver + */ + removeChild: function(view) { + // If we're destroying, the entire subtree will be + // freed, and the DOM will be handled separately, + // so no need to mess with childViews. + if (this.isDestroying) { return; } + + // update parent node + set(view, '_parentView', null); + + // remove view from childViews array. + var childViews = this._childViews; + + removeObject(childViews, view); + + this.propertyDidChange('childViews'); // HUH?! what happened to will change? + + return this; + }, + + /** + Removes all children from the `parentView`. + + @method removeAllChildren + @return {Ember.View} receiver + */ + removeAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + parentView.removeChild(view); + }); + }, + + destroyAllChildren: function() { + return this.mutateChildViews(function(parentView, view) { + view.destroy(); + }); + }, + + /** + Removes the view from its `parentView`, if one is found. Otherwise + does nothing. + + @method removeFromParent + @return {Ember.View} receiver + */ + removeFromParent: function() { + var parent = this._parentView; + + // Remove DOM element from parent + this.remove(); + + if (parent) { parent.removeChild(this); } + return this; + }, + + /** + You must call `destroy` on a view to destroy the view (and all of its + child views). This will remove the view from any parent node, then make + sure that the DOM element managed by the view can be released by the + memory manager. + + @method destroy + */ + destroy: function() { + var childViews = this._childViews; + // get parentView before calling super because it'll be destroyed + var nonVirtualParentView = get(this, 'parentView'); + var viewName = this.viewName; + var childLen, i; + + if (!this._super()) { return; } + + // remove from non-virtual parent view if viewName was specified + if (viewName && nonVirtualParentView) { + nonVirtualParentView.set(viewName, null); + } + + return this; + }, + + /** + Instantiates a view to be added to the childViews array during view + initialization. You generally will not call this method directly unless + you are overriding `createChildViews()`. Note that this method will + automatically configure the correct settings on the new view instance to + act as a child of the parent. + + @method createChildView + @param {Class|String} viewClass + @param {Hash} [attrs] Attributes to add + @return {Ember.View} new instance + */ + createChildView: function(view, attrs) { + if (!view) { + throw new TypeError("createChildViews first argument must exist"); + } + + if (view.isView && view._parentView === this && view.container === this.container) { + return view; + } + + attrs = attrs || {}; + attrs._parentView = this; + + if (CoreView.detect(view)) { + attrs.templateData = attrs.templateData || get(this, 'templateData'); + + attrs.container = this.container; + view = view.create(attrs); + + // don't set the property on a virtual view, as they are invisible to + // consumers of the view API + if (view.viewName) { + set(get(this, 'concreteView'), view.viewName, view); + } + } else if ('string' === typeof view) { + var fullName = 'view:' + view; + var ViewKlass = this.container.lookupFactory(fullName); + + + attrs.templateData = get(this, 'templateData'); + view = ViewKlass.create(attrs); + } else { + attrs.container = this.container; + + if (!get(view, 'templateData')) { + attrs.templateData = get(this, 'templateData'); + } + + setProperties(view, attrs); + + } + + return view; + }, + + becameVisible: Ember.K, + becameHidden: Ember.K, + + /** + When the view's `isVisible` property changes, toggle the visibility + element of the actual DOM element. + + @method _isVisibleDidChange + @private + */ + _isVisibleDidChange: observer('isVisible', function() { + if (this._isVisible === get(this, 'isVisible')) { return ; } + run.scheduleOnce('render', this, this._toggleVisibility); + }), + + _toggleVisibility: function() { + var $el = this.$(); + var isVisible = get(this, 'isVisible'); + + if (this._isVisible === isVisible) { return ; } + + // It's important to keep these in sync, even if we don't yet have + // an element in the DOM to manipulate: + this._isVisible = isVisible; + + if (!$el) { return; } + + $el.toggle(isVisible); + + if (this._isAncestorHidden()) { return; } + + if (isVisible) { + this._notifyBecameVisible(); + } else { + this._notifyBecameHidden(); + } + }, + + _notifyBecameVisible: function() { + this.trigger('becameVisible'); + + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameVisible(); + } + }); + }, + + _notifyBecameHidden: function() { + this.trigger('becameHidden'); + this.forEachChildView(function(view) { + var isVisible = get(view, 'isVisible'); + + if (isVisible || isVisible === null) { + view._notifyBecameHidden(); + } + }); + }, + + _isAncestorHidden: function() { + var parent = get(this, 'parentView'); + + while (parent) { + if (get(parent, 'isVisible') === false) { return true; } + + parent = get(parent, 'parentView'); + } + + return false; + }, + transitionTo: function(state, children) { + this._transitionTo(state, children); + }, + _transitionTo: function(state, children) { + var priorState = this.currentState; + var currentState = this.currentState = this._states[state]; + this._state = state; + + if (priorState && priorState.exit) { priorState.exit(this); } + if (currentState.enter) { currentState.enter(this); } + }, + + // ....................................................... + // EVENT HANDLING + // + + /** + Handle events from `Ember.EventDispatcher` + + @method handleEvent + @param eventName {String} + @param evt {Event} + @private + */ + handleEvent: function(eventName, evt) { + return this.currentState.handleEvent(this, eventName, evt); + }, + + registerObserver: function(root, path, target, observer) { + if (!observer && 'function' === typeof target) { + observer = target; + target = null; + } + + if (!root || typeof root !== 'object') { + return; + } + + var view = this; + var stateCheckedObserver = function() { + view.currentState.invokeObserver(this, observer); + }; + var scheduledObserver = function() { + run.scheduleOnce('render', this, stateCheckedObserver); + }; + + addObserver(root, path, target, scheduledObserver); + + this.one('willClearRender', function() { + removeObserver(root, path, target, scheduledObserver); + }); + } + + }); + deprecateProperty(View.prototype, 'state', '_state'); + deprecateProperty(View.prototype, 'states', '_states'); + + /* + Describe how the specified actions should behave in the various + states that a view can exist in. Possible states: + + * preRender: when a view is first instantiated, and after its + element was destroyed, it is in the preRender state + * inBuffer: once a view has been rendered, but before it has + been inserted into the DOM, it is in the inBuffer state + * hasElement: the DOM representation of the view is created, + and is ready to be inserted + * inDOM: once a view has been inserted into the DOM it is in + the inDOM state. A view spends the vast majority of its + existence in this state. + * destroyed: once a view has been destroyed (using the destroy + method), it is in this state. No further actions can be invoked + on a destroyed view. + */ + + // in the destroyed state, everything is illegal + + // before rendering has begun, all legal manipulations are noops. + + // inside the buffer, legal manipulations are done on the buffer + + // once the view has been inserted into the DOM, legal manipulations + // are done on the DOM element. + + function notifyMutationListeners() { + run.once(View, 'notifyMutationListeners'); + } + + View.reopenClass({ + + /** + Parse a path and return an object which holds the parsed properties. + + For example a path like "content.isEnabled:enabled:disabled" will return the + following object: + + ```javascript + { + path: "content.isEnabled", + className: "enabled", + falsyClassName: "disabled", + classNames: ":enabled:disabled" + } + ``` + + @method _parsePropertyPath + @static + @private + */ + _parsePropertyPath: function(path) { + var split = path.split(':'); + var propertyPath = split[0]; + var classNames = ""; + var className, falsyClassName; + + // check if the property is defined as prop:class or prop:trueClass:falseClass + if (split.length > 1) { + className = split[1]; + if (split.length === 3) { falsyClassName = split[2]; } + + classNames = ':' + className; + if (falsyClassName) { classNames += ":" + falsyClassName; } + } + + return { + path: propertyPath, + classNames: classNames, + className: (className === '') ? undefined : className, + falsyClassName: falsyClassName + }; + }, + + /** + Get the class name for a given value, based on the path, optional + `className` and optional `falsyClassName`. + + - if a `className` or `falsyClassName` has been specified: + - if the value is truthy and `className` has been specified, + `className` is returned + - if the value is falsy and `falsyClassName` has been specified, + `falsyClassName` is returned + - otherwise `null` is returned + - if the value is `true`, the dasherized last part of the supplied path + is returned + - if the value is not `false`, `undefined` or `null`, the `value` + is returned + - if none of the above rules apply, `null` is returned + + @method _classStringForValue + @param path + @param val + @param className + @param falsyClassName + @static + @private + */ + _classStringForValue: function(path, val, className, falsyClassName) { + if(isArray(val)) { + val = get(val, 'length') !== 0; + } + + // When using the colon syntax, evaluate the truthiness or falsiness + // of the value to determine which className to return + if (className || falsyClassName) { + if (className && !!val) { + return className; + + } else if (falsyClassName && !val) { + return falsyClassName; + + } else { + return null; + } + + // If value is a Boolean and true, return the dasherized property + // name. + } else if (val === true) { + // Normalize property path to be suitable for use + // as a class name. For exaple, content.foo.barBaz + // becomes bar-baz. + var parts = path.split('.'); + return dasherize(parts[parts.length-1]); + + // If the value is not false, undefined, or null, return the current + // value of the property. + } else if (val !== false && val != null) { + return val; + + // Nothing to display. Return null so that the old class is removed + // but no new class is added. + } else { + return null; + } + } + }); + + var mutation = EmberObject.extend(Evented).create(); + // TODO MOVE TO RENDERER HOOKS + View.addMutationListener = function(callback) { + mutation.on('change', callback); + }; + + View.removeMutationListener = function(callback) { + mutation.off('change', callback); + }; + + View.notifyMutationListeners = function() { + mutation.trigger('change'); + }; + + /** + Global views hash + + @property views + @static + @type Hash + */ + View.views = {}; + + // If someone overrides the child views computed property when + // defining their class, we want to be able to process the user's + // supplied childViews and then restore the original computed property + // at view initialization time. This happens in Ember.ContainerView's init + // method. + View.childViewsProperty = childViewsProperty; + + View.applyAttributeBindings = function(elem, name, value) { + var type = typeOf(value); + + // if this changes, also change the logic in ember-handlebars/lib/helpers/binding.js + if (name !== 'value' && (type === 'string' || (type === 'number' && !isNaN(value)))) { + if (value !== elem.attr(name)) { + elem.attr(name, value); + } + } else if (name === 'value' || type === 'boolean') { + if (isNone(value) || value === false) { + // `null`, `undefined` or `false` should remove attribute + elem.removeAttr(name); + // In IE8 `prop` couldn't remove attribute when name is `required`. + if (name === 'required') { + elem.removeProp(name); + } else { + elem.prop(name, ''); + } + } else if (value !== elem.prop(name)) { + // value should always be properties + elem.prop(name, value); + } + } else if (!value) { + elem.removeAttr(name); + } + }; + + __exports__["default"] = View; + }); +define("ember", + ["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { + "use strict"; + /* global navigator */ + // require the main entry points for each of these packages + // this is so that the global exports occur properly + + // do this to ensure that Ember.Test is defined properly on the global + // if it is present. + if (Ember.__loader.registry['ember-testing']) { + requireModule('ember-testing'); + } + + /** + Ember + + @module ember + */ + + }); +define("morph", + ["./morph/morph","./morph/dom-helper","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Morph = __dependency1__["default"]; + var Morph; + __exports__.Morph = Morph; + var DOMHelper = __dependency2__["default"]; + var DOMHelper; + __exports__.DOMHelper = DOMHelper; + }); +define("morph/dom-helper", + ["../morph/morph","./dom-helper/build-html-dom","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Morph = __dependency1__["default"]; + var buildHTMLDOM = __dependency2__.buildHTMLDOM; + var svgNamespace = __dependency2__.svgNamespace; + var svgHTMLIntegrationPoints = __dependency2__.svgHTMLIntegrationPoints; + + var deletesBlankTextNodes = (function(){ + var element = document.createElement('div'); + element.appendChild( document.createTextNode('') ); + var clonedElement = element.cloneNode(true); + return clonedElement.childNodes.length === 0; + })(); + + var ignoresCheckedAttribute = (function(){ + var element = document.createElement('input'); + element.setAttribute('checked', 'checked'); + var clonedElement = element.cloneNode(false); + return !clonedElement.checked; + })(); + + function isSVG(ns){ + return ns === svgNamespace; + } + + // This is not the namespace of the element, but of + // the elements inside that elements. + function interiorNamespace(element){ + if ( + element && + element.namespaceURI === svgNamespace && + !svgHTMLIntegrationPoints[element.tagName] + ) { + return svgNamespace; + } else { + return null; + } + } + + // The HTML spec allows for "omitted start tags". These tags are optional + // when their intended child is the first thing in the parent tag. For + // example, this is a tbody start tag: + // + //
    + // + // + // + // The tbody may be omitted, and the browser will accept and render: + // + //
    + // + // + // However, the omitted start tag will still be added to the DOM. Here + // we test the string and context to see if the browser is about to + // perform this cleanup. + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags + // describes which tags are omittable. The spec for tbody and colgroup + // explains this behavior: + // + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-tbody-element + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tables.html#the-colgroup-element + // + + var omittedStartTagChildTest = /<([\w:]+)/; + function detectOmittedStartTag(string, contextualElement){ + // Omitted start tags are only inside table tags. + if (contextualElement.tagName === 'TABLE') { + var omittedStartTagChildMatch = omittedStartTagChildTest.exec(string); + if (omittedStartTagChildMatch) { + var omittedStartTagChild = omittedStartTagChildMatch[1]; + // It is already asserted that the contextual element is a table + // and not the proper start tag. Just see if a tag was omitted. + return omittedStartTagChild === 'tr' || + omittedStartTagChild === 'col'; + } + } + } + + function buildSVGDOM(html, dom){ + var div = dom.document.createElement('div'); + div.innerHTML = ''+html+''; + return div.firstChild.childNodes; + } + + /* + * A class wrapping DOM functions to address environment compatibility, + * namespaces, contextual elements for morph un-escaped content + * insertion. + * + * When entering a template, a DOMHelper should be passed: + * + * template(context, { hooks: hooks, dom: new DOMHelper() }); + * + * TODO: support foreignObject as a passed contextual element. It has + * a namespace (svg) that does not match its internal namespace + * (xhtml). + * + * @class DOMHelper + * @constructor + * @param {HTMLDocument} _document The document DOM methods are proxied to + */ + function DOMHelper(_document){ + this.document = _document || window.document; + this.namespace = null; + } + + var prototype = DOMHelper.prototype; + prototype.constructor = DOMHelper; + + prototype.insertBefore = function(element, childElement, referenceChild) { + return element.insertBefore(childElement, referenceChild); + }; + + prototype.appendChild = function(element, childElement) { + return element.appendChild(childElement); + }; + + prototype.appendText = function(element, text) { + return element.appendChild(this.document.createTextNode(text)); + }; + + prototype.setAttribute = function(element, name, value) { + element.setAttribute(name, value); + }; + + if (document.createElementNS) { + // Only opt into namespace detection if a contextualElement + // is passed. + prototype.createElement = function(tagName, contextualElement) { + var namespace = this.namespace; + if (contextualElement) { + if (tagName === 'svg') { + namespace = svgNamespace; + } else { + namespace = interiorNamespace(contextualElement); + } + } + if (namespace) { + return this.document.createElementNS(namespace, tagName); + } else { + return this.document.createElement(tagName); + } + }; + } else { + prototype.createElement = function(tagName) { + return this.document.createElement(tagName); + }; + } + + prototype.setNamespace = function(ns) { + this.namespace = ns; + }; + + prototype.detectNamespace = function(element) { + this.namespace = interiorNamespace(element); + }; + + prototype.createDocumentFragment = function(){ + return this.document.createDocumentFragment(); + }; + + prototype.createTextNode = function(text){ + return this.document.createTextNode(text); + }; + + prototype.repairClonedNode = function(element, blankChildTextNodes, isChecked){ + if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { + for (var i=0, len=blankChildTextNodes.length;i]*)>", 'i'))[0]; + var endTag = ''; + + var wrappedHTML = [startTag, html, endTag]; + + var i = wrappingTags.length; + var wrappedDepth = 1 + i; + while(i--) { + wrappedHTML.unshift('<'+wrappingTags[i]+'>'); + wrappedHTML.push(''); + } + + var wrapper = document.createElement('div'); + scriptSafeInnerHTML(wrapper, wrappedHTML.join('')); + var element = wrapper; + while (wrappedDepth--) { + element = element.firstChild; + while (element && element.nodeType !== 1) { + element = element.nextSibling; + } + } + while (element && element.tagName !== tagName) { + element = element.nextSibling; + } + return element ? element.childNodes : []; + } + + var buildDOM; + if (needsShy) { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + scriptSafeInnerHTML(contextualElement, html); + return contextualElement.childNodes; + }; + } else { + buildDOM = function buildDOM(html, contextualElement, dom){ + contextualElement = dom.cloneNode(contextualElement, false); + contextualElement.innerHTML = html; + return contextualElement.childNodes; + }; + } + + + var buildHTMLDOM; + // Really, this just means IE8 and IE9 get a slower buildHTMLDOM + if (tagNamesRequiringInnerHTMLFix.length > 0 || movesWhitespace) { + buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom) { + // Make a list of the leading text on script nodes. Include + // script tags without any whitespace for easier processing later. + var spacesBefore = []; + var spacesAfter = []; + html = html.replace(/(\s*)()(\s*)/g, function(match, tag, spaces) { + spacesAfter.push(spaces); + return tag; + }); + + // Fetch nodes + var nodes; + if (tagNamesRequiringInnerHTMLFix[contextualElement.tagName.toLowerCase()]) { + // buildDOMWithFix uses string wrappers for problematic innerHTML. + nodes = buildDOMWithFix(html, contextualElement); + } else { + nodes = buildDOM(html, contextualElement, dom); + } + + // Build a list of script tags, the nodes themselves will be + // mutated as we add test nodes. + var i, j, node, nodeScriptNodes; + var scriptNodes = []; + for (i=0;node=nodes[i];i++) { + if (node.nodeType !== 1) { + continue; + } + if (node.tagName === 'SCRIPT') { + scriptNodes.push(node); + } else { + nodeScriptNodes = node.getElementsByTagName('script'); + for (j=0;j 0) { + textNode = dom.document.createTextNode(spaceBefore); + scriptNode.parentNode.insertBefore(textNode, scriptNode); + } + + spaceAfter = spacesAfter[i]; + if (spaceAfter && spaceAfter.length > 0) { + textNode = dom.document.createTextNode(spaceAfter); + scriptNode.parentNode.insertBefore(textNode, scriptNode.nextSibling); + } + } + + return nodes; + }; + } else if (needsIntegrationPointFix) { + buildHTMLDOM = function buildHTMLDOM(html, contextualElement, dom){ + if (svgHTMLIntegrationPoints[contextualElement.tagName]) { + return buildDOM(html, document.createElement('div'), dom); + } else { + return buildDOM(html, contextualElement, dom); + } + }; + } else { + buildHTMLDOM = buildDOM; + } + + __exports__.buildHTMLDOM = buildHTMLDOM; + }); +define("morph/morph", + ["exports"], + function(__exports__) { + "use strict"; + var splice = Array.prototype.splice; + + function ensureStartEnd(start, end) { + if (start === null || end === null) { + throw new Error('a fragment parent must have boundary nodes in order to detect insertion'); + } + } + + function ensureContext(contextualElement) { + if (!contextualElement || contextualElement.nodeType !== 1) { + throw new Error('An element node must be provided for a contextualElement, you provided ' + + (contextualElement ? 'nodeType ' + contextualElement.nodeType : 'nothing')); + } + } + + // TODO: this is an internal API, this should be an assert + function Morph(parent, start, end, domHelper, contextualElement) { + if (parent.nodeType === 11) { + ensureStartEnd(start, end); + this.element = null; + } else { + this.element = parent; + } + this._parent = parent; + this.start = start; + this.end = end; + this.domHelper = domHelper; + ensureContext(contextualElement); + this.contextualElement = contextualElement; + this.reset(); + } + + Morph.prototype.reset = function() { + this.text = null; + this.owner = null; + this.morphs = null; + this.before = null; + this.after = null; + this.escaped = true; + }; + + Morph.prototype.parent = function () { + if (!this.element) { + var parent = this.start.parentNode; + if (this._parent !== parent) { + this.element = this._parent = parent; + } + } + return this._parent; + }; + + Morph.prototype.destroy = function () { + if (this.owner) { + this.owner.removeMorph(this); + } else { + clear(this.element || this.parent(), this.start, this.end); + } + }; + + Morph.prototype.removeMorph = function (morph) { + var morphs = this.morphs; + for (var i=0, l=morphs.length; i 0 ? morphs[index-1] : null; + var after = index < morphs.length ? morphs[index] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var morph = new Morph(parent, start, end, this.domHelper, this.contextualElement); + + morph.owner = this; + morph._update(parent, node); + + if (before !== null) { + morph.before = before; + before.end = start.nextSibling; + before.after = morph; + } + + if (after !== null) { + morph.after = after; + after.before = morph; + after.start = end.previousSibling; + } + + this.morphs.splice(index, 0, morph); + return morph; + }; + + Morph.prototype.replace = function (index, removedLength, addedNodes) { + if (this.morphs === null) this.morphs = []; + var parent = this.element || this.parent(); + var morphs = this.morphs; + var before = index > 0 ? morphs[index-1] : null; + var after = index+removedLength < morphs.length ? morphs[index+removedLength] : null; + var start = before === null ? this.start : (before.end === null ? parent.lastChild : before.end.previousSibling); + var end = after === null ? this.end : (after.start === null ? parent.firstChild : after.start.nextSibling); + var addedLength = addedNodes === undefined ? 0 : addedNodes.length; + var args, i, current; + + if (removedLength > 0) { + clear(parent, start, end); + } + + if (addedLength === 0) { + if (before !== null) { + before.after = after; + before.end = end; + } + if (after !== null) { + after.before = before; + after.start = start; + } + morphs.splice(index, removedLength); + return; + } + + args = new Array(addedLength+2); + if (addedLength > 0) { + for (i=0; i " + n.nextStates.map(function(s) { return s.debug() }).join(" or ") + " )"; + }).join(", ") + } + END IF **/ + + // This is a somewhat naive strategy, but should work in a lot of cases + // A better strategy would properly resolve /posts/:id/new and /posts/edit/:id. + // + // This strategy generally prefers more static and less dynamic matching. + // Specifically, it + // + // * prefers fewer stars to more, then + // * prefers using stars for less of the match to more, then + // * prefers fewer dynamic segments to more, then + // * prefers more static segments to more + function sortSolutions(states) { + return states.sort(function(a, b) { + if (a.types.stars !== b.types.stars) { return a.types.stars - b.types.stars; } + + if (a.types.stars) { + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } + if (a.types.dynamics !== b.types.dynamics) { return b.types.dynamics - a.types.dynamics; } + } + + if (a.types.dynamics !== b.types.dynamics) { return a.types.dynamics - b.types.dynamics; } + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } + + return 0; + }); + } + + function recognizeChar(states, ch) { + var nextStates = []; + + for (var i=0, l=states.length; i 2 && key.slice(keyLength -2) === '[]') { + isArray = true; + key = key.slice(0, keyLength - 2); + if(!queryParams[key]) { + queryParams[key] = []; + } + } + value = pair[1] ? decodeURIComponent(pair[1]) : ''; + } + if (isArray) { + queryParams[key].push(value); + } else { + queryParams[key] = value; + } + } + return queryParams; + }, + + recognize: function(path) { + var states = [ this.rootState ], + pathLen, i, l, queryStart, queryParams = {}, + isSlashDropped = false; + + queryStart = path.indexOf('?'); + if (queryStart !== -1) { + var queryString = path.substr(queryStart + 1, path.length); + path = path.substr(0, queryStart); + queryParams = this.parseQueryString(queryString); + } + + path = decodeURI(path); + + // DEBUG GROUP path + + if (path.charAt(0) !== "/") { path = "/" + path; } + + pathLen = path.length; + if (pathLen > 1 && path.charAt(pathLen - 1) === "/") { + path = path.substr(0, pathLen - 1); + isSlashDropped = true; + } + + for (i=0, l=path.length; i= 0 && proceed; --i) { + var route = routes[i]; + recognizer.add(routes, { as: route.handler }); + proceed = route.path === '/' || route.path === '' || route.handler.slice(-6) === '.index'; + } + }); + }, + + hasRoute: function(route) { + return this.recognizer.hasRoute(route); + }, + + queryParamsTransition: function(changelist, wasTransitioning, oldState, newState) { + var router = this; + + fireQueryParamDidChange(this, newState, changelist); + + if (!wasTransitioning && this.activeTransition) { + // One of the handlers in queryParamsDidChange + // caused a transition. Just return that transition. + return this.activeTransition; + } else { + // Running queryParamsDidChange didn't change anything. + // Just update query params and be on our way. + + // We have to return a noop transition that will + // perform a URL update at the end. This gives + // the user the ability to set the url update + // method (default is replaceState). + var newTransition = new Transition(this); + newTransition.queryParamsOnly = true; + + oldState.queryParams = finalizeQueryParamChange(this, newState.handlerInfos, newState.queryParams, newTransition); + + newTransition.promise = newTransition.promise.then(function(result) { + updateURL(newTransition, oldState, true); + if (router.didTransition) { + router.didTransition(router.currentHandlerInfos); + } + return result; + }, null, promiseLabel("Transition complete")); + return newTransition; + } + }, + + // NOTE: this doesn't really belong here, but here + // it shall remain until our ES6 transpiler can + // handle cyclical deps. + transitionByIntent: function(intent, isIntermediate) { + try { + return getTransitionByIntent.apply(this, arguments); + } catch(e) { + return new Transition(this, intent, null, e); + } + }, + + /** + Clears the current and target route handlers and triggers exit + on each of them starting at the leaf and traversing up through + its ancestors. + */ + reset: function() { + if (this.state) { + forEach(this.state.handlerInfos.slice().reverse(), function(handlerInfo) { + var handler = handlerInfo.handler; + callHook(handler, 'exit'); + }); + } + + this.state = new TransitionState(); + this.currentHandlerInfos = null; + }, + + activeTransition: null, + + /** + var handler = handlerInfo.handler; + The entry point for handling a change to the URL (usually + via the back and forward button). + + Returns an Array of handlers and the parameters associated + with those parameters. + + @param {String} url a URL to process + + @return {Array} an Array of `[handler, parameter]` tuples + */ + handleURL: function(url) { + // Perform a URL-based transition, but don't change + // the URL afterward, since it already happened. + var args = slice.call(arguments); + if (url.charAt(0) !== '/') { args[0] = '/' + url; } + + return doTransition(this, args).method(null); + }, + + /** + Hook point for updating the URL. + + @param {String} url a URL to update to + */ + updateURL: function() { + throw new Error("updateURL is not implemented"); + }, + + /** + Hook point for replacing the current URL, i.e. with replaceState + + By default this behaves the same as `updateURL` + + @param {String} url a URL to update to + */ + replaceURL: function(url) { + this.updateURL(url); + }, + + /** + Transition into the specified named route. + + If necessary, trigger the exit callback on any handlers + that are no longer represented by the target route. + + @param {String} name the name of the route + */ + transitionTo: function(name) { + return doTransition(this, arguments); + }, + + intermediateTransitionTo: function(name) { + return doTransition(this, arguments, true); + }, + + refresh: function(pivotHandler) { + var state = this.activeTransition ? this.activeTransition.state : this.state; + var handlerInfos = state.handlerInfos; + var params = {}; + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + params[handlerInfo.name] = handlerInfo.params || {}; + } + + log(this, "Starting a refresh transition"); + var intent = new NamedTransitionIntent({ + name: handlerInfos[handlerInfos.length - 1].name, + pivotHandler: pivotHandler || handlerInfos[0].handler, + contexts: [], // TODO collect contexts...? + queryParams: this._changedQueryParams || state.queryParams || {} + }); + + return this.transitionByIntent(intent, false); + }, + + /** + Identical to `transitionTo` except that the current URL will be replaced + if possible. + + This method is intended primarily for use with `replaceState`. + + @param {String} name the name of the route + */ + replaceWith: function(name) { + return doTransition(this, arguments).method('replace'); + }, + + /** + Take a named route and context objects and generate a + URL. + + @param {String} name the name of the route to generate + a URL for + @param {...Object} objects a list of objects to serialize + + @return {String} a URL + */ + generate: function(handlerName) { + + var partitionedArgs = extractQueryParams(slice.call(arguments, 1)), + suppliedParams = partitionedArgs[0], + queryParams = partitionedArgs[1]; + + // Construct a TransitionIntent with the provided params + // and apply it to the present state of the router. + var intent = new NamedTransitionIntent({ name: handlerName, contexts: suppliedParams }); + var state = intent.applyToState(this.state, this.recognizer, this.getHandler); + var params = {}; + + for (var i = 0, len = state.handlerInfos.length; i < len; ++i) { + var handlerInfo = state.handlerInfos[i]; + var handlerParams = handlerInfo.serialize(); + merge(params, handlerParams); + } + params.queryParams = queryParams; + + return this.recognizer.generate(handlerName, params); + }, + + applyIntent: function(handlerName, contexts) { + var intent = new NamedTransitionIntent({ + name: handlerName, + contexts: contexts + }); + + var state = this.activeTransition && this.activeTransition.state || this.state; + return intent.applyToState(state, this.recognizer, this.getHandler); + }, + + isActiveIntent: function(handlerName, contexts, queryParams) { + var targetHandlerInfos = this.state.handlerInfos, + found = false, names, object, handlerInfo, handlerObj, i, len; + + if (!targetHandlerInfos.length) { return false; } + + var targetHandler = targetHandlerInfos[targetHandlerInfos.length - 1].name; + var recogHandlers = this.recognizer.handlersFor(targetHandler); + + var index = 0; + for (len = recogHandlers.length; index < len; ++index) { + handlerInfo = targetHandlerInfos[index]; + if (handlerInfo.name === handlerName) { break; } + } + + if (index === recogHandlers.length) { + // The provided route name isn't even in the route hierarchy. + return false; + } + + var state = new TransitionState(); + state.handlerInfos = targetHandlerInfos.slice(0, index + 1); + recogHandlers = recogHandlers.slice(0, index + 1); + + var intent = new NamedTransitionIntent({ + name: targetHandler, + contexts: contexts + }); + + var newState = intent.applyToHandlers(state, recogHandlers, this.getHandler, targetHandler, true, true); + + var handlersEqual = handlerInfosEqual(newState.handlerInfos, state.handlerInfos); + if (!queryParams || !handlersEqual) { + return handlersEqual; + } + + // Get a hash of QPs that will still be active on new route + var activeQPsOnNewHandler = {}; + merge(activeQPsOnNewHandler, queryParams); + + var activeQueryParams = this.state.queryParams; + for (var key in activeQueryParams) { + if (activeQueryParams.hasOwnProperty(key) && + activeQPsOnNewHandler.hasOwnProperty(key)) { + activeQPsOnNewHandler[key] = activeQueryParams[key]; + } + } + + return handlersEqual && !getChangelist(activeQPsOnNewHandler, queryParams); + }, + + isActive: function(handlerName) { + var partitionedArgs = extractQueryParams(slice.call(arguments, 1)); + return this.isActiveIntent(handlerName, partitionedArgs[0], partitionedArgs[1]); + }, + + trigger: function(name) { + var args = slice.call(arguments); + trigger(this, this.currentHandlerInfos, false, args); + }, + + /** + Hook point for logging transition status updates. + + @param {String} message The message to log. + */ + log: null, + + _willChangeContextEvent: 'willChangeContext', + _triggerWillChangeContext: function(handlerInfos, newTransition) { + trigger(this, handlerInfos, true, [this._willChangeContextEvent, newTransition]); + }, + + _triggerWillLeave: function(handlerInfos, newTransition, leavingChecker) { + trigger(this, handlerInfos, true, ['willLeave', newTransition, leavingChecker]); + } + }; + + /** + @private + + Fires queryParamsDidChange event + */ + function fireQueryParamDidChange(router, newState, queryParamChangelist) { + // If queryParams changed trigger event + if (queryParamChangelist) { + + // This is a little hacky but we need some way of storing + // changed query params given that no activeTransition + // is guaranteed to have occurred. + router._changedQueryParams = queryParamChangelist.all; + trigger(router, newState.handlerInfos, true, ['queryParamsDidChange', queryParamChangelist.changed, queryParamChangelist.all, queryParamChangelist.removed]); + router._changedQueryParams = null; + } + } + + /** + @private + + Takes an Array of `HandlerInfo`s, figures out which ones are + exiting, entering, or changing contexts, and calls the + proper handler hooks. + + For example, consider the following tree of handlers. Each handler is + followed by the URL segment it handles. + + ``` + |~index ("/") + | |~posts ("/posts") + | | |-showPost ("/:id") + | | |-newPost ("/new") + | | |-editPost ("/edit") + | |~about ("/about/:id") + ``` + + Consider the following transitions: + + 1. A URL transition to `/posts/1`. + 1. Triggers the `*model` callbacks on the + `index`, `posts`, and `showPost` handlers + 2. Triggers the `enter` callback on the same + 3. Triggers the `setup` callback on the same + 2. A direct transition to `newPost` + 1. Triggers the `exit` callback on `showPost` + 2. Triggers the `enter` callback on `newPost` + 3. Triggers the `setup` callback on `newPost` + 3. A direct transition to `about` with a specified + context object + 1. Triggers the `exit` callback on `newPost` + and `posts` + 2. Triggers the `serialize` callback on `about` + 3. Triggers the `enter` callback on `about` + 4. Triggers the `setup` callback on `about` + + @param {Router} transition + @param {TransitionState} newState + */ + function setupContexts(router, newState, transition) { + var partition = partitionHandlers(router.state, newState); + + forEach(partition.exited, function(handlerInfo) { + var handler = handlerInfo.handler; + delete handler.context; + + callHook(handler, 'reset', true, transition); + callHook(handler, 'exit', transition); + }); + + var oldState = router.oldState = router.state; + router.state = newState; + var currentHandlerInfos = router.currentHandlerInfos = partition.unchanged.slice(); + + try { + forEach(partition.reset, function(handlerInfo) { + var handler = handlerInfo.handler; + callHook(handler, 'reset', false, transition); + }); + + forEach(partition.updatedContext, function(handlerInfo) { + return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, false, transition); + }); + + forEach(partition.entered, function(handlerInfo) { + return handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, true, transition); + }); + } catch(e) { + router.state = oldState; + router.currentHandlerInfos = oldState.handlerInfos; + throw e; + } + + router.state.queryParams = finalizeQueryParamChange(router, currentHandlerInfos, newState.queryParams, transition); + } + + + /** + @private + + Helper method used by setupContexts. Handles errors or redirects + that may happen in enter/setup. + */ + function handlerEnteredOrUpdated(currentHandlerInfos, handlerInfo, enter, transition) { + + var handler = handlerInfo.handler, + context = handlerInfo.context; + + if (enter) { + callHook(handler, 'enter', transition); + } + if (transition && transition.isAborted) { + throw new TransitionAborted(); + } + + handler.context = context; + callHook(handler, 'contextDidChange'); + + callHook(handler, 'setup', context, transition); + if (transition && transition.isAborted) { + throw new TransitionAborted(); + } + + currentHandlerInfos.push(handlerInfo); + + return true; + } + + + /** + @private + + This function is called when transitioning from one URL to + another to determine which handlers are no longer active, + which handlers are newly active, and which handlers remain + active but have their context changed. + + Take a list of old handlers and new handlers and partition + them into four buckets: + + * unchanged: the handler was active in both the old and + new URL, and its context remains the same + * updated context: the handler was active in both the + old and new URL, but its context changed. The handler's + `setup` method, if any, will be called with the new + context. + * exited: the handler was active in the old URL, but is + no longer active. + * entered: the handler was not active in the old URL, but + is now active. + + The PartitionedHandlers structure has four fields: + + * `updatedContext`: a list of `HandlerInfo` objects that + represent handlers that remain active but have a changed + context + * `entered`: a list of `HandlerInfo` objects that represent + handlers that are newly active + * `exited`: a list of `HandlerInfo` objects that are no + longer active. + * `unchanged`: a list of `HanderInfo` objects that remain active. + + @param {Array[HandlerInfo]} oldHandlers a list of the handler + information for the previous URL (or `[]` if this is the + first handled transition) + @param {Array[HandlerInfo]} newHandlers a list of the handler + information for the new URL + + @return {Partition} + */ + function partitionHandlers(oldState, newState) { + var oldHandlers = oldState.handlerInfos; + var newHandlers = newState.handlerInfos; + + var handlers = { + updatedContext: [], + exited: [], + entered: [], + unchanged: [] + }; + + var handlerChanged, contextChanged = false, i, l; + + for (i=0, l=newHandlers.length; i= 0; --i) { + var handlerInfo = handlerInfos[i]; + merge(params, handlerInfo.params); + if (handlerInfo.handler.inaccessibleByURL) { + urlMethod = null; + } + } + + if (urlMethod) { + params.queryParams = transition._visibleQueryParams || state.queryParams; + var url = router.recognizer.generate(handlerName, params); + + if (urlMethod === 'replace') { + router.replaceURL(url); + } else { + router.updateURL(url); + } + } + } + + /** + @private + + Updates the URL (if necessary) and calls `setupContexts` + to update the router's array of `currentHandlerInfos`. + */ + function finalizeTransition(transition, newState) { + + try { + log(transition.router, transition.sequence, "Resolved all models on destination route; finalizing transition."); + + var router = transition.router, + handlerInfos = newState.handlerInfos, + seq = transition.sequence; + + // Run all the necessary enter/setup/exit hooks + setupContexts(router, newState, transition); + + // Check if a redirect occurred in enter/setup + if (transition.isAborted) { + // TODO: cleaner way? distinguish b/w targetHandlerInfos? + router.state.handlerInfos = router.currentHandlerInfos; + return Promise.reject(logAbort(transition)); + } + + updateURL(transition, newState, transition.intent.url); + + transition.isActive = false; + router.activeTransition = null; + + trigger(router, router.currentHandlerInfos, true, ['didTransition']); + + if (router.didTransition) { + router.didTransition(router.currentHandlerInfos); + } + + log(router, transition.sequence, "TRANSITION COMPLETE."); + + // Resolve with the final handler. + return handlerInfos[handlerInfos.length - 1].handler; + } catch(e) { + if (!((e instanceof TransitionAborted))) { + //var erroneousHandler = handlerInfos.pop(); + var infos = transition.state.handlerInfos; + transition.trigger(true, 'error', e, transition, infos[infos.length-1].handler); + transition.abort(); + } + + throw e; + } + } + + /** + @private + + Begins and returns a Transition based on the provided + arguments. Accepts arguments in the form of both URL + transitions and named transitions. + + @param {Router} router + @param {Array[Object]} args arguments passed to transitionTo, + replaceWith, or handleURL + */ + function doTransition(router, args, isIntermediate) { + // Normalize blank transitions to root URL transitions. + var name = args[0] || '/'; + + var lastArg = args[args.length-1]; + var queryParams = {}; + if (lastArg && lastArg.hasOwnProperty('queryParams')) { + queryParams = pop.call(args).queryParams; + } + + var intent; + if (args.length === 0) { + + log(router, "Updating query params"); + + // A query param update is really just a transition + // into the route you're already on. + var handlerInfos = router.state.handlerInfos; + intent = new NamedTransitionIntent({ + name: handlerInfos[handlerInfos.length - 1].name, + contexts: [], + queryParams: queryParams + }); + + } else if (name.charAt(0) === '/') { + + log(router, "Attempting URL transition to " + name); + intent = new URLTransitionIntent({ url: name }); + + } else { + + log(router, "Attempting transition to " + name); + intent = new NamedTransitionIntent({ + name: args[0], + contexts: slice.call(args, 1), + queryParams: queryParams + }); + } + + return router.transitionByIntent(intent, isIntermediate); + } + + function handlerInfosEqual(handlerInfos, otherHandlerInfos) { + if (handlerInfos.length !== otherHandlerInfos.length) { + return false; + } + + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + if (handlerInfos[i] !== otherHandlerInfos[i]) { + return false; + } + } + return true; + } + + function finalizeQueryParamChange(router, resolvedHandlers, newQueryParams, transition) { + // We fire a finalizeQueryParamChange event which + // gives the new route hierarchy a chance to tell + // us which query params it's consuming and what + // their final values are. If a query param is + // no longer consumed in the final route hierarchy, + // its serialized segment will be removed + // from the URL. + + for (var k in newQueryParams) { + if (newQueryParams.hasOwnProperty(k) && + newQueryParams[k] === null) { + delete newQueryParams[k]; + } + } + + var finalQueryParamsArray = []; + trigger(router, resolvedHandlers, true, ['finalizeQueryParamChange', newQueryParams, finalQueryParamsArray, transition]); + + if (transition) { + transition._visibleQueryParams = {}; + } + + var finalQueryParams = {}; + for (var i = 0, len = finalQueryParamsArray.length; i < len; ++i) { + var qp = finalQueryParamsArray[i]; + finalQueryParams[qp.key] = qp.value; + if (transition && qp.visible !== false) { + transition._visibleQueryParams[qp.key] = qp.value; + } + } + return finalQueryParams; + } + + function notifyExistingHandlers(router, newState, newTransition) { + var oldHandlers = router.state.handlerInfos, + changing = [], + leavingIndex = null, + leaving, leavingChecker, i, oldHandlerLen, oldHandler, newHandler; + + oldHandlerLen = oldHandlers.length; + for (i = 0; i < oldHandlerLen; i++) { + oldHandler = oldHandlers[i]; + newHandler = newState.handlerInfos[i]; + + if (!newHandler || oldHandler.name !== newHandler.name) { + leavingIndex = i; + break; + } + + if (!newHandler.isResolved) { + changing.push(oldHandler); + } + } + + if (leavingIndex !== null) { + leaving = oldHandlers.slice(leavingIndex, oldHandlerLen); + leavingChecker = function(name) { + for (var h = 0, len = leaving.length; h < len; h++) { + if (leaving[h].name === name) { + return true; + } + } + return false; + }; + + router._triggerWillLeave(leaving, newTransition, leavingChecker); + } + + if (changing.length > 0) { + router._triggerWillChangeContext(changing, newTransition); + } + + trigger(router, oldHandlers, true, ['willTransition', newTransition]); + } + + __exports__["default"] = Router; + }); +define("router/transition-intent", + ["./utils","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var merge = __dependency1__.merge; + + function TransitionIntent(props) { + this.initialize(props); + + // TODO: wat + this.data = this.data || {}; + } + + TransitionIntent.prototype = { + initialize: null, + applyToState: null + }; + + __exports__["default"] = TransitionIntent; + }); +define("router/transition-intent/named-transition-intent", + ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var TransitionIntent = __dependency1__["default"]; + var TransitionState = __dependency2__["default"]; + var handlerInfoFactory = __dependency3__["default"]; + var isParam = __dependency4__.isParam; + var extractQueryParams = __dependency4__.extractQueryParams; + var merge = __dependency4__.merge; + var subclass = __dependency4__.subclass; + + __exports__["default"] = subclass(TransitionIntent, { + name: null, + pivotHandler: null, + contexts: null, + queryParams: null, + + initialize: function(props) { + this.name = props.name; + this.pivotHandler = props.pivotHandler; + this.contexts = props.contexts || []; + this.queryParams = props.queryParams; + }, + + applyToState: function(oldState, recognizer, getHandler, isIntermediate) { + + var partitionedArgs = extractQueryParams([this.name].concat(this.contexts)), + pureArgs = partitionedArgs[0], + queryParams = partitionedArgs[1], + handlers = recognizer.handlersFor(pureArgs[0]); + + var targetRouteName = handlers[handlers.length-1].handler; + + return this.applyToHandlers(oldState, handlers, getHandler, targetRouteName, isIntermediate); + }, + + applyToHandlers: function(oldState, handlers, getHandler, targetRouteName, isIntermediate, checkingIfActive) { + + var i, len; + var newState = new TransitionState(); + var objects = this.contexts.slice(0); + + var invalidateIndex = handlers.length; + + // Pivot handlers are provided for refresh transitions + if (this.pivotHandler) { + for (i = 0, len = handlers.length; i < len; ++i) { + if (getHandler(handlers[i].handler) === this.pivotHandler) { + invalidateIndex = i; + break; + } + } + } + + var pivotHandlerFound = !this.pivotHandler; + + for (i = handlers.length - 1; i >= 0; --i) { + var result = handlers[i]; + var name = result.handler; + var handler = getHandler(name); + + var oldHandlerInfo = oldState.handlerInfos[i]; + var newHandlerInfo = null; + + if (result.names.length > 0) { + if (i >= invalidateIndex) { + newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); + } else { + newHandlerInfo = this.getHandlerInfoForDynamicSegment(name, handler, result.names, objects, oldHandlerInfo, targetRouteName, i); + } + } else { + // This route has no dynamic segment. + // Therefore treat as a param-based handlerInfo + // with empty params. This will cause the `model` + // hook to be called with empty params, which is desirable. + newHandlerInfo = this.createParamHandlerInfo(name, handler, result.names, objects, oldHandlerInfo); + } + + if (checkingIfActive) { + // If we're performing an isActive check, we want to + // serialize URL params with the provided context, but + // ignore mismatches between old and new context. + newHandlerInfo = newHandlerInfo.becomeResolved(null, newHandlerInfo.context); + var oldContext = oldHandlerInfo && oldHandlerInfo.context; + if (result.names.length > 0 && newHandlerInfo.context === oldContext) { + // If contexts match in isActive test, assume params also match. + // This allows for flexibility in not requiring that every last + // handler provide a `serialize` method + newHandlerInfo.params = oldHandlerInfo && oldHandlerInfo.params; + } + newHandlerInfo.context = oldContext; + } + + var handlerToUse = oldHandlerInfo; + if (i >= invalidateIndex || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { + invalidateIndex = Math.min(i, invalidateIndex); + handlerToUse = newHandlerInfo; + } + + if (isIntermediate && !checkingIfActive) { + handlerToUse = handlerToUse.becomeResolved(null, handlerToUse.context); + } + + newState.handlerInfos.unshift(handlerToUse); + } + + if (objects.length > 0) { + throw new Error("More context objects were passed than there are dynamic segments for the route: " + targetRouteName); + } + + if (!isIntermediate) { + this.invalidateChildren(newState.handlerInfos, invalidateIndex); + } + + merge(newState.queryParams, this.queryParams || {}); + + return newState; + }, + + invalidateChildren: function(handlerInfos, invalidateIndex) { + for (var i = invalidateIndex, l = handlerInfos.length; i < l; ++i) { + var handlerInfo = handlerInfos[i]; + handlerInfos[i] = handlerInfos[i].getUnresolved(); + } + }, + + getHandlerInfoForDynamicSegment: function(name, handler, names, objects, oldHandlerInfo, targetRouteName, i) { + + var numNames = names.length; + var objectToUse; + if (objects.length > 0) { + + // Use the objects provided for this transition. + objectToUse = objects[objects.length - 1]; + if (isParam(objectToUse)) { + return this.createParamHandlerInfo(name, handler, names, objects, oldHandlerInfo); + } else { + objects.pop(); + } + } else if (oldHandlerInfo && oldHandlerInfo.name === name) { + // Reuse the matching oldHandlerInfo + return oldHandlerInfo; + } else { + if (this.preTransitionState) { + var preTransitionHandlerInfo = this.preTransitionState.handlerInfos[i]; + objectToUse = preTransitionHandlerInfo && preTransitionHandlerInfo.context; + } else { + // Ideally we should throw this error to provide maximal + // information to the user that not enough context objects + // were provided, but this proves too cumbersome in Ember + // in cases where inner template helpers are evaluated + // before parent helpers un-render, in which cases this + // error somewhat prematurely fires. + //throw new Error("Not enough context objects were provided to complete a transition to " + targetRouteName + ". Specifically, the " + name + " route needs an object that can be serialized into its dynamic URL segments [" + names.join(', ') + "]"); + return oldHandlerInfo; + } + } + + return handlerInfoFactory('object', { + name: name, + handler: handler, + context: objectToUse, + names: names + }); + }, + + createParamHandlerInfo: function(name, handler, names, objects, oldHandlerInfo) { + var params = {}; + + // Soak up all the provided string/numbers + var numNames = names.length; + while (numNames--) { + + // Only use old params if the names match with the new handler + var oldParams = (oldHandlerInfo && name === oldHandlerInfo.name && oldHandlerInfo.params) || {}; + + var peek = objects[objects.length - 1]; + var paramName = names[numNames]; + if (isParam(peek)) { + params[paramName] = "" + objects.pop(); + } else { + // If we're here, this means only some of the params + // were string/number params, so try and use a param + // value from a previous handler. + if (oldParams.hasOwnProperty(paramName)) { + params[paramName] = oldParams[paramName]; + } else { + throw new Error("You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route " + name); + } + } + } + + return handlerInfoFactory('param', { + name: name, + handler: handler, + params: params + }); + } + }); + }); +define("router/transition-intent/url-transition-intent", + ["../transition-intent","../transition-state","../handler-info/factory","../utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var TransitionIntent = __dependency1__["default"]; + var TransitionState = __dependency2__["default"]; + var handlerInfoFactory = __dependency3__["default"]; + var oCreate = __dependency4__.oCreate; + var merge = __dependency4__.merge; + var subclass = __dependency4__.subclass; + + __exports__["default"] = subclass(TransitionIntent, { + url: null, + + initialize: function(props) { + this.url = props.url; + }, + + applyToState: function(oldState, recognizer, getHandler) { + var newState = new TransitionState(); + + var results = recognizer.recognize(this.url), + queryParams = {}, + i, len; + + if (!results) { + throw new UnrecognizedURLError(this.url); + } + + var statesDiffer = false; + + for (i = 0, len = results.length; i < len; ++i) { + var result = results[i]; + var name = result.handler; + var handler = getHandler(name); + + if (handler.inaccessibleByURL) { + throw new UnrecognizedURLError(this.url); + } + + var newHandlerInfo = handlerInfoFactory('param', { + name: name, + handler: handler, + params: result.params + }); + + var oldHandlerInfo = oldState.handlerInfos[i]; + if (statesDiffer || newHandlerInfo.shouldSupercede(oldHandlerInfo)) { + statesDiffer = true; + newState.handlerInfos[i] = newHandlerInfo; + } else { + newState.handlerInfos[i] = oldHandlerInfo; + } + } + + merge(newState.queryParams, results.queryParams); + + return newState; + } + }); + + /** + Promise reject reasons passed to promise rejection + handlers for failed transitions. + */ + function UnrecognizedURLError(message) { + this.message = (message || "UnrecognizedURLError"); + this.name = "UnrecognizedURLError"; + } + }); +define("router/transition-state", + ["./handler-info","./utils","rsvp/promise","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var ResolvedHandlerInfo = __dependency1__.ResolvedHandlerInfo; + var forEach = __dependency2__.forEach; + var promiseLabel = __dependency2__.promiseLabel; + var callHook = __dependency2__.callHook; + var Promise = __dependency3__["default"]; + + function TransitionState(other) { + this.handlerInfos = []; + this.queryParams = {}; + this.params = {}; + } + + TransitionState.prototype = { + handlerInfos: null, + queryParams: null, + params: null, + + promiseLabel: function(label) { + var targetName = ''; + forEach(this.handlerInfos, function(handlerInfo) { + if (targetName !== '') { + targetName += '.'; + } + targetName += handlerInfo.name; + }); + return promiseLabel("'" + targetName + "': " + label); + }, + + resolve: function(shouldContinue, payload) { + var self = this; + // First, calculate params for this state. This is useful + // information to provide to the various route hooks. + var params = this.params; + forEach(this.handlerInfos, function(handlerInfo) { + params[handlerInfo.name] = handlerInfo.params || {}; + }); + + payload = payload || {}; + payload.resolveIndex = 0; + + var currentState = this; + var wasAborted = false; + + // The prelude RSVP.resolve() asyncs us into the promise land. + return Promise.resolve(null, this.promiseLabel("Start transition")) + .then(resolveOneHandlerInfo, null, this.promiseLabel('Resolve handler'))['catch'](handleError, this.promiseLabel('Handle error')); + + function innerShouldContinue() { + return Promise.resolve(shouldContinue(), currentState.promiseLabel("Check if should continue"))['catch'](function(reason) { + // We distinguish between errors that occurred + // during resolution (e.g. beforeModel/model/afterModel), + // and aborts due to a rejecting promise from shouldContinue(). + wasAborted = true; + return Promise.reject(reason); + }, currentState.promiseLabel("Handle abort")); + } + + function handleError(error) { + // This is the only possible + // reject value of TransitionState#resolve + var handlerInfos = currentState.handlerInfos; + var errorHandlerIndex = payload.resolveIndex >= handlerInfos.length ? + handlerInfos.length - 1 : payload.resolveIndex; + return Promise.reject({ + error: error, + handlerWithError: currentState.handlerInfos[errorHandlerIndex].handler, + wasAborted: wasAborted, + state: currentState + }); + } + + function proceed(resolvedHandlerInfo) { + var wasAlreadyResolved = currentState.handlerInfos[payload.resolveIndex].isResolved; + + // Swap the previously unresolved handlerInfo with + // the resolved handlerInfo + currentState.handlerInfos[payload.resolveIndex++] = resolvedHandlerInfo; + + if (!wasAlreadyResolved) { + // Call the redirect hook. The reason we call it here + // vs. afterModel is so that redirects into child + // routes don't re-run the model hooks for this + // already-resolved route. + var handler = resolvedHandlerInfo.handler; + callHook(handler, 'redirect', resolvedHandlerInfo.context, payload); + } + + // Proceed after ensuring that the redirect hook + // didn't abort this transition by transitioning elsewhere. + return innerShouldContinue().then(resolveOneHandlerInfo, null, currentState.promiseLabel('Resolve handler')); + } + + function resolveOneHandlerInfo() { + if (payload.resolveIndex === currentState.handlerInfos.length) { + // This is is the only possible + // fulfill value of TransitionState#resolve + return { + error: null, + state: currentState + }; + } + + var handlerInfo = currentState.handlerInfos[payload.resolveIndex]; + + return handlerInfo.resolve(innerShouldContinue, payload) + .then(proceed, null, currentState.promiseLabel('Proceed')); + } + } + }; + + __exports__["default"] = TransitionState; + }); +define("router/transition", + ["rsvp/promise","./handler-info","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var ResolvedHandlerInfo = __dependency2__.ResolvedHandlerInfo; + var trigger = __dependency3__.trigger; + var slice = __dependency3__.slice; + var log = __dependency3__.log; + var promiseLabel = __dependency3__.promiseLabel; + + /** + @private + + A Transition is a thennable (a promise-like object) that represents + an attempt to transition to another route. It can be aborted, either + explicitly via `abort` or by attempting another transition while a + previous one is still underway. An aborted transition can also + be `retry()`d later. + */ + function Transition(router, intent, state, error) { + var transition = this; + this.state = state || router.state; + this.intent = intent; + this.router = router; + this.data = this.intent && this.intent.data || {}; + this.resolvedModels = {}; + this.queryParams = {}; + + if (error) { + this.promise = Promise.reject(error); + return; + } + + if (state) { + this.params = state.params; + this.queryParams = state.queryParams; + this.handlerInfos = state.handlerInfos; + + var len = state.handlerInfos.length; + if (len) { + this.targetName = state.handlerInfos[len-1].name; + } + + for (var i = 0; i < len; ++i) { + var handlerInfo = state.handlerInfos[i]; + + // TODO: this all seems hacky + if (!handlerInfo.isResolved) { break; } + this.pivotHandler = handlerInfo.handler; + } + + this.sequence = Transition.currentSequence++; + this.promise = state.resolve(checkForAbort, this)['catch'](function(result) { + if (result.wasAborted || transition.isAborted) { + return Promise.reject(logAbort(transition)); + } else { + transition.trigger('error', result.error, transition, result.handlerWithError); + transition.abort(); + return Promise.reject(result.error); + } + }, promiseLabel('Handle Abort')); + } else { + this.promise = Promise.resolve(this.state); + this.params = {}; + } + + function checkForAbort() { + if (transition.isAborted) { + return Promise.reject(undefined, promiseLabel("Transition aborted - reject")); + } + } + } + + Transition.currentSequence = 0; + + Transition.prototype = { + targetName: null, + urlMethod: 'update', + intent: null, + params: null, + pivotHandler: null, + resolveIndex: 0, + handlerInfos: null, + resolvedModels: null, + isActive: true, + state: null, + queryParamsOnly: false, + + isTransition: true, + + isExiting: function(handler) { + var handlerInfos = this.handlerInfos; + for (var i = 0, len = handlerInfos.length; i < len; ++i) { + var handlerInfo = handlerInfos[i]; + if (handlerInfo.name === handler || handlerInfo.handler === handler) { + return false; + } + } + return true; + }, + + /** + @public + + The Transition's internal promise. Calling `.then` on this property + is that same as calling `.then` on the Transition object itself, but + this property is exposed for when you want to pass around a + Transition's promise, but not the Transition object itself, since + Transition object can be externally `abort`ed, while the promise + cannot. + */ + promise: null, + + /** + @public + + Custom state can be stored on a Transition's `data` object. + This can be useful for decorating a Transition within an earlier + hook and shared with a later hook. Properties set on `data` will + be copied to new transitions generated by calling `retry` on this + transition. + */ + data: null, + + /** + @public + + A standard promise hook that resolves if the transition + succeeds and rejects if it fails/redirects/aborts. + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @param {Function} onFulfilled + @param {Function} onRejected + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + then: function(onFulfilled, onRejected, label) { + return this.promise.then(onFulfilled, onRejected, label); + }, + + /** + @public + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @method catch + @param {Function} onRejection + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + "catch": function(onRejection, label) { + return this.promise["catch"](onRejection, label); + }, + + /** + @public + + Forwards to the internal `promise` property which you can + use in situations where you want to pass around a thennable, + but not the Transition itself. + + @method finally + @param {Function} callback + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + "finally": function(callback, label) { + return this.promise["finally"](callback, label); + }, + + /** + @public + + Aborts the Transition. Note you can also implicitly abort a transition + by initiating another transition while a previous one is underway. + */ + abort: function() { + if (this.isAborted) { return this; } + log(this.router, this.sequence, this.targetName + ": transition was aborted"); + this.intent.preTransitionState = this.router.state; + this.isAborted = true; + this.isActive = false; + this.router.activeTransition = null; + return this; + }, + + /** + @public + + Retries a previously-aborted transition (making sure to abort the + transition if it's still active). Returns a new transition that + represents the new attempt to transition. + */ + retry: function() { + // TODO: add tests for merged state retry()s + this.abort(); + return this.router.transitionByIntent(this.intent, false); + }, + + /** + @public + + Sets the URL-changing method to be employed at the end of a + successful transition. By default, a new Transition will just + use `updateURL`, but passing 'replace' to this method will + cause the URL to update using 'replaceWith' instead. Omitting + a parameter will disable the URL change, allowing for transitions + that don't update the URL at completion (this is also used for + handleURL, since the URL has already changed before the + transition took place). + + @param {String} method the type of URL-changing method to use + at the end of a transition. Accepted values are 'replace', + falsy values, or any other non-falsy value (which is + interpreted as an updateURL transition). + + @return {Transition} this transition + */ + method: function(method) { + this.urlMethod = method; + return this; + }, + + /** + @public + + Fires an event on the current list of resolved/resolving + handlers within this transition. Useful for firing events + on route hierarchies that haven't fully been entered yet. + + Note: This method is also aliased as `send` + + @param {Boolean} [ignoreFailure=false] a boolean specifying whether unhandled events throw an error + @param {String} name the name of the event to fire + */ + trigger: function (ignoreFailure) { + var args = slice.call(arguments); + if (typeof ignoreFailure === 'boolean') { + args.shift(); + } else { + // Throw errors on unhandled trigger events by default + ignoreFailure = false; + } + trigger(this.router, this.state.handlerInfos.slice(0, this.resolveIndex + 1), ignoreFailure, args); + }, + + /** + @public + + Transitions are aborted and their promises rejected + when redirects occur; this method returns a promise + that will follow any redirects that occur and fulfill + with the value fulfilled by any redirecting transitions + that occur. + + @return {Promise} a promise that fulfills with the same + value that the final redirecting transition fulfills with + */ + followRedirects: function() { + var router = this.router; + return this.promise['catch'](function(reason) { + if (router.activeTransition) { + return router.activeTransition.followRedirects(); + } + return Promise.reject(reason); + }); + }, + + toString: function() { + return "Transition (sequence " + this.sequence + ")"; + }, + + /** + @private + */ + log: function(message) { + log(this.router, this.sequence, message); + } + }; + + // Alias 'trigger' as 'send' + Transition.prototype.send = Transition.prototype.trigger; + + /** + @private + + Logs and returns a TransitionAborted error. + */ + function logAbort(transition) { + log(transition.router, transition.sequence, "detected abort."); + return new TransitionAborted(); + } + + function TransitionAborted(message) { + this.message = (message || "TransitionAborted"); + this.name = "TransitionAborted"; + } + + __exports__.Transition = Transition; + __exports__.logAbort = logAbort; + __exports__.TransitionAborted = TransitionAborted; + }); +define("router/utils", + ["exports"], + function(__exports__) { + "use strict"; + var slice = Array.prototype.slice; + + var _isArray; + if (!Array.isArray) { + _isArray = function (x) { + return Object.prototype.toString.call(x) === "[object Array]"; + }; + } else { + _isArray = Array.isArray; + } + + var isArray = _isArray; + __exports__.isArray = isArray; + function merge(hash, other) { + for (var prop in other) { + if (other.hasOwnProperty(prop)) { hash[prop] = other[prop]; } + } + } + + var oCreate = Object.create || function(proto) { + function F() {} + F.prototype = proto; + return new F(); + }; + __exports__.oCreate = oCreate; + /** + @private + + Extracts query params from the end of an array + **/ + function extractQueryParams(array) { + var len = (array && array.length), head, queryParams; + + if(len && len > 0 && array[len - 1] && array[len - 1].hasOwnProperty('queryParams')) { + queryParams = array[len - 1].queryParams; + head = slice.call(array, 0, len - 1); + return [head, queryParams]; + } else { + return [array, null]; + } + } + + __exports__.extractQueryParams = extractQueryParams;/** + @private + + Coerces query param properties and array elements into strings. + **/ + function coerceQueryParamsToString(queryParams) { + for (var key in queryParams) { + if (typeof queryParams[key] === 'number') { + queryParams[key] = '' + queryParams[key]; + } else if (isArray(queryParams[key])) { + for (var i = 0, l = queryParams[key].length; i < l; i++) { + queryParams[key][i] = '' + queryParams[key][i]; + } + } + } + } + /** + @private + */ + function log(router, sequence, msg) { + if (!router.log) { return; } + + if (arguments.length === 3) { + router.log("Transition #" + sequence + ": " + msg); + } else { + msg = sequence; + router.log(msg); + } + } + + __exports__.log = log;function bind(context, fn) { + var boundArgs = arguments; + return function(value) { + var args = slice.call(boundArgs, 2); + args.push(value); + return fn.apply(context, args); + }; + } + + __exports__.bind = bind;function isParam(object) { + return (typeof object === "string" || object instanceof String || typeof object === "number" || object instanceof Number); + } + + + function forEach(array, callback) { + for (var i=0, l=array.length; i=0; i--) { + var handlerInfo = handlerInfos[i], + handler = handlerInfo.handler; + + if (handler.events && handler.events[name]) { + if (handler.events[name].apply(handler, args) === true) { + eventWasHandled = true; + } else { + return; + } + } + } + + if (!eventWasHandled && !ignoreFailure) { + throw new Error("Nothing handled the event '" + name + "'."); + } + } + + __exports__.trigger = trigger;function getChangelist(oldObject, newObject) { + var key; + var results = { + all: {}, + changed: {}, + removed: {} + }; + + merge(results.all, newObject); + + var didChange = false; + coerceQueryParamsToString(oldObject); + coerceQueryParamsToString(newObject); + + // Calculate removals + for (key in oldObject) { + if (oldObject.hasOwnProperty(key)) { + if (!newObject.hasOwnProperty(key)) { + didChange = true; + results.removed[key] = oldObject[key]; + } + } + } + + // Calculate changes + for (key in newObject) { + if (newObject.hasOwnProperty(key)) { + if (isArray(oldObject[key]) && isArray(newObject[key])) { + if (oldObject[key].length !== newObject[key].length) { + results.changed[key] = newObject[key]; + didChange = true; + } else { + for (var i = 0, l = oldObject[key].length; i < l; i++) { + if (oldObject[key][i] !== newObject[key][i]) { + results.changed[key] = newObject[key]; + didChange = true; + } + } + } + } + else { + if (oldObject[key] !== newObject[key]) { + results.changed[key] = newObject[key]; + didChange = true; + } + } + } + } + + return didChange && results; + } + + __exports__.getChangelist = getChangelist;function promiseLabel(label) { + return 'Router: ' + label; + } + + __exports__.promiseLabel = promiseLabel;function subclass(parentConstructor, proto) { + function C(props) { + parentConstructor.call(this, props || {}); + } + C.prototype = oCreate(parentConstructor.prototype); + merge(C.prototype, proto); + return C; + } + + __exports__.subclass = subclass;function resolveHook(obj, hookName) { + if (!obj) { return; } + var underscored = "_" + hookName; + return obj[underscored] && underscored || + obj[hookName] && hookName; + } + + function callHook(obj, hookName) { + var args = slice.call(arguments, 2); + return applyHook(obj, hookName, args); + } + + function applyHook(obj, _hookName, args) { + var hookName = resolveHook(obj, _hookName); + if (hookName) { + return obj[hookName].apply(obj, args); + } + } + + __exports__.merge = merge; + __exports__.slice = slice; + __exports__.isParam = isParam; + __exports__.coerceQueryParamsToString = coerceQueryParamsToString; + __exports__.callHook = callHook; + __exports__.resolveHook = resolveHook; + __exports__.applyHook = applyHook; + }); +define("rsvp", + ["./rsvp/promise","./rsvp/events","./rsvp/node","./rsvp/all","./rsvp/all-settled","./rsvp/race","./rsvp/hash","./rsvp/hash-settled","./rsvp/rethrow","./rsvp/defer","./rsvp/config","./rsvp/map","./rsvp/resolve","./rsvp/reject","./rsvp/filter","./rsvp/asap","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var EventTarget = __dependency2__["default"]; + var denodeify = __dependency3__["default"]; + var all = __dependency4__["default"]; + var allSettled = __dependency5__["default"]; + var race = __dependency6__["default"]; + var hash = __dependency7__["default"]; + var hashSettled = __dependency8__["default"]; + var rethrow = __dependency9__["default"]; + var defer = __dependency10__["default"]; + var config = __dependency11__.config; + var configure = __dependency11__.configure; + var map = __dependency12__["default"]; + var resolve = __dependency13__["default"]; + var reject = __dependency14__["default"]; + var filter = __dependency15__["default"]; + var asap = __dependency16__["default"]; + + config.async = asap; // default async is asap; + var cast = resolve; + function async(callback, arg) { + config.async(callback, arg); + } + + function on() { + config.on.apply(config, arguments); + } + + function off() { + config.off.apply(config, arguments); + } + + // Set up instrumentation through `window.__PROMISE_INTRUMENTATION__` + if (typeof window !== 'undefined' && typeof window['__PROMISE_INSTRUMENTATION__'] === 'object') { + var callbacks = window['__PROMISE_INSTRUMENTATION__']; + configure('instrument', true); + for (var eventName in callbacks) { + if (callbacks.hasOwnProperty(eventName)) { + on(eventName, callbacks[eventName]); + } + } + } + + __exports__.cast = cast; + __exports__.Promise = Promise; + __exports__.EventTarget = EventTarget; + __exports__.all = all; + __exports__.allSettled = allSettled; + __exports__.race = race; + __exports__.hash = hash; + __exports__.hashSettled = hashSettled; + __exports__.rethrow = rethrow; + __exports__.defer = defer; + __exports__.denodeify = denodeify; + __exports__.configure = configure; + __exports__.on = on; + __exports__.off = off; + __exports__.resolve = resolve; + __exports__.reject = reject; + __exports__.async = async; + __exports__.map = map; + __exports__.filter = filter; + }); +define("rsvp.umd", + ["./rsvp"], + function(__dependency1__) { + "use strict"; + var Promise = __dependency1__.Promise; + var allSettled = __dependency1__.allSettled; + var hash = __dependency1__.hash; + var hashSettled = __dependency1__.hashSettled; + var denodeify = __dependency1__.denodeify; + var on = __dependency1__.on; + var off = __dependency1__.off; + var map = __dependency1__.map; + var filter = __dependency1__.filter; + var resolve = __dependency1__.resolve; + var reject = __dependency1__.reject; + var rethrow = __dependency1__.rethrow; + var all = __dependency1__.all; + var defer = __dependency1__.defer; + var EventTarget = __dependency1__.EventTarget; + var configure = __dependency1__.configure; + var race = __dependency1__.race; + var async = __dependency1__.async; + + var RSVP = { + 'race': race, + 'Promise': Promise, + 'allSettled': allSettled, + 'hash': hash, + 'hashSettled': hashSettled, + 'denodeify': denodeify, + 'on': on, + 'off': off, + 'map': map, + 'filter': filter, + 'resolve': resolve, + 'reject': reject, + 'all': all, + 'rethrow': rethrow, + 'defer': defer, + 'EventTarget': EventTarget, + 'configure': configure, + 'async': async + }; + + /* global define:true module:true window: true */ + if (typeof define === 'function' && define['amd']) { + define(function() { return RSVP; }); + } else if (typeof module !== 'undefined' && module['exports']) { + module['exports'] = RSVP; + } else if (typeof this !== 'undefined') { + this['RSVP'] = RSVP; + } + }); +define("rsvp/-internal", + ["./utils","./instrument","./config","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var objectOrFunction = __dependency1__.objectOrFunction; + var isFunction = __dependency1__.isFunction; + + var instrument = __dependency2__["default"]; + + var config = __dependency3__.config; + + function withOwnPromise() { + return new TypeError('A promises callback cannot return that same promise.'); + } + + function noop() {} + + var PENDING = void 0; + var FULFILLED = 1; + var REJECTED = 2; + + var GET_THEN_ERROR = new ErrorObject(); + + function getThen(promise) { + try { + return promise.then; + } catch(error) { + GET_THEN_ERROR.error = error; + return GET_THEN_ERROR; + } + } + + function tryThen(then, value, fulfillmentHandler, rejectionHandler) { + try { + then.call(value, fulfillmentHandler, rejectionHandler); + } catch(e) { + return e; + } + } + + function handleForeignThenable(promise, thenable, then) { + config.async(function(promise) { + var sealed = false; + var error = tryThen(then, thenable, function(value) { + if (sealed) { return; } + sealed = true; + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function(reason) { + if (sealed) { return; } + sealed = true; + + reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + reject(promise, error); + } + }, promise); + } + + function handleOwnThenable(promise, thenable) { + if (thenable._state === FULFILLED) { + fulfill(promise, thenable._result); + } else if (promise._state === REJECTED) { + reject(promise, thenable._result); + } else { + subscribe(thenable, undefined, function(value) { + if (thenable !== value) { + resolve(promise, value); + } else { + fulfill(promise, value); + } + }, function(reason) { + reject(promise, reason); + }); + } + } + + function handleMaybeThenable(promise, maybeThenable) { + if (maybeThenable.constructor === promise.constructor) { + handleOwnThenable(promise, maybeThenable); + } else { + var then = getThen(maybeThenable); + + if (then === GET_THEN_ERROR) { + reject(promise, GET_THEN_ERROR.error); + } else if (then === undefined) { + fulfill(promise, maybeThenable); + } else if (isFunction(then)) { + handleForeignThenable(promise, maybeThenable, then); + } else { + fulfill(promise, maybeThenable); + } + } + } + + function resolve(promise, value) { + if (promise === value) { + fulfill(promise, value); + } else if (objectOrFunction(value)) { + handleMaybeThenable(promise, value); + } else { + fulfill(promise, value); + } + } + + function publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + publish(promise); + } + + function fulfill(promise, value) { + if (promise._state !== PENDING) { return; } + + promise._result = value; + promise._state = FULFILLED; + + if (promise._subscribers.length === 0) { + if (config.instrument) { + instrument('fulfilled', promise); + } + } else { + config.async(publish, promise); + } + } + + function reject(promise, reason) { + if (promise._state !== PENDING) { return; } + promise._state = REJECTED; + promise._result = reason; + + config.async(publishRejection, promise); + } + + function subscribe(parent, child, onFulfillment, onRejection) { + var subscribers = parent._subscribers; + var length = subscribers.length; + + parent._onerror = null; + + subscribers[length] = child; + subscribers[length + FULFILLED] = onFulfillment; + subscribers[length + REJECTED] = onRejection; + + if (length === 0 && parent._state) { + config.async(publish, parent); + } + } + + function publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (config.instrument) { + instrument(settled === FULFILLED ? 'fulfilled' : 'rejected', promise); + } + + if (subscribers.length === 0) { return; } + + var child, callback, detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; + } + + function ErrorObject() { + this.error = null; + } + + var TRY_CATCH_ERROR = new ErrorObject(); + + function tryCatch(callback, detail) { + try { + return callback(detail); + } catch(e) { + TRY_CATCH_ERROR.error = e; + return TRY_CATCH_ERROR; + } + } + + function invokeCallback(settled, promise, callback, detail) { + var hasCallback = isFunction(callback), + value, error, succeeded, failed; + + if (hasCallback) { + value = tryCatch(callback, detail); + + if (value === TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value = null; + } else { + succeeded = true; + } + + if (promise === value) { + reject(promise, withOwnPromise()); + return; + } + + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== PENDING) { + // noop + } else if (hasCallback && succeeded) { + resolve(promise, value); + } else if (failed) { + reject(promise, error); + } else if (settled === FULFILLED) { + fulfill(promise, value); + } else if (settled === REJECTED) { + reject(promise, value); + } + } + + function initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value){ + resolve(promise, value); + }, function rejectPromise(reason) { + reject(promise, reason); + }); + } catch(e) { + reject(promise, e); + } + } + + __exports__.noop = noop; + __exports__.resolve = resolve; + __exports__.reject = reject; + __exports__.fulfill = fulfill; + __exports__.subscribe = subscribe; + __exports__.publish = publish; + __exports__.publishRejection = publishRejection; + __exports__.initializePromise = initializePromise; + __exports__.invokeCallback = invokeCallback; + __exports__.FULFILLED = FULFILLED; + __exports__.REJECTED = REJECTED; + __exports__.PENDING = PENDING; + }); +define("rsvp/all-settled", + ["./enumerator","./promise","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + var makeSettledResult = __dependency1__.makeSettledResult; + var Promise = __dependency2__["default"]; + var o_create = __dependency3__.o_create; + + function AllSettled(Constructor, entries, label) { + this._superConstructor(Constructor, entries, false /* don't abort on reject */, label); + } + + AllSettled.prototype = o_create(Enumerator.prototype); + AllSettled.prototype._superConstructor = Enumerator; + AllSettled.prototype._makeResult = makeSettledResult; + AllSettled.prototype._validationError = function() { + return new Error('allSettled must be called with an array'); + }; + + /** + `RSVP.allSettled` is similar to `RSVP.all`, but instead of implementing + a fail-fast method, it waits until all the promises have returned and + shows you all the results. This is useful if you want to handle multiple + promises' failure states together as a set. + + Returns a promise that is fulfilled when all the given promises have been + settled. The return promise is fulfilled with an array of the states of + the promises passed into the `promises` array argument. + + Each state object will either indicate fulfillment or rejection, and + provide the corresponding value or reason. The states will take one of + the following formats: + + ```javascript + { state: 'fulfilled', value: value } + or + { state: 'rejected', reason: reason } + ``` + + Example: + + ```javascript + var promise1 = RSVP.Promise.resolve(1); + var promise2 = RSVP.Promise.reject(new Error('2')); + var promise3 = RSVP.Promise.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.allSettled(promises).then(function(array){ + // array == [ + // { state: 'fulfilled', value: 1 }, + // { state: 'rejected', reason: Error }, + // { state: 'rejected', reason: Error } + // ] + // Note that for the second item, reason.message will be '2', and for the + // third item, reason.message will be '3'. + }, function(error) { + // Not run. (This block would only be called if allSettled had failed, + // for instance if passed an incorrect argument type.) + }); + ``` + + @method allSettled + @static + @for RSVP + @param {Array} promises + @param {String} label - optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled with an array of the settled + states of the constituent promises. + */ + + __exports__["default"] = function allSettled(entries, label) { + return new AllSettled(Promise, entries, label).promise; + } + }); +define("rsvp/all", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.all`. + + @method all + @static + @for RSVP + @param {Array} array Array of promises. + @param {String} label An optional label. This is useful + for tooling. + */ + __exports__["default"] = function all(array, label) { + return Promise.all(array, label); + } + }); +define("rsvp/asap", + ["exports"], + function(__exports__) { + "use strict"; + var len = 0; + + __exports__["default"] = function asap(callback, arg) { + queue[len] = callback; + queue[len + 1] = arg; + len += 2; + if (len === 2) { + // If len is 1, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + scheduleFlush(); + } + } + + var browserWindow = (typeof window !== 'undefined') ? window : undefined + var browserGlobal = browserWindow || {}; + var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; + + // test for web worker but not in IE10 + var isWorker = typeof Uint8ClampedArray !== 'undefined' && + typeof importScripts !== 'undefined' && + typeof MessageChannel !== 'undefined'; + + // node + function useNextTick() { + return function() { + process.nextTick(flush); + }; + } + + // vertx + function useVertxTimer() { + return function() { + vertxNext(flush); + }; + } + + function useMutationObserver() { + var iterations = 0; + var observer = new BrowserMutationObserver(flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function() { + node.data = (iterations = ++iterations % 2); + }; + } + + // web worker + function useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = flush; + return function () { + channel.port2.postMessage(0); + }; + } + + function useSetTimeout() { + return function() { + setTimeout(flush, 1); + }; + } + + var queue = new Array(1000); + function flush() { + for (var i = 0; i < len; i+=2) { + var callback = queue[i]; + var arg = queue[i+1]; + + callback(arg); + + queue[i] = undefined; + queue[i+1] = undefined; + } + + len = 0; + } + + function attemptVertex() { + try { + var vertx = require('vertx'); + var vertxNext = vertx.runOnLoop || vertx.runOnContext; + return useVertxTimer(); + } catch(e) { + return useSetTimeout(); + } + } + + var scheduleFlush; + // Decide what async method to use to triggering processing of queued callbacks: + if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { + scheduleFlush = useNextTick(); + } else if (BrowserMutationObserver) { + scheduleFlush = useMutationObserver(); + } else if (isWorker) { + scheduleFlush = useMessageChannel(); + } else if (browserWindow === undefined && typeof require === 'function') { + scheduleFlush = attemptVertex(); + } else { + scheduleFlush = useSetTimeout(); + } + }); +define("rsvp/config", + ["./events","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var EventTarget = __dependency1__["default"]; + + var config = { + instrument: false + }; + + EventTarget.mixin(config); + + function configure(name, value) { + if (name === 'onerror') { + // handle for legacy users that expect the actual + // error to be passed to their function added via + // `RSVP.configure('onerror', someFunctionHere);` + config.on('error', value); + return; + } + + if (arguments.length === 2) { + config[name] = value; + } else { + return config[name]; + } + } + + __exports__.config = config; + __exports__.configure = configure; + }); +define("rsvp/defer", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + `RSVP.defer` returns an object similar to jQuery's `$.Deferred`. + `RSVP.defer` should be used when porting over code reliant on `$.Deferred`'s + interface. New code should use the `RSVP.Promise` constructor instead. + + The object returned from `RSVP.defer` is a plain object with three properties: + + * promise - an `RSVP.Promise`. + * reject - a function that causes the `promise` property on this object to + become rejected + * resolve - a function that causes the `promise` property on this object to + become fulfilled. + + Example: + + ```javascript + var deferred = RSVP.defer(); + + deferred.resolve("Success!"); + + defered.promise.then(function(value){ + // value here is "Success!" + }); + ``` + + @method defer + @static + @for RSVP + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Object} + */ + + __exports__["default"] = function defer(label) { + var deferred = { }; + + deferred['promise'] = new Promise(function(resolve, reject) { + deferred['resolve'] = resolve; + deferred['reject'] = reject; + }, label); + + return deferred; + } + }); +define("rsvp/enumerator", + ["./utils","./-internal","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var isArray = __dependency1__.isArray; + var isMaybeThenable = __dependency1__.isMaybeThenable; + + var noop = __dependency2__.noop; + var reject = __dependency2__.reject; + var fulfill = __dependency2__.fulfill; + var subscribe = __dependency2__.subscribe; + var FULFILLED = __dependency2__.FULFILLED; + var REJECTED = __dependency2__.REJECTED; + var PENDING = __dependency2__.PENDING; + + function makeSettledResult(state, position, value) { + if (state === FULFILLED) { + return { + state: 'fulfilled', + value: value + }; + } else { + return { + state: 'rejected', + reason: value + }; + } + } + + __exports__.makeSettledResult = makeSettledResult;function Enumerator(Constructor, input, abortOnReject, label) { + this._instanceConstructor = Constructor; + this.promise = new Constructor(noop, label); + this._abortOnReject = abortOnReject; + + if (this._validateInput(input)) { + this._input = input; + this.length = input.length; + this._remaining = input.length; + + this._init(); + + if (this.length === 0) { + fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(); + if (this._remaining === 0) { + fulfill(this.promise, this._result); + } + } + } else { + reject(this.promise, this._validationError()); + } + } + + Enumerator.prototype._validateInput = function(input) { + return isArray(input); + }; + + Enumerator.prototype._validationError = function() { + return new Error('Array Methods must be provided an Array'); + }; + + Enumerator.prototype._init = function() { + this._result = new Array(this.length); + }; + + __exports__["default"] = Enumerator; + + Enumerator.prototype._enumerate = function() { + var length = this.length; + var promise = this.promise; + var input = this._input; + + for (var i = 0; promise._state === PENDING && i < length; i++) { + this._eachEntry(input[i], i); + } + }; + + Enumerator.prototype._eachEntry = function(entry, i) { + var c = this._instanceConstructor; + if (isMaybeThenable(entry)) { + if (entry.constructor === c && entry._state !== PENDING) { + entry._onerror = null; + this._settledAt(entry._state, i, entry._result); + } else { + this._willSettleAt(c.resolve(entry), i); + } + } else { + this._remaining--; + this._result[i] = this._makeResult(FULFILLED, i, entry); + } + }; + + Enumerator.prototype._settledAt = function(state, i, value) { + var promise = this.promise; + + if (promise._state === PENDING) { + this._remaining--; + + if (this._abortOnReject && state === REJECTED) { + reject(promise, value); + } else { + this._result[i] = this._makeResult(state, i, value); + } + } + + if (this._remaining === 0) { + fulfill(promise, this._result); + } + }; + + Enumerator.prototype._makeResult = function(state, i, value) { + return value; + }; + + Enumerator.prototype._willSettleAt = function(promise, i) { + var enumerator = this; + + subscribe(promise, undefined, function(value) { + enumerator._settledAt(FULFILLED, i, value); + }, function(reason) { + enumerator._settledAt(REJECTED, i, reason); + }); + }; + }); +define("rsvp/events", + ["exports"], + function(__exports__) { + "use strict"; + function indexOf(callbacks, callback) { + for (var i=0, l=callbacks.length; i 1; + }; + + RSVP.filter(promises, filterFn).then(function(result){ + // result is [ 2, 3 ] + }); + ``` + + If any of the `promises` given to `RSVP.filter` are rejected, the first promise + that is rejected will be given as an argument to the returned promise's + rejection handler. For example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error('2')); + var promise3 = RSVP.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + var filterFn = function(item){ + return item > 1; + }; + + RSVP.filter(promises, filterFn).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === '2' + }); + ``` + + `RSVP.filter` will also wait for any promises returned from `filterFn`. + For instance, you may want to fetch a list of users then return a subset + of those users based on some asynchronous operation: + + ```javascript + + var alice = { name: 'alice' }; + var bob = { name: 'bob' }; + var users = [ alice, bob ]; + + var promises = users.map(function(user){ + return RSVP.resolve(user); + }); + + var filterFn = function(user){ + // Here, Alice has permissions to create a blog post, but Bob does not. + return getPrivilegesForUser(user).then(function(privs){ + return privs.can_create_blog_post === true; + }); + }; + RSVP.filter(promises, filterFn).then(function(users){ + // true, because the server told us only Alice can create a blog post. + users.length === 1; + // false, because Alice is the only user present in `users` + users[0] === bob; + }); + ``` + + @method filter + @static + @for RSVP + @param {Array} promises + @param {Function} filterFn - function to be called on each resolved value to + filter the final results. + @param {String} label optional string describing the promise. Useful for + tooling. + @return {Promise} + */ + __exports__["default"] = function filter(promises, filterFn, label) { + return Promise.all(promises, label).then(function(values) { + if (!isFunction(filterFn)) { + throw new TypeError("You must pass a function as filter's second argument."); + } + + var length = values.length; + var filtered = new Array(length); + + for (var i = 0; i < length; i++) { + filtered[i] = filterFn(values[i]); + } + + return Promise.all(filtered, label).then(function(filtered) { + var results = new Array(length); + var newLength = 0; + + for (var i = 0; i < length; i++) { + if (filtered[i]) { + results[newLength] = values[i]; + newLength++; + } + } + + results.length = newLength; + + return results; + }); + }); + } + }); +define("rsvp/hash-settled", + ["./promise","./enumerator","./promise-hash","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var makeSettledResult = __dependency2__.makeSettledResult; + var PromiseHash = __dependency3__["default"]; + var Enumerator = __dependency2__["default"]; + var o_create = __dependency4__.o_create; + + function HashSettled(Constructor, object, label) { + this._superConstructor(Constructor, object, false, label); + } + + HashSettled.prototype = o_create(PromiseHash.prototype); + HashSettled.prototype._superConstructor = Enumerator; + HashSettled.prototype._makeResult = makeSettledResult; + + HashSettled.prototype._validationError = function() { + return new Error('hashSettled must be called with an object'); + }; + + /** + `RSVP.hashSettled` is similar to `RSVP.allSettled`, but takes an object + instead of an array for its `promises` argument. + + Unlike `RSVP.all` or `RSVP.hash`, which implement a fail-fast method, + but like `RSVP.allSettled`, `hashSettled` waits until all the + constituent promises have returned and then shows you all the results + with their states and values/reasons. This is useful if you want to + handle multiple promises' failure states together as a set. + + Returns a promise that is fulfilled when all the given promises have been + settled, or rejected if the passed parameters are invalid. + + The returned promise is fulfilled with a hash that has the same key names as + the `promises` object argument. If any of the values in the object are not + promises, they will be copied over to the fulfilled object and marked with state + 'fulfilled'. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.Promise.resolve(1), + yourPromise: RSVP.Promise.resolve(2), + theirPromise: RSVP.Promise.resolve(3), + notAPromise: 4 + }; + + RSVP.hashSettled(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: { state: 'fulfilled', value: 1 }, + // yourPromise: { state: 'fulfilled', value: 2 }, + // theirPromise: { state: 'fulfilled', value: 3 }, + // notAPromise: { state: 'fulfilled', value: 4 } + // } + }); + ``` + + If any of the `promises` given to `RSVP.hash` are rejected, the state will + be set to 'rejected' and the reason for rejection provided. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.Promise.resolve(1), + rejectedPromise: RSVP.Promise.reject(new Error('rejection')), + anotherRejectedPromise: RSVP.Promise.reject(new Error('more rejection')), + }; + + RSVP.hashSettled(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: { state: 'fulfilled', value: 1 }, + // rejectedPromise: { state: 'rejected', reason: Error }, + // anotherRejectedPromise: { state: 'rejected', reason: Error }, + // } + // Note that for rejectedPromise, reason.message == 'rejection', + // and for anotherRejectedPromise, reason.message == 'more rejection'. + }); + ``` + + An important note: `RSVP.hashSettled` is intended for plain JavaScript objects that + are just a set of keys and values. `RSVP.hashSettled` will NOT preserve prototype + chains. + + Example: + + ```javascript + function MyConstructor(){ + this.example = RSVP.Promise.resolve('Example'); + } + + MyConstructor.prototype = { + protoProperty: RSVP.Promise.resolve('Proto Property') + }; + + var myObject = new MyConstructor(); + + RSVP.hashSettled(myObject).then(function(hash){ + // protoProperty will not be present, instead you will just have an + // object that looks like: + // { + // example: { state: 'fulfilled', value: 'Example' } + // } + // + // hash.hasOwnProperty('protoProperty'); // false + // 'undefined' === typeof hash.protoProperty + }); + ``` + + @method hashSettled + @for RSVP + @param {Object} promises + @param {String} label optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when when all properties of `promises` + have been settled. + @static + */ + __exports__["default"] = function hashSettled(object, label) { + return new HashSettled(Promise, object, label).promise; + } + }); +define("rsvp/hash", + ["./promise","./promise-hash","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var PromiseHash = __dependency2__["default"]; + + /** + `RSVP.hash` is similar to `RSVP.all`, but takes an object instead of an array + for its `promises` argument. + + Returns a promise that is fulfilled when all the given promises have been + fulfilled, or rejected if any of them become rejected. The returned promise + is fulfilled with a hash that has the same key names as the `promises` object + argument. If any of the values in the object are not promises, they will + simply be copied over to the fulfilled object. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.resolve(1), + yourPromise: RSVP.resolve(2), + theirPromise: RSVP.resolve(3), + notAPromise: 4 + }; + + RSVP.hash(promises).then(function(hash){ + // hash here is an object that looks like: + // { + // myPromise: 1, + // yourPromise: 2, + // theirPromise: 3, + // notAPromise: 4 + // } + }); + ```` + + If any of the `promises` given to `RSVP.hash` are rejected, the first promise + that is rejected will be given as the reason to the rejection handler. + + Example: + + ```javascript + var promises = { + myPromise: RSVP.resolve(1), + rejectedPromise: RSVP.reject(new Error('rejectedPromise')), + anotherRejectedPromise: RSVP.reject(new Error('anotherRejectedPromise')), + }; + + RSVP.hash(promises).then(function(hash){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === 'rejectedPromise' + }); + ``` + + An important note: `RSVP.hash` is intended for plain JavaScript objects that + are just a set of keys and values. `RSVP.hash` will NOT preserve prototype + chains. + + Example: + + ```javascript + function MyConstructor(){ + this.example = RSVP.resolve('Example'); + } + + MyConstructor.prototype = { + protoProperty: RSVP.resolve('Proto Property') + }; + + var myObject = new MyConstructor(); + + RSVP.hash(myObject).then(function(hash){ + // protoProperty will not be present, instead you will just have an + // object that looks like: + // { + // example: 'Example' + // } + // + // hash.hasOwnProperty('protoProperty'); // false + // 'undefined' === typeof hash.protoProperty + }); + ``` + + @method hash + @static + @for RSVP + @param {Object} promises + @param {String} label optional string that describes the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all properties of `promises` + have been fulfilled, or rejected if any of them become rejected. + */ + __exports__["default"] = function hash(object, label) { + return new PromiseHash(Promise, object, label).promise; + } + }); +define("rsvp/instrument", + ["./config","./utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var now = __dependency2__.now; + + var queue = []; + + function scheduleFlush() { + setTimeout(function() { + var entry; + for (var i = 0; i < queue.length; i++) { + entry = queue[i]; + + var payload = entry.payload; + + payload.guid = payload.key + payload.id; + payload.childGuid = payload.key + payload.childId; + if (payload.error) { + payload.stack = payload.error.stack; + } + + config.trigger(entry.name, entry.payload); + } + queue.length = 0; + }, 50); + } + + __exports__["default"] = function instrument(eventName, promise, child) { + if (1 === queue.push({ + name: eventName, + payload: { + key: promise._guidKey, + id: promise._id, + eventName: eventName, + detail: promise._result, + childId: child && child._id, + label: promise._label, + timeStamp: now(), + error: config["instrument-with-stack"] ? new Error(promise._label) : null + }})) { + scheduleFlush(); + } + } + }); +define("rsvp/map", + ["./promise","./utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var isFunction = __dependency2__.isFunction; + + /** + `RSVP.map` is similar to JavaScript's native `map` method, except that it + waits for all promises to become fulfilled before running the `mapFn` on + each item in given to `promises`. `RSVP.map` returns a promise that will + become fulfilled with the result of running `mapFn` on the values the promises + become fulfilled with. + + For example: + + ```javascript + + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.resolve(2); + var promise3 = RSVP.resolve(3); + var promises = [ promise1, promise2, promise3 ]; + + var mapFn = function(item){ + return item + 1; + }; + + RSVP.map(promises, mapFn).then(function(result){ + // result is [ 2, 3, 4 ] + }); + ``` + + If any of the `promises` given to `RSVP.map` are rejected, the first promise + that is rejected will be given as an argument to the returned promise's + rejection handler. For example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error('2')); + var promise3 = RSVP.reject(new Error('3')); + var promises = [ promise1, promise2, promise3 ]; + + var mapFn = function(item){ + return item + 1; + }; + + RSVP.map(promises, mapFn).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(reason) { + // reason.message === '2' + }); + ``` + + `RSVP.map` will also wait if a promise is returned from `mapFn`. For example, + say you want to get all comments from a set of blog posts, but you need + the blog posts first because they contain a url to those comments. + + ```javscript + + var mapFn = function(blogPost){ + // getComments does some ajax and returns an RSVP.Promise that is fulfilled + // with some comments data + return getComments(blogPost.comments_url); + }; + + // getBlogPosts does some ajax and returns an RSVP.Promise that is fulfilled + // with some blog post data + RSVP.map(getBlogPosts(), mapFn).then(function(comments){ + // comments is the result of asking the server for the comments + // of all blog posts returned from getBlogPosts() + }); + ``` + + @method map + @static + @for RSVP + @param {Array} promises + @param {Function} mapFn function to be called on each fulfilled promise. + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled with the result of calling + `mapFn` on each fulfilled promise or value when they become fulfilled. + The promise will be rejected if any of the given `promises` become rejected. + @static + */ + __exports__["default"] = function map(promises, mapFn, label) { + return Promise.all(promises, label).then(function(values) { + if (!isFunction(mapFn)) { + throw new TypeError("You must pass a function as map's second argument."); + } + + var length = values.length; + var results = new Array(length); + + for (var i = 0; i < length; i++) { + results[i] = mapFn(values[i]); + } + + return Promise.all(results, label); + }); + } + }); +define("rsvp/node", + ["./promise","./-internal","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + var noop = __dependency2__.noop; + var resolve = __dependency2__.resolve; + var reject = __dependency2__.reject; + var isArray = __dependency3__.isArray; + + function Result() { + this.value = undefined; + } + + var ERROR = new Result(); + var GET_THEN_ERROR = new Result(); + + function getThen(obj) { + try { + return obj.then; + } catch(error) { + ERROR.value= error; + return ERROR; + } + } + + + function tryApply(f, s, a) { + try { + f.apply(s, a); + } catch(error) { + ERROR.value = error; + return ERROR; + } + } + + function makeObject(_, argumentNames) { + var obj = {}; + var name; + var i; + var length = _.length; + var args = new Array(length); + + for (var x = 0; x < length; x++) { + args[x] = _[x]; + } + + for (i = 0; i < argumentNames.length; i++) { + name = argumentNames[i]; + obj[name] = args[i + 1]; + } + + return obj; + } + + function arrayResult(_) { + var length = _.length; + var args = new Array(length - 1); + + for (var i = 1; i < length; i++) { + args[i - 1] = _[i]; + } + + return args; + } + + function wrapThenable(then, promise) { + return { + then: function(onFulFillment, onRejection) { + return then.call(promise, onFulFillment, onRejection); + } + }; + } + + /** + `RSVP.denodeify` takes a 'node-style' function and returns a function that + will return an `RSVP.Promise`. You can use `denodeify` in Node.js or the + browser when you'd prefer to use promises over using callbacks. For example, + `denodeify` transforms the following: + + ```javascript + var fs = require('fs'); + + fs.readFile('myfile.txt', function(err, data){ + if (err) return handleError(err); + handleData(data); + }); + ``` + + into: + + ```javascript + var fs = require('fs'); + var readFile = RSVP.denodeify(fs.readFile); + + readFile('myfile.txt').then(handleData, handleError); + ``` + + If the node function has multiple success parameters, then `denodeify` + just returns the first one: + + ```javascript + var request = RSVP.denodeify(require('request')); + + request('http://example.com').then(function(res) { + // ... + }); + ``` + + However, if you need all success parameters, setting `denodeify`'s + second parameter to `true` causes it to return all success parameters + as an array: + + ```javascript + var request = RSVP.denodeify(require('request'), true); + + request('http://example.com').then(function(result) { + // result[0] -> res + // result[1] -> body + }); + ``` + + Or if you pass it an array with names it returns the parameters as a hash: + + ```javascript + var request = RSVP.denodeify(require('request'), ['res', 'body']); + + request('http://example.com').then(function(result) { + // result.res + // result.body + }); + ``` + + Sometimes you need to retain the `this`: + + ```javascript + var app = require('express')(); + var render = RSVP.denodeify(app.render.bind(app)); + ``` + + The denodified function inherits from the original function. It works in all + environments, except IE 10 and below. Consequently all properties of the original + function are available to you. However, any properties you change on the + denodeified function won't be changed on the original function. Example: + + ```javascript + var request = RSVP.denodeify(require('request')), + cookieJar = request.jar(); // <- Inheritance is used here + + request('http://example.com', {jar: cookieJar}).then(function(res) { + // cookieJar.cookies holds now the cookies returned by example.com + }); + ``` + + Using `denodeify` makes it easier to compose asynchronous operations instead + of using callbacks. For example, instead of: + + ```javascript + var fs = require('fs'); + + fs.readFile('myfile.txt', function(err, data){ + if (err) { ... } // Handle error + fs.writeFile('myfile2.txt', data, function(err){ + if (err) { ... } // Handle error + console.log('done') + }); + }); + ``` + + you can chain the operations together using `then` from the returned promise: + + ```javascript + var fs = require('fs'); + var readFile = RSVP.denodeify(fs.readFile); + var writeFile = RSVP.denodeify(fs.writeFile); + + readFile('myfile.txt').then(function(data){ + return writeFile('myfile2.txt', data); + }).then(function(){ + console.log('done') + }).catch(function(error){ + // Handle error + }); + ``` + + @method denodeify + @static + @for RSVP + @param {Function} nodeFunc a 'node-style' function that takes a callback as + its last argument. The callback expects an error to be passed as its first + argument (if an error occurred, otherwise null), and the value from the + operation as its second argument ('function(err, value){ }'). + @param {Boolean|Array} argumentNames An optional paramter that if set + to `true` causes the promise to fulfill with the callback's success arguments + as an array. This is useful if the node function has multiple success + paramters. If you set this paramter to an array with names, the promise will + fulfill with a hash with these names as keys and the success parameters as + values. + @return {Function} a function that wraps `nodeFunc` to return an + `RSVP.Promise` + @static + */ + __exports__["default"] = function denodeify(nodeFunc, options) { + var fn = function() { + var self = this; + var l = arguments.length; + var args = new Array(l + 1); + var arg; + var promiseInput = false; + + for (var i = 0; i < l; ++i) { + arg = arguments[i]; + + if (!promiseInput) { + // TODO: clean this up + promiseInput = needsPromiseInput(arg); + if (promiseInput === GET_THEN_ERROR) { + var p = new Promise(noop); + reject(p, GET_THEN_ERROR.value); + return p; + } else if (promiseInput && promiseInput !== true) { + arg = wrapThenable(promiseInput, arg); + } + } + args[i] = arg; + } + + var promise = new Promise(noop); + + args[l] = function(err, val) { + if (err) + reject(promise, err); + else if (options === undefined) + resolve(promise, val); + else if (options === true) + resolve(promise, arrayResult(arguments)); + else if (isArray(options)) + resolve(promise, makeObject(arguments, options)); + else + resolve(promise, val); + }; + + if (promiseInput) { + return handlePromiseInput(promise, args, nodeFunc, self); + } else { + return handleValueInput(promise, args, nodeFunc, self); + } + }; + + fn.__proto__ = nodeFunc; + + return fn; + } + + function handleValueInput(promise, args, nodeFunc, self) { + var result = tryApply(nodeFunc, self, args); + if (result === ERROR) { + reject(promise, result.value); + } + return promise; + } + + function handlePromiseInput(promise, args, nodeFunc, self){ + return Promise.all(args).then(function(args){ + var result = tryApply(nodeFunc, self, args); + if (result === ERROR) { + reject(promise, result.value); + } + return promise; + }); + } + + function needsPromiseInput(arg) { + if (arg && typeof arg === 'object') { + if (arg.constructor === Promise) { + return true; + } else { + return getThen(arg); + } + } else { + return false; + } + } + }); +define("rsvp/promise-hash", + ["./enumerator","./-internal","./utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + var PENDING = __dependency2__.PENDING; + var o_create = __dependency3__.o_create; + + function PromiseHash(Constructor, object, label) { + this._superConstructor(Constructor, object, true, label); + } + + __exports__["default"] = PromiseHash; + + PromiseHash.prototype = o_create(Enumerator.prototype); + PromiseHash.prototype._superConstructor = Enumerator; + PromiseHash.prototype._init = function() { + this._result = {}; + }; + + PromiseHash.prototype._validateInput = function(input) { + return input && typeof input === 'object'; + }; + + PromiseHash.prototype._validationError = function() { + return new Error('Promise.hash must be called with an object'); + }; + + PromiseHash.prototype._enumerate = function() { + var promise = this.promise; + var input = this._input; + var results = []; + + for (var key in input) { + if (promise._state === PENDING && input.hasOwnProperty(key)) { + results.push({ + position: key, + entry: input[key] + }); + } + } + + var length = results.length; + this._remaining = length; + var result; + + for (var i = 0; promise._state === PENDING && i < length; i++) { + result = results[i]; + this._eachEntry(result.entry, result.position); + } + }; + }); +define("rsvp/promise", + ["./config","./instrument","./utils","./-internal","./promise/all","./promise/race","./promise/resolve","./promise/reject","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { + "use strict"; + var config = __dependency1__.config; + var instrument = __dependency2__["default"]; + + var isFunction = __dependency3__.isFunction; + var now = __dependency3__.now; + + var noop = __dependency4__.noop; + var subscribe = __dependency4__.subscribe; + var initializePromise = __dependency4__.initializePromise; + var invokeCallback = __dependency4__.invokeCallback; + var FULFILLED = __dependency4__.FULFILLED; + var REJECTED = __dependency4__.REJECTED; + + var all = __dependency5__["default"]; + var race = __dependency6__["default"]; + var Resolve = __dependency7__["default"]; + var Reject = __dependency8__["default"]; + + var guidKey = 'rsvp_' + now() + '-'; + var counter = 0; + + function needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); + } + + function needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); + } + __exports__["default"] = Promise; + /** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise’s eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + var promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + var xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class RSVP.Promise + @param {function} resolver + @param {String} label optional string for labeling the promise. + Useful for tooling. + @constructor + */ + function Promise(resolver, label) { + this._id = counter++; + this._label = label; + this._state = undefined; + this._result = undefined; + this._subscribers = []; + + if (config.instrument) { + instrument('created', this); + } + + if (noop !== resolver) { + if (!isFunction(resolver)) { + needsResolver(); + } + + if (!(this instanceof Promise)) { + needsNew(); + } + + initializePromise(this, resolver); + } + } + + Promise.cast = Resolve; // deprecated + Promise.all = all; + Promise.race = race; + Promise.resolve = Resolve; + Promise.reject = Reject; + + Promise.prototype = { + constructor: Promise, + + _guidKey: guidKey, + + _onerror: function (reason) { + config.trigger('error', reason); + }, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + var result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + var author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + then: function(onFulfillment, onRejection, label) { + var parent = this; + var state = parent._state; + + if (state === FULFILLED && !onFulfillment || state === REJECTED && !onRejection) { + if (config.instrument) { + instrument('chained', this, this); + } + return this; + } + + parent._onerror = null; + + var child = new this.constructor(noop, label); + var result = parent._result; + + if (config.instrument) { + instrument('chained', parent, child); + } + + if (state) { + var callback = arguments[state - 1]; + config.async(function(){ + invokeCallback(state, child, callback, result); + }); + } else { + subscribe(parent, child, onFulfillment, onRejection); + } + + return child; + }, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + 'catch': function(onRejection, label) { + return this.then(null, onRejection, label); + }, + + /** + `finally` will be invoked regardless of the promise's fate just as native + try/catch/finally behaves + + Synchronous example: + + ```js + findAuthor() { + if (Math.random() > 0.5) { + throw new Error(); + } + return new Author(); + } + + try { + return findAuthor(); // succeed or fail + } catch(error) { + return findOtherAuther(); + } finally { + // always runs + // doesn't affect the return value + } + ``` + + Asynchronous example: + + ```js + findAuthor().catch(function(reason){ + return findOtherAuther(); + }).finally(function(){ + // author was either found, or not + }); + ``` + + @method finally + @param {Function} callback + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} + */ + 'finally': function(callback, label) { + var constructor = this.constructor; + + return this.then(function(value) { + return constructor.resolve(callback()).then(function(){ + return value; + }); + }, function(reason) { + return constructor.resolve(callback()).then(function(){ + throw reason; + }); + }, label); + } + }; + }); +define("rsvp/promise/all", + ["../enumerator","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Enumerator = __dependency1__["default"]; + + /** + `RSVP.Promise.all` accepts an array of promises, and returns a new promise which + is fulfilled with an array of fulfillment values for the passed promises, or + rejected with the reason of the first passed promise to be rejected. It casts all + elements of the passed iterable to promises as it runs this algorithm. + + Example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.resolve(2); + var promise3 = RSVP.resolve(3); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.Promise.all(promises).then(function(array){ + // The array here would be [ 1, 2, 3 ]; + }); + ``` + + If any of the `promises` given to `RSVP.all` are rejected, the first promise + that is rejected will be given as an argument to the returned promises's + rejection handler. For example: + + Example: + + ```javascript + var promise1 = RSVP.resolve(1); + var promise2 = RSVP.reject(new Error("2")); + var promise3 = RSVP.reject(new Error("3")); + var promises = [ promise1, promise2, promise3 ]; + + RSVP.Promise.all(promises).then(function(array){ + // Code here never runs because there are rejected promises! + }, function(error) { + // error.message === "2" + }); + ``` + + @method all + @static + @param {Array} entries array of promises + @param {String} label optional string for labeling the promise. + Useful for tooling. + @return {Promise} promise that is fulfilled when all `promises` have been + fulfilled, or rejected if any of them become rejected. + @static + */ + __exports__["default"] = function all(entries, label) { + return new Enumerator(this, entries, true /* abort on reject */, label).promise; + } + }); +define("rsvp/promise/race", + ["../utils","../-internal","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + var isArray = __dependency1__.isArray; + + var noop = __dependency2__.noop; + var resolve = __dependency2__.resolve; + var reject = __dependency2__.reject; + var subscribe = __dependency2__.subscribe; + var PENDING = __dependency2__.PENDING; + + /** + `RSVP.Promise.race` returns a new promise which is settled in the same way as the + first passed promise to settle. + + Example: + + ```javascript + var promise1 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + var promise2 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 2'); + }, 100); + }); + + RSVP.Promise.race([promise1, promise2]).then(function(result){ + // result === 'promise 2' because it was resolved before promise1 + // was resolved. + }); + ``` + + `RSVP.Promise.race` is deterministic in that only the state of the first + settled promise matters. For example, even if other promises given to the + `promises` array argument are resolved, but the first settled promise has + become rejected before the other promises became fulfilled, the returned + promise will become rejected: + + ```javascript + var promise1 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + resolve('promise 1'); + }, 200); + }); + + var promise2 = new RSVP.Promise(function(resolve, reject){ + setTimeout(function(){ + reject(new Error('promise 2')); + }, 100); + }); + + RSVP.Promise.race([promise1, promise2]).then(function(result){ + // Code here never runs + }, function(reason){ + // reason.message === 'promise 2' because promise 2 became rejected before + // promise 1 became fulfilled + }); + ``` + + An example real-world use case is implementing timeouts: + + ```javascript + RSVP.Promise.race([ajax('foo.json'), timeout(5000)]) + ``` + + @method race + @static + @param {Array} promises array of promises to observe + @param {String} label optional string for describing the promise returned. + Useful for tooling. + @return {Promise} a promise which settles in the same way as the first passed + promise to settle. + */ + __exports__["default"] = function race(entries, label) { + /*jshint validthis:true */ + var Constructor = this; + + var promise = new Constructor(noop, label); + + if (!isArray(entries)) { + reject(promise, new TypeError('You must pass an array to race.')); + return promise; + } + + var length = entries.length; + + function onFulfillment(value) { + resolve(promise, value); + } + + function onRejection(reason) { + reject(promise, reason); + } + + for (var i = 0; promise._state === PENDING && i < length; i++) { + subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); + } + + return promise; + } + }); +define("rsvp/promise/reject", + ["../-internal","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var noop = __dependency1__.noop; + var _reject = __dependency1__.reject; + + /** + `RSVP.Promise.reject` returns a promise rejected with the passed `reason`. + It is shorthand for the following: + + ```javascript + var promise = new RSVP.Promise(function(resolve, reject){ + reject(new Error('WHOOPS')); + }); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + var promise = RSVP.Promise.reject(new Error('WHOOPS')); + + promise.then(function(value){ + // Code here doesn't run because the promise is rejected! + }, function(reason){ + // reason.message === 'WHOOPS' + }); + ``` + + @method reject + @static + @param {Any} reason value that the returned promise will be rejected with. + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. + */ + __exports__["default"] = function reject(reason, label) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(noop, label); + _reject(promise, reason); + return promise; + } + }); +define("rsvp/promise/resolve", + ["../-internal","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var noop = __dependency1__.noop; + var _resolve = __dependency1__.resolve; + + /** + `RSVP.Promise.resolve` returns a promise that will become resolved with the + passed `value`. It is shorthand for the following: + + ```javascript + var promise = new RSVP.Promise(function(resolve, reject){ + resolve(1); + }); + + promise.then(function(value){ + // value === 1 + }); + ``` + + Instead of writing the above, your code now simply becomes the following: + + ```javascript + var promise = RSVP.Promise.resolve(1); + + promise.then(function(value){ + // value === 1 + }); + ``` + + @method resolve + @static + @param {Any} value value that the returned promise will be resolved with + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` + */ + __exports__["default"] = function resolve(object, label) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(noop, label); + _resolve(promise, object); + return promise; + } + }); +define("rsvp/race", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.race`. + + @method race + @static + @for RSVP + @param {Array} array Array of promises. + @param {String} label An optional label. This is useful + for tooling. + */ + __exports__["default"] = function race(array, label) { + return Promise.race(array, label); + } + }); +define("rsvp/reject", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.reject`. + + @method reject + @static + @for RSVP + @param {Any} reason value that the returned promise will be rejected with. + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise rejected with the given `reason`. + */ + __exports__["default"] = function reject(reason, label) { + return Promise.reject(reason, label); + } + }); +define("rsvp/resolve", + ["./promise","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Promise = __dependency1__["default"]; + + /** + This is a convenient alias for `RSVP.Promise.resolve`. + + @method resolve + @static + @for RSVP + @param {Any} value value that the returned promise will be resolved with + @param {String} label optional string for identifying the returned promise. + Useful for tooling. + @return {Promise} a promise that will become fulfilled with the given + `value` + */ + __exports__["default"] = function resolve(value, label) { + return Promise.resolve(value, label); + } + }); +define("rsvp/rethrow", + ["exports"], + function(__exports__) { + "use strict"; + /** + `RSVP.rethrow` will rethrow an error on the next turn of the JavaScript event + loop in order to aid debugging. + + Promises A+ specifies that any exceptions that occur with a promise must be + caught by the promises implementation and bubbled to the last handler. For + this reason, it is recommended that you always specify a second rejection + handler function to `then`. However, `RSVP.rethrow` will throw the exception + outside of the promise, so it bubbles up to your console if in the browser, + or domain/cause uncaught exception in Node. `rethrow` will also throw the + error again so the error can be handled by the promise per the spec. + + ```javascript + function throws(){ + throw new Error('Whoops!'); + } + + var promise = new RSVP.Promise(function(resolve, reject){ + throws(); + }); + + promise.catch(RSVP.rethrow).then(function(){ + // Code here doesn't run because the promise became rejected due to an + // error! + }, function (err){ + // handle the error here + }); + ``` + + The 'Whoops' error will be thrown on the next turn of the event loop + and you can watch for it in your console. You can also handle it using a + rejection handler given to `.then` or `.catch` on the returned promise. + + @method rethrow + @static + @for RSVP + @param {Error} reason reason the promise became rejected. + @throws Error + @static + */ + __exports__["default"] = function rethrow(reason) { + setTimeout(function() { + throw reason; + }); + throw reason; + } + }); +define("rsvp/utils", + ["exports"], + function(__exports__) { + "use strict"; + function objectOrFunction(x) { + return typeof x === 'function' || (typeof x === 'object' && x !== null); + } + + __exports__.objectOrFunction = objectOrFunction;function isFunction(x) { + return typeof x === 'function'; + } + + __exports__.isFunction = isFunction;function isMaybeThenable(x) { + return typeof x === 'object' && x !== null; + } + + __exports__.isMaybeThenable = isMaybeThenable;var _isArray; + if (!Array.isArray) { + _isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; + } else { + _isArray = Array.isArray; + } + + var isArray = _isArray; + __exports__.isArray = isArray; + // Date.now is not available in browsers < IE9 + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility + var now = Date.now || function() { return new Date().getTime(); }; + __exports__.now = now; + function F() { } + + var o_create = (Object.create || function (o) { + if (arguments.length > 1) { + throw new Error('Second argument not supported'); + } + if (typeof o !== 'object') { + throw new TypeError('Argument must be an object'); + } + F.prototype = o; + return new F(); + }); + __exports__.o_create = o_create; + }); +requireModule("ember"); + +})(); \ No newline at end of file