diff --git a/Gemfile b/Gemfile index 443cba64..c63e57e4 100644 --- a/Gemfile +++ b/Gemfile @@ -49,6 +49,9 @@ gem 'kaminari' gem 'rqrcode' gem 'mini_magick' + +#gem 'geokit' +#gem 'iso_country_codes' #gem "less-rails-bootstrap-devise", :git => 'git://github.com/bigbento/less-rails-bootstrap-devise.git' # To use ActiveModel has_secure_password diff --git a/app/models/product_category.rb b/app/models/product_category.rb index bcfc11ce..2293bd9f 100644 --- a/app/models/product_category.rb +++ b/app/models/product_category.rb @@ -64,7 +64,6 @@ class ProductCategory h = {table_number: table.number, table_occupied: table.occupied?, supplier_name: supplier.name, my_list: list.try(:user_ids).to_a.include?(user.id)} #(products - product_categories.map(&:products).flatten).each{ |p| other.add_product(p) } - h[:categories] = product_categories.map(&:to_client_format).select(&:present?) h end diff --git a/app/views/supplier/edit.html.slim b/app/views/supplier/edit.html.slim index e73905bb..61928ac5 100644 --- a/app/views/supplier/edit.html.slim +++ b/app/views/supplier/edit.html.slim @@ -26,7 +26,8 @@ = f.label :time_zone, class: 'control-label' .controls /= f.input :time_zone, collection: ActiveSupport::TimeZone.all, label_method: :to_s, value_method: :name, include_blank: false - = f.collection_select :time_zone, ActiveSupport::TimeZone.all, :name, :to_s + /= f.collection_select :time_zone, ActiveSupport::TimeZone.all, :name, :to_s + = f.time_zone_select :time_zone /.accordion-group .accordion-heading a.accordion-toggle data-toggle="collapse" data-parent="#settings-sections" href="#settings-wifi" data-t="attributes.supplier.offer_wifi" diff --git a/spec/acceptance/suppliers/product_category_time_zone_availability.feature b/spec/acceptance/suppliers/product_category_time_zone_availability.feature new file mode 100644 index 00000000..411f8d5d --- /dev/null +++ b/spec/acceptance/suppliers/product_category_time_zone_availability.feature @@ -0,0 +1,11 @@ +Feature: Serving a product category from a different time zone + + @javascript + Scenario: Serving a product category from Buenos Aires + Given there is a confirmed and open supplier + And the supplier is in "Buenos Aires" + And the supplier has a night offset of 120 minutes + And there is a product category with product available on Fridays between 11PM and 1AM + Then the product category should not be visible on Thursday "11:30PM" + Then the product category should be visible on Friday "11:30PM" + Then the product category should be visible on Saturday "00:30AM" diff --git a/spec/acceptance/suppliers/settings.feature b/spec/acceptance/suppliers/settings.feature index f40b5a9f..d0132255 100644 --- a/spec/acceptance/suppliers/settings.feature +++ b/spec/acceptance/suppliers/settings.feature @@ -1,4 +1,5 @@ Feature: Manage settings + Scenario: Changing the supplier email Given there is a confirmed and open supplier And I am signed in as supplier @@ -11,3 +12,11 @@ Feature: Manage settings When the supplier clicks on the new email confirmation link Then the supplier gets redirected to the supplier settings path And the supplier email is the new email and the unconfirmed email is empty + + Scenario: Setting the timezone + Given there is a confirmed and open supplier + And I am signed in as supplier + When I visit the supplier settings path + And the supplier selects "(GMT-03:00) Buenos Aires" as Time Zone + And the supplier submits the supplier settings form + Then the supplier timezone should be "Buenos Aires" diff --git a/spec/acceptance_steps/supplier_steps.rb b/spec/acceptance_steps/supplier_steps.rb index 5167918c..a333c0d6 100644 --- a/spec/acceptance_steps/supplier_steps.rb +++ b/spec/acceptance_steps/supplier_steps.rb @@ -8,3 +8,14 @@ step "There is an open supplier with a menu" do @apple_pie.add_product_category @category_lunch end +step "the supplier is in :time_zone" do |time_zone| + time_zone = ActiveSupport::TimeZone.zones_map[time_zone] + raise "time zone #{time_zone} cannot be found" unless time_zone + @supplier.time_zone = time_zone.name + @supplier.save +end + +step "the supplier has a night offset of :minutes minutes" do |minutes| + @supplier.night_offset = minutes + @supplier.save +end diff --git a/spec/acceptance_steps/suppliers/product_category_steps.rb b/spec/acceptance_steps/suppliers/product_category_steps.rb index 09ec4223..aa0f5a55 100644 --- a/spec/acceptance_steps/suppliers/product_category_steps.rb +++ b/spec/acceptance_steps/suppliers/product_category_steps.rb @@ -53,3 +53,34 @@ end step "there are :count supplier product categories" do |count| @product_categories = create_list :product_category, count.to_i, supplier: @supplier end + +step "there is a product category with product available on :day between :category_start_time and :category_end_time" do |day, category_start_time, category_end_time| + step 'there is a product' + start_minute = (Time.parse(category_start_time).seconds_since_midnight / 60).round + end_minute = (Time.parse(category_end_time).seconds_since_midnight / 60).round + end_minute += 1440 if end_minute < start_minute #night offset option + @product_category = create :product_category, + supplier: @supplier, + week_days: [0,0,0,0,0,1,0], + product_ids: [@product.id], + start_from: start_minute, + end_on: end_minute +end + +step "the product category should not be visible on :week_day :time" do |week_day, time| + timestamp = Time.parse(time) + needed_wday = Date::DAYNAMES.index{|d| d == week_day} + raise "cannot find day of week for #{week_day}" unless needed_wday.is_a?(Integer) + timestamp = timestamp + (needed_wday - timestamp.wday).days unless timestamp.wday == needed_wday + product_categories = ProductCategory.for_supplier_in_time(@supplier, timestamp) + product_categories.should be_empty +end + +step "the product category should be visible on :week_day :time" do |week_day, time| + timestamp = Time.parse(time) + needed_wday = Date::DAYNAMES.index{|d| d == week_day} + raise "cannot find day of week for #{week_day}" unless needed_wday.is_a?(Integer) + timestamp = timestamp + (needed_wday - timestamp.wday).days unless timestamp.wday == needed_wday + product_categories = ProductCategory.for_supplier_in_time(@supplier, timestamp) + product_categories.should include @product_category +end diff --git a/spec/acceptance_steps/suppliers/product_steps.rb b/spec/acceptance_steps/suppliers/product_steps.rb index 1e22ef3b..de1dad6e 100644 --- a/spec/acceptance_steps/suppliers/product_steps.rb +++ b/spec/acceptance_steps/suppliers/product_steps.rb @@ -7,6 +7,10 @@ step "there are :count supplier products" do |count| @products = create_list :product, count.to_i, supplier: @supplier end +step 'there is a product' do + @product = create :product, supplier: @supplier +end + step "the supplier fills in the new product form selecting the first product category" do find('#product_name').set 'New product' find('#product_code').set 'NL0487' diff --git a/spec/acceptance_steps/suppliers/settings_steps.rb b/spec/acceptance_steps/suppliers/settings_steps.rb index a6bb5a17..df5cfb25 100644 --- a/spec/acceptance_steps/suppliers/settings_steps.rb +++ b/spec/acceptance_steps/suppliers/settings_steps.rb @@ -39,3 +39,12 @@ step "the supplier email is the new email and the unconfirmed email is empty" do @supplier.email.should == 'new-supplier-mail@qwaiter.com' @supplier.unconfirmed_email.should be_blank end + +step "the supplier selects :time_zone as Time Zone" do |visual_time_zone| + page.select visual_time_zone, from: 'supplier_time_zone' +end + +step "the supplier timezone should be :time_zone" do |time_zone| + @supplier.reload + @supplier.time_zone.should == time_zone +end diff --git a/vendor/assets/ember/development/ember-data.js b/vendor/assets/ember/development/ember-data.js index fb43a632..6d9d3ffb 100644 --- a/vendor/assets/ember/development/ember-data.js +++ b/vendor/assets/ember/development/ember-data.js @@ -1,15 +1,14 @@ -// ========================================================================== -// Project: Ember Data -// Copyright: ©2011-2013 Tilde Inc. and contributors. -// Portions ©2011 LivingSocial Inc. -// License: Licensed under MIT license (see license.js) -// ========================================================================== +// Fetched from channel: release, with url http://builds.emberjs.com/beta/ember-data.js +// Fetched on: 2014-01-04T21:06:07Z +/*! + * @overview Ember Data + * @copyright Copyright 2011-2013 Tilde Inc. and contributors. + * Portions Copyright 2011 LivingSocial Inc. + * @license Licensed under MIT license (see license.js) + */ - -// Version: v1.0.0-beta.3-20-g33263b0 -// Last commit: 33263b0 (2013-10-02 18:47:37 -0700) - + // Version: 1.0.0-beta.5+pre.69cb8b87 (function() { var define, requireModule; @@ -61,10 +60,10 @@ var define, requireModule; @class DS @static */ - +var DS; if ('undefined' === typeof DS) { DS = Ember.Namespace.create({ - VERSION: '1.0.0-beta.2' + VERSION: '1.0.0-beta.5+pre.69cb8b87' }); if ('undefined' !== typeof window) { @@ -75,6 +74,7 @@ if ('undefined' === typeof DS) { Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); } } + })(); @@ -90,9 +90,56 @@ function aliasMethod(methodName) { }; } +/** + In Ember Data a Serializer is used to serialize and deserialize + records when they are transfered in and out of an external source. + This process involves normalizing property names, transforming + attribute values and serializeing relationships. + + For maximum performance Ember Data recomends you use the + [RESTSerializer](DS.RESTSerializer.html) or one of its subclasses. + + `JSONSerializer` is useful for simpler or legacy backends that may + not support the http://jsonapi.org/ spec. + + @class JSONSerializer + @namespace DS +*/ DS.JSONSerializer = Ember.Object.extend({ + /** + The primaryKey is used when serializing and deserializing + data. Ember Data always uses the `id` propery to store the id of + the record. The external source may not always follow this + convention. In these cases it is usesful to override the + primaryKey property to match the primaryKey of your external + store. + + Example + + ```javascript + App.ApplicationSerializer = DS.JSONSerializer.extend({ + primaryKey: '_id' + }); + ``` + + @property primaryKey + @type {String} + */ primaryKey: 'id', + /** + Given a subclass of `DS.Model` and a JSON object this method will + iterate through each attribute of the `DS.Model` and invoke the + `DS.Transform#deserialize` method on the matching property of the + JSON object. This method is typically called after the + serializer's `normalize` method. + + @method applyTransforms + @private + @param {subclass of DS.Model} type + @param {Object} data The data to transform + @return {Object} data The transformed data object + */ applyTransforms: function(type, data) { type.eachTransformedAttribute(function(key, type) { var transform = this.transformFor(type); @@ -102,6 +149,39 @@ DS.JSONSerializer = Ember.Object.extend({ return data; }, + /** + Normalizes a part of the JSON payload returned by + the server. You should override this method, munge the hash + and call super if you have generic normalization to do. + + It takes the type of the record that is being normalized + (as a DS.Model class), the property where the hash was + originally found, and the hash to normalize. + + You can use this method, for example, to normalize underscored keys to camelized + or other general-purpose normalizations. + + Example + + ```javascript + App.ApplicationSerializer = DS.JSONSerializer.extend({ + normalize: function(type, hash) { + var normalizedHash = {}; + var fields = Ember.get(type, 'fields'); + fields.forEach(function(field) { + var normalizedProp = Ember.String.camelize(field); + normalizedHash[normalizedProp] = hash[field]; + }); + return this._super.apply(this, arguments); + } + }); + ``` + + @method normalize + @param {subclass of DS.Model} type + @param {Object} hash + @return {Object} + */ normalize: function(type, hash) { if (!hash) { return hash; } @@ -110,7 +190,149 @@ DS.JSONSerializer = Ember.Object.extend({ }, // SERIALIZE + /** + Called when a record is saved in order to convert the + record into JSON. + By default, it creates a JSON object with a key for + each attribute and belongsTo relationship. + + For example, consider this model: + + ```javascript + App.Comment = DS.Model.extend({ + title: DS.attr(), + body: DS.attr(), + + author: DS.belongsTo('user') + }); + ``` + + The default serialization would create a JSON object like: + + ```javascript + { + "title": "Rails is unagi", + "body": "Rails? Omakase? O_O", + "author": 12 + } + ``` + + By default, attributes are passed through as-is, unless + you specified an attribute type (`DS.attr('date')`). If + you specify a transform, the JavaScript value will be + serialized when inserted into the JSON hash. + + By default, belongs-to relationships are converted into + IDs when inserted into the JSON hash. + + ## IDs + + `serialize` takes an options hash with a single option: + `includeId`. If this option is `true`, `serialize` will, + by default include the ID in the JSON object it builds. + + The adapter passes in `includeId: true` when serializing + a record for `createRecord`, but not for `updateRecord`. + + ## Customization + + Your server may expect a different JSON format than the + built-in serialization format. + + In that case, you can implement `serialize` yourself and + return a JSON hash of your choosing. + + ```javascript + App.PostSerializer = DS.JSONSerializer.extend({ + serialize: function(post, options) { + var json = { + POST_TTL: post.get('title'), + POST_BDY: post.get('body'), + POST_CMS: post.get('comments').mapProperty('id') + } + + if (options.includeId) { + json.POST_ID_ = post.get('id'); + } + + return json; + } + }); + ``` + + ## Customizing an App-Wide Serializer + + If you want to define a serializer for your entire + application, you'll probably want to use `eachAttribute` + and `eachRelationship` on the record. + + ```javascript + App.ApplicationSerializer = DS.JSONSerializer.extend({ + serialize: function(record, options) { + var json = {}; + + record.eachAttribute(function(name) { + json[serverAttributeName(name)] = record.get(name); + }) + + record.eachRelationship(function(name, relationship) { + if (relationship.kind === 'hasMany') { + json[serverHasManyName(name)] = record.get(name).mapBy('id'); + } + }); + + if (options.includeId) { + json.ID_ = record.get('id'); + } + + return json; + } + }); + + function serverAttributeName(attribute) { + return attribute.underscore().toUpperCase(); + } + + function serverHasManyName(name) { + return serverAttributeName(name.singularize()) + "_IDS"; + } + ``` + + This serializer will generate JSON that looks like this: + + ```javascript + { + "TITLE": "Rails is omakase", + "BODY": "Yep. Omakase.", + "COMMENT_IDS": [ 1, 2, 3 ] + } + ``` + + ## Tweaking the Default JSON + + If you just want to do some small tweaks on the default JSON, + you can call super first and make the tweaks on the returned + JSON. + + ```javascript + App.PostSerializer = DS.JSONSerializer.extend({ + serialize: function(record, options) { + var json = this._super.apply(this, arguments); + + json.subject = json.title; + delete json.title; + + return json; + } + }); + ``` + + @method serialize + @param {subclass of DS.Model} record + @param {Object} options + @return {Object} json + */ serialize: function(record, options) { var json = {}; @@ -137,6 +359,29 @@ DS.JSONSerializer = Ember.Object.extend({ return json; }, + /** + `serializeAttribute` can be used to customize how `DS.attr` + properties are serialized + + For example if you wanted to ensure all you attributes were always + serialized as properties on an `attributes` object you could + write: + + ```javascript + App.ApplicationSerializer = DS.JSONSerializer.extend({ + serializeAttribute: function(record, json, key, attributes) { + json.attributes = json.attributes || {}; + this._super(record, json.attributes, key, attributes); + } + }); + ``` + + @method serializeAttribute + @param {DS.Model} record + @param {Object} json + @param {String} key + @param {Object} attribute + */ serializeAttribute: function(record, json, key, attribute) { var attrs = get(this, 'attrs'); var value = get(record, key), type = attribute.type; @@ -153,6 +398,31 @@ DS.JSONSerializer = Ember.Object.extend({ json[key] = value; }, + /** + `serializeBelongsTo` can be used to customize how `DS.belongsTo` + properties are serialized. + + Example + + ```javascript + App.PostSerializer = DS.JSONSerializer.extend({ + serializeBelongsTo: function(record, json, relationship) { + var key = relationship.key; + + var belongsTo = get(record, key); + + key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : key; + + json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.toJSON(); + } + }); + ``` + + @method serializeBelongsTo + @param {DS.Model} record + @param {Object} json + @param {Object} relationship + */ serializeBelongsTo: function(record, json, relationship) { var key = relationship.key; @@ -171,6 +441,30 @@ DS.JSONSerializer = Ember.Object.extend({ } }, + /** + `serializeHasMany` can be used to customize how `DS.hasMany` + properties are serialized. + + Example + + ```javascript + App.PostSerializer = DS.JSONSerializer.extend({ + serializeHasMany: function(record, json, relationship) { + var key = relationship.key; + if (key === 'comments') { + return; + } else { + this._super.apply(this, arguments); + } + } + }); + ``` + + @method serializeHasMany + @param {DS.Model} record + @param {Object} json + @param {Object} relationship + */ serializeHasMany: function(record, json, relationship) { var key = relationship.key; @@ -183,12 +477,65 @@ DS.JSONSerializer = Ember.Object.extend({ }, /** - You can use this method to customize how polymorphic objects are serialized. + You can use this method to customize how polymorphic objects are + serialized. Objects are considered to be polymorphic if + `{polymorphic: true}` is pass as the second argument to the + `DS.belongsTo` function. + + Example + + ```javascript + App.CommentSerializer = DS.JSONSerializer.extend({ + serializePolymorphicType: function(record, json, relationship) { + var key = relationship.key, + belongsTo = get(record, key); + key = this.keyForAttribute ? this.keyForAttribute(key) : key; + json[key + "_type"] = belongsTo.constructor.typeKey; + } + }); + ``` + + @method serializePolymorphicType + @param {DS.Model} record + @param {Object} json + @param {Object} relationship */ serializePolymorphicType: Ember.K, // EXTRACT + /** + The `extract` method is used to deserialize payload data from the + server. By default the `JSONSerializer` does not push the records + into the store. However records that subclass `JSONSerializer` + such as the `RESTSerializer` may push records into the store as + part of the extract call. + + This method deletegates to a more specific extract method based on + the `requestType`. + + Example + + ```javascript + var get = Ember.get; + socket.on('message', function(message) { + var modelName = message.model; + var data = message.data; + var type = store.modelFor(modelName); + var serializer = store.serializerFor(type.typeKey); + var record = serializer.extract(store, type, data, get(data, 'id'), 'single'); + store.push(modelName, record); + }); + ``` + + @method extract + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @param {String or Number} id + @param {String} requestType + @return {Object} json The deserialized payload + */ extract: function(store, type, payload, id, requestType) { this.extractMeta(store, type, payload); @@ -196,27 +543,205 @@ DS.JSONSerializer = Ember.Object.extend({ return this[specificExtract](store, type, payload, id, requestType); }, + /** + `extractFindAll` is a hook into the extract method used when a + call is made to `DS.Store#findAll`. By default this method is an + alias for [extractArray](#method_extractArray). + + @method extractFindAll + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Array} array An array of deserialized objects + */ extractFindAll: aliasMethod('extractArray'), + /** + `extractFindQuery` is a hook into the extract method used when a + call is made to `DS.Store#findQuery`. By default this method is an + alias for [extractArray](#method_extractArray). + + @method extractFindQuery + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Array} array An array of deserialized objects + */ extractFindQuery: aliasMethod('extractArray'), + /** + `extractFindMany` is a hook into the extract method used when a + call is made to `DS.Store#findMany`. By default this method is + alias for [extractArray](#method_extractArray). + + @method extractFindMany + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Array} array An array of deserialized objects + */ extractFindMany: aliasMethod('extractArray'), + /** + `extractFindHasMany` is a hook into the extract method used when a + call is made to `DS.Store#findHasMany`. By default this method is + alias for [extractArray](#method_extractArray). + + @method extractFindHasMany + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Array} array An array of deserialized objects + */ extractFindHasMany: aliasMethod('extractArray'), + /** + `extractCreateRecord` is a hook into the extract method used when a + call is made to `DS.Store#createRecord`. By default this method is + alias for [extractSave](#method_extractSave). + + @method extractCreateRecord + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Object} json The deserialized payload + */ extractCreateRecord: aliasMethod('extractSave'), + /** + `extractUpdateRecord` is a hook into the extract method used when + a call is made to `DS.Store#update`. By default this method is alias + for [extractSave](#method_extractSave). + + @method extractUpdateRecord + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Object} json The deserialized payload + */ extractUpdateRecord: aliasMethod('extractSave'), + /** + `extractDeleteRecord` is a hook into the extract method used when + a call is made to `DS.Store#deleteRecord`. By default this method is + alias for [extractSave](#method_extractSave). + + @method extractDeleteRecord + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Object} json The deserialized payload + */ extractDeleteRecord: aliasMethod('extractSave'), + /** + `extractFind` is a hook into the extract method used when + a call is made to `DS.Store#find`. By default this method is + alias for [extractSingle](#method_extractSingle). + + @method extractFind + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Object} json The deserialized payload + */ extractFind: aliasMethod('extractSingle'), + /** + `extractFindBelongsTo` is a hook into the extract method used when + a call is made to `DS.Store#findBelongsTo`. By default this method is + alias for [extractSingle](#method_extractSingle). + + @method extractFindBelongsTo + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Object} json The deserialized payload + */ extractFindBelongsTo: aliasMethod('extractSingle'), + /** + `extractSave` is a hook into the extract method used when a call + is made to `DS.Model#save`. By default this method is alias + for [extractSingle](#method_extractSingle). + + @method extractSave + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Object} json The deserialized payload + */ extractSave: aliasMethod('extractSingle'), + /** + `extractSingle` is used to deserialize a single record returned + from the adapter. + + Example + + ```javascript + App.PostSerializer = DS.JSONSerializer.extend({ + extractSingle: function(store, type, payload) { + payload.comments = payload._embedded.comment; + delete payload._embedded; + + return this._super(store, type, payload); + }, + }); + ``` + + @method extractSingle + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Object} json The deserialized payload + */ extractSingle: function(store, type, payload) { return this.normalize(type, payload); }, + /** + `extractArray` is used to deserialize an array of records + returned from the adapter. + + Example + + ```javascript + App.PostSerializer = DS.JSONSerializer.extend({ + extractArray: function(store, type, payload) { + return payload.map(function(json) { + return this.extractSingle(json); + }, this); + } + }); + ``` + + @method extractArray + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + @return {Array} array An array of deserialized objects + */ extractArray: function(store, type, payload) { return this.normalize(type, payload); }, + /** + `extractMeta` is used to deserialize any meta information in the + adapter payload. By default Ember Data expects meta information to + be located on the `meta` property of the payload object. + + Example + + ```javascript + App.PostSerializer = DS.JSONSerializer.extend({ + extractMeta: function(store, type, payload) { + if (payload && payload._pagination) { + store.metaForType(type, payload._pagination); + delete payload._pagination; + } + } + }); + ``` + + @method extractMeta + @param {DS.Store} store + @param {subclass of DS.Model} type + @param {Object} payload + */ extractMeta: function(store, type, payload) { if (payload && payload.meta) { store.metaForType(type, payload.meta); @@ -224,8 +749,36 @@ DS.JSONSerializer = Ember.Object.extend({ } }, + /** + `keyForRelationship` can be used to define a custom key when + serializeing relationship properties. By default `JSONSerializer` + does not provide an implementation of this method. + + Example + + ```javascript + App.PostSerializer = DS.JSONSerializer.extend({ + keyForRelationship: function(key, relationship) { + return 'rel_' + Ember.String.underscore(key); + } + }); + ``` + + @method keyForRelationship + @param {String} key + @param {String} relationship type + @return {String} normalized key + */ + // HELPERS + /** + @method transformFor + @private + @param {String} attributeType + @param {Boolean} skipAssertion + @return {DS.Transform} transform + */ transformFor: function(attributeType, skipAssertion) { var transform = this.container.lookup('transform:' + attributeType); Ember.assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); @@ -353,19 +906,105 @@ DS.DebugAdapter = Ember.DataAdapter.extend({ (function() { -DS.Transform = Ember.Object.extend({ +/** + The `DS.Transform` class is used to serialize and deserialize model + attributes when they are saved or loaded from an + adapter. Subclassing `DS.Transform` is useful for creating custom + attributes. All subclasses of `DS.Transform` must implement a + `serialize` and a `deserialize` method. + Example + + ```javascript + App.RawTransform = DS.Transform.extend({ + deserialize: function(serialized) { + return serialized; + }, + serialize: function(deserialized) { + return deserialized; + } + }); + ``` + + Usage + + ```javascript + var attr = DS.attr; + App.Requirement = DS.Model.extend({ + name: attr('string'), + optionsArray: attr('raw') + }); + ``` + + @class Transform + @namespace DS + */ +DS.Transform = Ember.Object.extend({ + /** + When given a deserialized value from a record attribute this + method must return the serialized value. + + Example + + ```javascript + serialize: function(deserialized) { + return Ember.isEmpty(deserialized) ? null : Number(deserialized); + } + ``` + + @method serialize + @param deserialized The deserialized value + @return The serialized value + */ serialize: Ember.required(), - + + /** + When given a serialize value from a JSON object this method must + return the deserialized value for the record attribute. + + Example + + ```javascript + deserialize: function(serialized) { + return empty(serialized) ? null : Number(serialized); + } + ``` + + @method deserialized + @param serialized The serialized value + @return The deserialized value + */ deserialize: Ember.required() }); + })(); (function() { +/** + The `DS.BooleanTransform` class is used to serialize and deserialize + boolean attributes on Ember Data record objects. This transform is + used when `boolean` is passed as the type parameter to the + [DS.attr](../../data#method_attr) function. + + Usage + + ```javascript + var attr = DS.attr; + App.User = DS.Model.extend({ + isAdmin: attr('boolean'), + name: attr('string'), + email: attr('string') + }); + ``` + + @class BooleanTransform + @extends DS.Transform + @namespace DS + */ DS.BooleanTransform = DS.Transform.extend({ deserialize: function(serialized) { var type = typeof serialized; @@ -391,6 +1030,25 @@ DS.BooleanTransform = DS.Transform.extend({ (function() { +/** + The `DS.DateTransform` class is used to serialize and deserialize + date attributes on Ember Data record objects. This transform is used + when `date` is passed as the type parameter to the + [DS.attr](../../data#method_attr) function. + + ```javascript + var attr = DS.attr; + App.Score = DS.Model.extend({ + value: attr('number'), + player: DS.belongsTo('player'), + date: attr('date') + }); + ``` + + @class DateTransform + @extends DS.Transform + @namespace DS + */ DS.DateTransform = DS.Transform.extend({ deserialize: function(serialized) { @@ -446,7 +1104,27 @@ DS.DateTransform = DS.Transform.extend({ (function() { var empty = Ember.isEmpty; +/** + The `DS.NumberTransform` class is used to serialize and deserialize + numeric attributes on Ember Data record objects. This transform is + used when `number` is passed as the type parameter to the + [DS.attr](../../data#method_attr) function. + Usage + + ```javascript + var attr = DS.attr; + App.Score = DS.Model.extend({ + value: attr('number'), + player: DS.belongsTo('player'), + date: attr('date') + }); + ``` + + @class NumberTransform + @extends DS.Transform + @namespace DS + */ DS.NumberTransform = DS.Transform.extend({ deserialize: function(serialized) { @@ -457,6 +1135,7 @@ DS.NumberTransform = DS.Transform.extend({ return empty(deserialized) ? null : Number(deserialized); } }); + })(); @@ -464,6 +1143,27 @@ DS.NumberTransform = DS.Transform.extend({ (function() { var none = Ember.isNone; +/** + The `DS.StringTransform` class is used to serialize and deserialize + string attributes on Ember Data record objects. This transform is + used when `string` is passed as the type parameter to the + [DS.attr](../../data#method_attr) function. + + Usage + + ```javascript + var attr = DS.attr; + App.User = DS.Model.extend({ + isAdmin: attr('boolean'), + name: attr('string'), + email: attr('string') + }); + ``` + + @class StringTransform + @extends DS.Transform + @namespace DS + */ DS.StringTransform = DS.Transform.extend({ deserialize: function(serialized) { @@ -541,6 +1241,7 @@ Ember.onLoad('Ember.Application', function(Application) { Application.initializer({ name: "transforms", + before: "store", initialize: function(container, application) { application.register('transform:boolean', DS.BooleanTransform); @@ -552,6 +1253,7 @@ Ember.onLoad('Ember.Application', function(Application) { Application.initializer({ name: "dataAdapter", + before: "store", initialize: function(container, application) { application.register('dataAdapter:main', DS.DebugAdapter); @@ -560,6 +1262,7 @@ Ember.onLoad('Ember.Application', function(Application) { Application.initializer({ name: "injectStore", + before: "store", initialize: function(container, application) { application.inject('controller', 'store', 'store:main'); @@ -712,9 +1415,10 @@ DS.RecordArray = Ember.ArrayProxy.extend(Ember.Evented, { }, save: function() { - var promise = Ember.RSVP.all(this.invoke("save")).then(function(array) { + var promiseLabel = "DS: RecordArray#save " + get(this, 'type'); + var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) { return Ember.A(array); - }); + }, null, "DS: RecordArray#save apply Ember.NativeArray"); return DS.PromiseArray.create({ promise: promise }); } @@ -844,6 +1548,14 @@ DS.ManyArray = DS.RecordArray.extend({ this._changesToSync = Ember.OrderedSet.create(); }, + /** + The property name of the relationship + + @property {String} + @private + */ + name: null, + /** The record to which this relationship belongs. @@ -864,6 +1576,15 @@ DS.ManyArray = DS.RecordArray.extend({ isLoaded: false, + /** + Used for async `hasMany` arrays + to keep track of when they will resolve. + + @property {Ember.RSVP.Promise} + @private + */ + promise: null, + loadingRecordsCount: function(count) { this.loadingRecordsCount = count; }, @@ -880,7 +1601,7 @@ DS.ManyArray = DS.RecordArray.extend({ var records = get(this, 'content'), store = get(this, 'store'), owner = get(this, 'owner'), - resolver = Ember.RSVP.defer(); + resolver = Ember.RSVP.defer("DS: ManyArray#fetch " + get(this, 'type')); var unloadedRecords = records.filterProperty('isEmpty', true); store.fetchMany(unloadedRecords, owner, resolver); @@ -1001,160 +1722,6 @@ DS.ManyArray = DS.RecordArray.extend({ -(function() { -/** - @module ember-data -*/ - -var get = Ember.get; -var forEach = Ember.ArrayPolyfills.forEach; - -var resolveMapConflict = function(oldValue, newValue) { - return oldValue; -}; - -var transformMapKey = function(key, value) { - return key; -}; - -var transformMapValue = function(key, value) { - return value; -}; - -/** - The Mappable mixin is designed for classes that would like to - behave as a map for configuration purposes. - - For example, the DS.Adapter class can behave like a map, with - more semantic API, via the `map` API: - - DS.Adapter.map('App.Person', { firstName: { key: 'FIRST' } }); - - Class configuration via a map-like API has a few common requirements - that differentiate it from the standard Ember.Map implementation. - - First, values often are provided as strings that should be normalized - into classes the first time the configuration options are used. - - Second, the values configured on parent classes should also be taken - into account. - - Finally, setting the value of a key sometimes should merge with the - previous value, rather than replacing it. - - This mixin provides a instance method, `createInstanceMapFor`, that - will reify all of the configuration options set on an instance's - constructor and provide it for the instance to use. - - Classes can implement certain hooks that allow them to customize - the requirements listed above: - - * `resolveMapConflict` - called when a value is set for an existing - value - * `transformMapKey` - allows a key name (for example, a global path - to a class) to be normalized - * `transformMapValue` - allows a value (for example, a class that - should be instantiated) to be normalized - - Classes that implement this mixin should also implement a class - method built using the `generateMapFunctionFor` method: - - DS.Adapter.reopenClass({ - map: DS.Mappable.generateMapFunctionFor('attributes', function(key, newValue, map) { - var existingValue = map.get(key); - - for (var prop in newValue) { - if (!newValue.hasOwnProperty(prop)) { continue; } - existingValue[prop] = newValue[prop]; - } - }) - }); - - The function passed to `generateMapFunctionFor` is invoked every time a - new value is added to the map. - - @class _Mappable - @private - @namespace DS -**/ -DS._Mappable = Ember.Mixin.create({ - createInstanceMapFor: function(mapName) { - var instanceMeta = getMappableMeta(this); - - instanceMeta.values = instanceMeta.values || {}; - - if (instanceMeta.values[mapName]) { return instanceMeta.values[mapName]; } - - var instanceMap = instanceMeta.values[mapName] = new Ember.Map(); - - var klass = this.constructor; - - while (klass && klass !== DS.Store) { - this._copyMap(mapName, klass, instanceMap); - klass = klass.superclass; - } - - instanceMeta.values[mapName] = instanceMap; - return instanceMap; - }, - - _copyMap: function(mapName, klass, instanceMap) { - var classMeta = getMappableMeta(klass); - - var classMap = classMeta[mapName]; - if (classMap) { - forEach.call(classMap, eachMap, this); - } - - function eachMap(key, value) { - var transformedKey = (klass.transformMapKey || transformMapKey)(key, value); - var transformedValue = (klass.transformMapValue || transformMapValue)(key, value); - - var oldValue = instanceMap.get(transformedKey); - var newValue = transformedValue; - - if (oldValue) { - newValue = (this.constructor.resolveMapConflict || resolveMapConflict)(oldValue, newValue); - } - - instanceMap.set(transformedKey, newValue); - } - } - -}); - -DS._Mappable.generateMapFunctionFor = function(mapName, transform) { - return function(key, value) { - var meta = getMappableMeta(this); - - var map = meta[mapName] || Ember.MapWithDefault.create({ - defaultValue: function() { return {}; } - }); - - transform.call(this, key, value, map); - - meta[mapName] = map; - }; -}; - -function getMappableMeta(obj) { - var meta = Ember.meta(obj, true), - keyName = 'DS.Mappable', - value = meta[keyName]; - - if (!value) { meta[keyName] = {}; } - - if (!meta.hasOwnProperty(keyName)) { - meta[keyName] = Ember.create(meta[keyName]); - } - - return meta[keyName]; -} - -})(); - - - (function() { /*globals Ember*/ /*jshint eqnull:true*/ @@ -1169,6 +1736,7 @@ var forEach = Ember.EnumerableUtils.forEach; var indexOf = Ember.EnumerableUtils.indexOf; var map = Ember.EnumerableUtils.map; var resolve = Ember.RSVP.resolve; +var copy = Ember.copy; // Implementors Note: // @@ -1203,7 +1771,9 @@ var coerceId = function(id) { Define your application's store like this: - MyApp.Store = DS.Store.extend(); + ```javascript + MyApp.Store = DS.Store.extend(); + ``` Most Ember.js applications will only have a single `DS.Store` that is automatically created by their `Ember.Application`. @@ -1211,12 +1781,16 @@ var coerceId = function(id) { You can retrieve models from the store in several ways. To retrieve a record for a specific id, use `DS.Model`'s `find()` method: - var person = App.Person.find(123); + ```javascript + var person = App.Person.find(123); + ``` If your application has multiple `DS.Store` instances (an unusual case), you can specify which store should be used: - var person = store.find(App.Person, 123); + ```javascript + var person = store.find(App.Person, 123); + ``` In general, you should retrieve models using the methods on `DS.Model`; you should rarely need to interact with the store directly. @@ -1224,9 +1798,11 @@ var coerceId = function(id) { By default, the store will talk to your backend using a standard REST mechanism. You can customize how the store talks to your backend by specifying a custom adapter: - MyApp.store = DS.Store.create({ - adapter: 'MyApp.CustomAdapter' - }); + ```javascript + MyApp.store = DS.Store.create({ + adapter: 'MyApp.CustomAdapter' + }); + ``` You can learn more about writing a custom adapter by reading the `DS.Adapter` documentation. @@ -1234,9 +1810,8 @@ var coerceId = function(id) { @class Store @namespace DS @extends Ember.Object - @uses DS._Mappable */ -DS.Store = Ember.Object.extend(DS._Mappable, { +DS.Store = Ember.Object.extend({ /** @method init @@ -1302,7 +1877,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { @private @returns DS.Adapter */ - defaultAdapter: Ember.computed(function() { + defaultAdapter: Ember.computed('adapter', function() { var adapter = get(this, 'adapter'); Ember.assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name or a factory', !(adapter instanceof DS.Adapter)); @@ -1316,7 +1891,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { } return adapter; - }).property('adapter'), + }), // ..................... // . CREATE NEW RECORD . @@ -1343,7 +1918,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { createRecord: function(type, properties) { type = this.modelFor(type); - properties = properties || {}; + properties = copy(properties) || {}; // If the passed properties do not include a primary key, // give the adapter an opportunity to generate one. Typically, @@ -1423,7 +1998,9 @@ DS.Store = Ember.Object.extend(DS._Mappable, { To find a record by ID, pass the `id` as the second parameter: - store.find('person', 1); + ```javascript + store.find('person', 1); + ``` The `find` method will always return a **promise** that will be resolved with the record. If the record was already in the store, the promise will @@ -1437,7 +2014,9 @@ DS.Store = Ember.Object.extend(DS._Mappable, { To find all records for a type, call `find` with no additional parameters: - store.find('person'); + ```javascript + store.find('person'); + ``` This will ask the adapter's `findAll` method to find the records for the given type, and return a promise that will be resolved once the server @@ -1448,7 +2027,9 @@ DS.Store = Ember.Object.extend(DS._Mappable, { To find a record by a query, call `find` with a hash as the second parameter: - store.find(App.Person, { page: 1 }); + ```javascript + store.find(App.Person, { page: 1 }); + ``` This will ask the adapter's `findQuery` method to find the records for the query, and return a promise that will be resolved once the server @@ -1484,7 +2065,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { var record = this.recordForId(type, id); - var promise = this.fetchRecord(record) || resolve(record); + var promise = this.fetchRecord(record) || resolve(record, "DS: Store#findById " + type + " with id: " + id); return promiseObject(promise); }, @@ -1492,6 +2073,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { This method makes a series of requests to the adapter's `find` method and returns a promise that resolves once they are all loaded. + @private @method findByIds @param {String} type @param {Array} ids @@ -1499,12 +2081,10 @@ DS.Store = Ember.Object.extend(DS._Mappable, { */ findByIds: function(type, ids) { var store = this; - + var promiseLabel = "DS: Store#findByIds " + type; return promiseArray(Ember.RSVP.all(map(ids, function(id) { return store.findById(type, id); - })).then(function(array) { - return Ember.A(array); - })); + })).then(Ember.A, null, "DS: Store#findByIds of " + type + " complete")); }, /** @@ -1524,7 +2104,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { var type = record.constructor, id = get(record, 'id'), - resolver = Ember.RSVP.defer(); + resolver = Ember.RSVP.defer("DS: Store#fetchRecord " + record ); record.loadingData(resolver.promise); @@ -1533,7 +2113,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { Ember.assert("You tried to find a record but you have no adapter (for " + type + ")", adapter); Ember.assert("You tried to find a record but your adapter (for " + type + ") does not implement 'find'", adapter.find); - _find(adapter, this, type, id, resolver); + resolver.resolve(_find(adapter, this, type, id)); return resolver.promise; }, @@ -1553,8 +2133,6 @@ DS.Store = Ember.Object.extend(DS._Mappable, { @param id */ getById: function(type, id) { - type = this.modelFor(type); - if (this.hasRecordForId(type, id)) { return this.recordForId(type, id); } else { @@ -1575,7 +2153,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { @param {DS.Model} record @param {Resolver} resolver */ - reloadRecord: function(record, resolver) { + reloadRecord: function(record) { var type = record.constructor, adapter = this.adapterFor(type), id = get(record, 'id'); @@ -1584,7 +2162,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { Ember.assert("You tried to reload a record but you have no adapter (for " + type + ")", adapter); Ember.assert("You tried to reload a record but your adapter does not implement `find`", adapter.find); - return _find(adapter, this, type, id, resolver); + return _find(adapter, this, type, id); }, /** @@ -1623,7 +2201,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { Ember.assert("You tried to load many records but you have no adapter (for " + type + ")", adapter); Ember.assert("You tried to load many records but your adapter does not implement `findMany`", adapter.findMany); - _findMany(adapter, this, type, ids, owner, resolver); + resolver.resolve(_findMany(adapter, this, type, ids, owner)); }, this); }, @@ -1631,13 +2209,13 @@ DS.Store = Ember.Object.extend(DS._Mappable, { Returns true if a record for a given type and ID is already loaded. @method hasRecordForId - @param {String} type + @param {DS.Model} type @param {String|Integer} id @returns Boolean */ hasRecordForId: function(type, id) { id = coerceId(id); - + type = this.modelFor(type); return !!this.typeMapFor(type).idToRecord[id]; }, @@ -1728,7 +2306,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { Ember.assert("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", adapter.findHasMany); var records = this.recordArrayManager.createManyArray(relationship.type, Ember.A([])); - _findHasMany(adapter, this, owner, link, relationship, resolver); + resolver.resolve(_findHasMany(adapter, this, owner, link, relationship)); return records; }, @@ -1738,7 +2316,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { Ember.assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.constructor + ")", adapter); Ember.assert("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", adapter.findBelongsTo); - _findBelongsTo(adapter, this, owner, link, relationship, resolver); + resolver.resolve(_findBelongsTo(adapter, this, owner, link, relationship)); }, /** @@ -1769,12 +2347,13 @@ DS.Store = Ember.Object.extend(DS._Mappable, { }); var adapter = this.adapterFor(type), - resolver = Ember.RSVP.defer(); + promiseLabel = "DS: Store#findQuery " + type, + resolver = Ember.RSVP.defer(promiseLabel); Ember.assert("You tried to load a query but you have no adapter (for " + type + ")", adapter); Ember.assert("You tried to load a query but your adapter does not implement `findQuery`", adapter.findQuery); - _findQuery(adapter, this, type, query, array, resolver); + resolver.resolve(_findQuery(adapter, this, type, query, array)); return promiseArray(resolver.promise); }, @@ -1805,14 +2384,14 @@ DS.Store = Ember.Object.extend(DS._Mappable, { fetchAll: function(type, array) { var adapter = this.adapterFor(type), sinceToken = this.typeMapFor(type).metadata.since, - resolver = Ember.RSVP.defer(); + resolver = Ember.RSVP.defer("DS: Store#findAll " + type); set(array, 'isUpdating', true); Ember.assert("You tried to load all records but you have no adapter (for " + type + ")", adapter); Ember.assert("You tried to load all records but your adapter does not implement `findAll`", adapter.findAll); - _findAll(adapter, this, type, sinceToken, resolver); + resolver.resolve(_findAll(adapter, this, type, sinceToken)); return promiseArray(resolver.promise); }, @@ -1877,6 +2456,8 @@ DS.Store = Ember.Object.extend(DS._Mappable, { while(record = records.pop()) { record.unloadRecord(); } + + typeMap.findAllCache = null; }, /** @@ -1895,8 +2476,13 @@ DS.Store = Ember.Object.extend(DS._Mappable, { filter function will be invoked again to determine whether it should still be in the array. + Optionally you can pass a query which will be triggered at first. The + results returned by the server could then appear in the filter if they + match the filter function. + @method filter @param {Class} type + @param {Object} query optional query @param {Function} filter @return {DS.FilteredRecordArray} */ @@ -1923,7 +2509,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { this.recordArrayManager.registerFilteredRecordArray(array, type, filter); if (promise) { - return promise.then(function() { return array; }); + return promise.then(function() { return array; }, null, "DS: Store#filter of " + type); } else { return array; } @@ -1935,7 +2521,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { will result in a request or that it will be a cache hit. @method recordIsLoaded - @param {Class} type + @param type @param {string} id @return {boolean} */ @@ -1964,8 +2550,8 @@ DS.Store = Ember.Object.extend(DS._Mappable, { If the adapter updates attributes or acknowledges creation or deletion, the record will notify the store to update its membership in any filters. - To avoid thrashing, this method is invoked only once per + run loop per record. @method dataWasUpdated @@ -1975,20 +2561,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { @param {DS.Model} record */ dataWasUpdated: function(type, record) { - // Because data updates are invoked at the end of the run loop, - // it is possible that a record might be deleted after its data - // has been modified and this method was scheduled to be called. - // - // If that's the case, the record would have already been removed - // from all record arrays; calling updateRecordArrays would just - // add it back. If the record is deleted, just bail. It shouldn't - // give us any more trouble after this. - - if (get(record, 'isDeleted')) { return; } - - if (get(record, 'isLoaded')) { - this.recordArrayManager.recordDidChange(record); - } + this.recordArrayManager.recordDidChange(record); }, // .............. @@ -2036,7 +2609,7 @@ DS.Store = Ember.Object.extend(DS._Mappable, { operation = 'updateRecord'; } - _commit(adapter, this, operation, record, resolver); + resolver.resolve(_commit(adapter, this, operation, record)); }, this); }, @@ -2169,21 +2742,22 @@ DS.Store = Ember.Object.extend(DS._Mappable, { etc.) @method modelFor - @param {String} key + @param {String or subclass of DS.Model} key @returns {subclass of DS.Model} */ modelFor: function(key) { - if (typeof key !== 'string') { - return key; + var factory; + + if (typeof key === 'string') { + factory = this.container.lookupFactory('model:' + key); + if (!factory) { throw new Ember.Error("No model was found for '" + key + "'"); } + factory.typeKey = key; + } else { + // A factory already supplied. + factory = key; } - var factory = this.container.lookupFactory('model:'+key); - - Ember.assert("No model was found for '" + key + "'", factory); - factory.store = this; - factory.typeKey = key; - return factory; }, @@ -2293,13 +2867,20 @@ DS.Store = Ember.Object.extend(DS._Mappable, { store.pushPayload('post', pushData); ``` - @method push + @method pushPayload @param {String} type @param {Object} payload */ pushPayload: function (type, payload) { - var serializer = this.serializerFor(type); + var serializer; + if (!payload) { + payload = type; + serializer = defaultSerializer(this.container); + Ember.assert("You cannot use `store#pushPayload` without a type unless your default serializer defines `pushPayload`", serializer.pushPayload); + } else { + serializer = this.serializerFor(type); + } serializer.pushPayload(this, payload); }, @@ -2525,6 +3106,7 @@ function normalizeRelationships(store, type, data, record) { deserializeRecordId(store, data, key, relationship, value); } else if (kind === 'hasMany') { deserializeRecordIds(store, data, key, relationship, value); + addUnsavedRecords(record, key, value); } }); @@ -2561,6 +3143,14 @@ function deserializeRecordIds(store, data, key, relationship, ids) { } } +// If there are any unsaved records that are in a hasMany they won't be +// in the payload, so add them back in manually. +function addUnsavedRecords(record, key, data) { + if(record) { + data.pushObjects(record.get(key).filterBy('isNew')); + } +} + // Delegation to the adapter and promise management DS.PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); @@ -2585,6 +3175,11 @@ function serializerFor(container, type, defaultSerializer) { container.lookup('serializer:_default'); } +function defaultSerializer(container) { + return container.lookup('serializer:application') || + container.lookup('serializer:_default'); +} + function serializerForAdapter(adapter, type) { var serializer = adapter.serializer, defaultSerializer = adapter.defaultSerializer, @@ -2603,11 +3198,11 @@ function serializerForAdapter(adapter, type) { return serializer; } -function _find(adapter, store, type, id, resolver) { +function _find(adapter, store, type, id) { var promise = adapter.find(store, type, id), serializer = serializerForAdapter(adapter, type); - return resolve(promise).then(function(payload) { + return resolve(promise, "DS: Handle Adapter#find of " + type + " with id: " + id).then(function(payload) { Ember.assert("You made a request for a " + type.typeKey + " with id " + id + ", but the adapter's response did not have any data", payload); payload = serializer.extract(store, type, payload, id, 'find'); @@ -2616,54 +3211,54 @@ function _find(adapter, store, type, id, resolver) { var record = store.getById(type, id); record.notFound(); throw error; - }).then(resolver.resolve, resolver.reject); + }, "DS: Extract payload of '" + type + "'"); } -function _findMany(adapter, store, type, ids, owner, resolver) { +function _findMany(adapter, store, type, ids, owner) { var promise = adapter.findMany(store, type, ids, owner), serializer = serializerForAdapter(adapter, type); - return resolve(promise).then(function(payload) { + return resolve(promise, "DS: Handle Adapter#findMany of " + type).then(function(payload) { payload = serializer.extract(store, type, payload, null, 'findMany'); Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); store.pushMany(type, payload); - }).then(resolver.resolve, resolver.reject); + }, null, "DS: Extract payload of " + type); } -function _findHasMany(adapter, store, record, link, relationship, resolver) { +function _findHasMany(adapter, store, record, link, relationship) { var promise = adapter.findHasMany(store, record, link, relationship), serializer = serializerForAdapter(adapter, relationship.type); - return resolve(promise).then(function(payload) { + return resolve(promise, "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type).then(function(payload) { payload = serializer.extract(store, relationship.type, payload, null, 'findHasMany'); Ember.assert("The response from a findHasMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); var records = store.pushMany(relationship.type, payload); record.updateHasMany(relationship.key, records); - }).then(resolver.resolve, resolver.reject); + }, null, "DS: Extract payload of " + record + " : hasMany " + relationship.type); } -function _findBelongsTo(adapter, store, record, link, relationship, resolver) { +function _findBelongsTo(adapter, store, record, link, relationship) { var promise = adapter.findBelongsTo(store, record, link, relationship), serializer = serializerForAdapter(adapter, relationship.type); - return resolve(promise).then(function(payload) { + return resolve(promise, "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type).then(function(payload) { payload = serializer.extract(store, relationship.type, payload, null, 'findBelongsTo'); var record = store.push(relationship.type, payload); record.updateBelongsTo(relationship.key, record); return record; - }).then(resolver.resolve, resolver.reject); + }, null, "DS: Extract payload of " + record + " : " + relationship.type); } -function _findAll(adapter, store, type, sinceToken, resolver) { +function _findAll(adapter, store, type, sinceToken) { var promise = adapter.findAll(store, type, sinceToken), serializer = serializerForAdapter(adapter, type); - return resolve(promise).then(function(payload) { + return resolve(promise, "DS: Handle Adapter#findAll of " + type).then(function(payload) { payload = serializer.extract(store, type, payload, null, 'findAll'); Ember.assert("The response from a findAll must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); @@ -2671,24 +3266,24 @@ function _findAll(adapter, store, type, sinceToken, resolver) { store.pushMany(type, payload); store.didUpdateAll(type); return store.all(type); - }).then(resolver.resolve, resolver.reject); + }, null, "DS: Extract payload of findAll " + type); } -function _findQuery(adapter, store, type, query, recordArray, resolver) { +function _findQuery(adapter, store, type, query, recordArray) { var promise = adapter.findQuery(store, type, query, recordArray), serializer = serializerForAdapter(adapter, type); - return resolve(promise).then(function(payload) { + return resolve(promise, "DS: Handle Adapter#findQuery of " + type).then(function(payload) { payload = serializer.extract(store, type, payload, null, 'findAll'); Ember.assert("The response from a findQuery must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array'); recordArray.load(payload); return recordArray; - }).then(resolver.resolve, resolver.reject); + }, null, "DS: Extract payload of findQuery " + type); } -function _commit(adapter, store, operation, record, resolver) { +function _commit(adapter, store, operation, record) { var type = record.constructor, promise = adapter[operation](store, type, record), serializer = serializerForAdapter(adapter, type); @@ -2707,7 +3302,7 @@ function _commit(adapter, store, operation, record, resolver) { } throw reason; - }).then(resolver.resolve, resolver.reject); + }, "DS: Extract and notify about " + operation + " completion of " + record); } })(); @@ -2720,95 +3315,111 @@ function _commit(adapter, store, operation, record, resolver) { */ var get = Ember.get, set = Ember.set; - /* - WARNING: Much of these docs are inaccurate as of bf8497. - This file encapsulates the various states that a record can transition through during its lifecycle. +*/ +/** + ### State - ### State Manager + Each record has a `currentState` property that explicitly tracks what + state a record is in at any given time. For instance, if a record is + newly created and has not yet been sent to the adapter to be saved, + it would be in the `root.loaded.created.uncommitted` state. If a + record has had local modifications made to it that are in the + process of being saved, the record would be in the + `root.loaded.updated.inFlight` state. (These state paths will be + explained in more detail below.) - A record's state manager explicitly tracks what state a record is in - at any given time. For instance, if a record is newly created and has - not yet been sent to the adapter to be saved, it would be in the - `created.uncommitted` state. If a record has had local modifications - made to it that are in the process of being saved, the record would be - in the `updated.inFlight` state. (These state paths will be explained - in more detail below.) + Events are sent by the record or its store to the record's + `currentState` property. How the state reacts to these events is + dependent on which state it is in. In some states, certain events + will be invalid and will cause an exception to be raised. - Events are sent by the record or its store to the record's state manager. - How the state manager reacts to these events is dependent on which state - it is in. In some states, certain events will be invalid and will cause - an exception to be raised. + States are hierarchical and every state is a substate of the + `RootState`. For example, a record can be in the + `root.deleted.uncommitted` state, then transition into the + `root.deleted.inFlight` state. If a child state does not implement + an event handler, the state manager will attempt to invoke the event + on all parent states until the root state is reached. The state + hierarchy of a record is described in terms of a path string. You + can determine a record's current state by getting the state's + `stateName` property: - States are hierarchical. For example, a record can be in the - `deleted.start` state, then transition into the `deleted.inFlight` state. - If a child state does not implement an event handler, the state manager - will attempt to invoke the event on all parent states until the root state is - reached. The state hierarchy of a record is described in terms of a path - string. You can determine a record's current state by getting its manager's - current state path: + ```javascript + record.get('currentState.stateName'); + //=> "root.created.uncommitted" + ``` - record.get('stateManager.currentPath'); - //=> "created.uncommitted" + The hierarchy of valid states that ship with ember data looks like + this: - The `DS.Model` states are themselves stateless. What we mean is that, - though each instance of a record also has a unique instance of a - `DS.StateManager`, the hierarchical states that each of *those* points - to is a shared data structure. For performance reasons, instead of each - record getting its own copy of the hierarchy of states, each state - manager points to this global, immutable shared instance. How does a - state know which record it should be acting on? We pass a reference to - the current state manager as the first parameter to every method invoked - on a state. + ```text + * root + * deleted + * saved + * uncommitted + * inFlight + * empty + * loaded + * created + * uncommitted + * inFlight + * saved + * updated + * uncommitted + * inFlight + * loading + ``` - The state manager passed as the first parameter is where you should stash + The `DS.Model` states are themselves stateless. What we mean is + that, the hierarchical states that each of *those* points to is a + shared data structure. For performance reasons, instead of each + record getting its own copy of the hierarchy of states, each record + points to this global, immutable shared instance. How does a state + know which record it should be acting on? We pass the record + instance into the state's event handlers as the first argument. + + The record passed as the first parameter is where you should stash state about the record if needed; you should never store data on the state - object itself. If you need access to the record being acted on, you can - retrieve the state manager's `record` property. For example, if you had - an event handler `myEvent`: + object itself. - myEvent: function(manager) { - var record = manager.get('record'); - record.doSomething(); - } + ### Events and Flags - For more information about state managers in general, see the Ember.js - documentation on `Ember.StateManager`. - - ### Events, Flags, and Transitions - - A state may implement zero or more events, flags, or transitions. + A state may implement zero or more events and flags. #### Events Events are named functions that are invoked when sent to a record. The - state manager will first look for a method with the given name on the - current state. If no method is found, it will search the current state's - parent, and then its grandparent, and so on until reaching the top of - the hierarchy. If the root is reached without an event handler being found, - an exception will be raised. This can be very helpful when debugging new - features. + record will first look for a method with the given name on the + current state. If no method is found, it will search the current + state's parent, and then its grandparent, and so on until reaching + the top of the hierarchy. If the root is reached without an event + handler being found, an exception will be raised. This can be very + helpful when debugging new features. Here's an example implementation of a state with a `myEvent` event handler: - aState: DS.State.create({ - myEvent: function(manager, param) { - console.log("Received myEvent with "+param); - } - }) + ```javascript + aState: DS.State.create({ + myEvent: function(manager, param) { + console.log("Received myEvent with", param); + } + }) + ``` To trigger this event: - record.send('myEvent', 'foo'); - //=> "Received myEvent with foo" + ```javascript + record.send('myEvent', 'foo'); + //=> "Received myEvent with foo" + ``` Note that an optional parameter can be sent to a record's `send()` method, which will be passed as the second parameter to the event handler. Events should transition to a different state if appropriate. This can be - done by calling the state manager's `transitionTo()` method with a path to the + done by calling the record's `transitionTo()` method with a path to the desired state. The state manager will attempt to resolve the state path relative to the current state. If no state is found at that path, it will attempt to resolve it relative to the current state's parent, and then its @@ -2816,12 +3427,12 @@ var get = Ember.get, set = Ember.set; like this: * created - * start <-- currentState + * uncommitted <-- currentState * inFlight * updated * inFlight - If we are currently in the `start` state, calling + If we are currently in the `uncommitted` state, calling `transitionTo('inFlight')` would transition to the `created.inFlight` state, while calling `transitionTo('updated.inFlight')` would transition to the `updated.inFlight` state. @@ -2836,16 +3447,20 @@ var get = Ember.get, set = Ember.set; state in a more user-friendly way than examining its state path. For example, instead of doing this: - var statePath = record.get('stateManager.currentPath'); - if (statePath === 'created.inFlight') { - doSomething(); - } + ```javascript + var statePath = record.get('stateManager.currentPath'); + if (statePath === 'created.inFlight') { + doSomething(); + } + ``` You can say: - if (record.get('isNew') && record.get('isSaving')) { - doSomething(); - } + ```javascript + if (record.get('isNew') && record.get('isSaving')) { + doSomething(); + } + ``` If your state does not set a value for a given flag, the value will be inherited from its parent (or the first place in the state hierarchy @@ -2855,23 +3470,18 @@ var get = Ember.get, set = Ember.set; in addition to the area below, you will also need to declare it in the `DS.Model` class. - #### Transitions - Transitions are like event handlers but are called automatically upon - entering or exiting a state. To implement a transition, just call a method - either `enter` or `exit`: + * [isEmpty](DS.Model.html#property_isEmpty) + * [isLoading](DS.Model.html#property_isLoading) + * [isLoaded](DS.Model.html#property_isLoaded) + * [isDirty](DS.Model.html#property_isDirty) + * [isSaving](DS.Model.html#property_isSaving) + * [isDeleted](DS.Model.html#property_isDeleted) + * [isNew](DS.Model.html#property_isNew) + * [isValid](DS.Model.html#property_isValid) - myState: DS.State.create({ - // Gets called automatically when entering - // this state. - enter: function(manager) { - console.log("Entered myState"); - } - }) - - Note that enter and exit events are called once per transition. If the - current state changes, but changes to another child state of the parent, - the transition event on the parent will not be triggered. + @namespace DS + @class RootState */ var hasDefinedProperties = function(object) { @@ -2974,8 +3584,8 @@ var DirtyState = { record.transitionTo('inFlight'); }, - reloadRecord: function(record, resolver) { - get(record, 'store').reloadRecord(record, resolver); + reloadRecord: function(record, resolve) { + resolve(get(record, 'store').reloadRecord(record)); }, rolledBack: function(record) { @@ -3255,8 +3865,8 @@ var RootState = { record.transitionTo('updated.inFlight'); }, - reloadRecord: function(record, resolver) { - get(record, 'store').reloadRecord(record, resolver); + reloadRecord: function(record, resolve) { + resolve(get(record, 'store').reloadRecord(record)); }, deleteRecord: function(record) { @@ -3275,6 +3885,10 @@ var RootState = { record.send('invokeLifecycleCallbacks', get(record, 'lastDirtyType')); }, + // loaded.saved.notFound would be triggered by a failed + // `reload()` on an unchanged record + notFound: Ember.K + }, // A record is in this state after it has been locally @@ -3300,9 +3914,7 @@ var RootState = { // TRANSITIONS setup: function(record) { - var store = get(record, 'store'); - - store.recordArrayManager.remove(record); + record.updateRecordArrays(); }, // SUBSTATES @@ -3417,9 +4029,9 @@ DS.RootState = RootState; var get = Ember.get, set = Ember.set, merge = Ember.merge, once = Ember.run.once; -var retrieveFromCurrentState = Ember.computed(function(key, value) { +var retrieveFromCurrentState = Ember.computed('currentState', function(key, value) { return get(get(this, 'currentState'), key); -}).property('currentState').readOnly(); +}).readOnly(); /** @@ -3431,35 +4043,284 @@ var retrieveFromCurrentState = Ember.computed(function(key, value) { @uses Ember.Evented */ DS.Model = Ember.Object.extend(Ember.Evented, { + /** + If this property is `true` the record is in the `empty` + state. Empty is the first state all records enter after they have + been created. Most records created by the store will quickly + transition to the `loading` state if data needs to be fetched from + the server or the `created` state if the record is created on the + client. A record can also enter the empty state if the adapter is + unable to locate the record. + + @property isEmpty + @type {Boolean} + @readOnly + */ isEmpty: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `loading` state. A + record enters this state when the store askes the adapter for its + data. It remains in this state until the adapter provides the + requested data. + + @property isLoading + @type {Boolean} + @readOnly + */ isLoading: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `loaded` state. A + record enters this state when its data is populated. Most of a + record's lifecycle is spent inside substates of the `loaded` + state. + + Example + + ```javascript + var record = store.createRecord(App.Model); + record.get('isLoaded'); // true + + store.find('model', 1).then(function(model) { + model.get('isLoaded'); // true + }); + ``` + + @property isLoaded + @type {Boolean} + @readOnly + */ isLoaded: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `dirty` state. The + record has local changes that have not yet been saved by the + adapter. This includes records that have been created (but not yet + saved) or deleted. + + Example + + ```javascript + var record = store.createRecord(App.Model); + record.get('isDirty'); // true + + store.find('model', 1).then(function(model) { + model.get('isDirty'); // false + model.set('foo', 'some value'); + model.set('isDirty'); // true + }); + ``` + + @property isDirty + @type {Boolean} + @readOnly + */ isDirty: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `saving` state. A + record enters the saving state when `save` is called, but the + adapter has not yet acknowledged that the changes have been + persisted to the backend. + + Example + + ```javascript + var record = store.createRecord(App.Model); + record.get('isSaving'); // false + var promise = record.save(); + record.get('isSaving'); // true + promise.then(function() { + record.get('isSaving'); // false + }); + ``` + + @property isSaving + @type {Boolean} + @readOnly + */ isSaving: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `deleted` state + and has been marked for deletion. When `isDeleted` is true and + `isDirty` is true, the record is deleted locally but the deletion + was not yet persisted. When `isSaving` is true, the change is + in-flight. When both `isDirty` and `isSaving` are false, the + change has persisted. + + Example + + ```javascript + var record = store.createRecord(App.Model); + record.get('isDeleted'); // false + record.deleteRecord(); + record.get('isDeleted'); // true + ``` + + @property isDeleted + @type {Boolean} + @readOnly + */ isDeleted: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `new` state. A + record will be in the `new` state when it has been created on the + client and the adapter has not yet report that it was successfully + saved. + + Example + + ```javascript + var record = store.createRecord(App.Model); + record.get('isNew'); // true + + store.find('model', 1).then(function(model) { + model.get('isNew'); // false + }); + ``` + + @property isNew + @type {Boolean} + @readOnly + */ isNew: retrieveFromCurrentState, + /** + If this property is `true` the record is in the `valid` state. A + record will be in the `valid` state when no client-side + validations have failed and the adapter did not report any + server-side validation failures. + + @property isValid + @type {Boolean} + @readOnly + */ isValid: retrieveFromCurrentState, + /** + If the record is in the dirty state this property will report what + kind of change has caused it to move into the dirty + state. Possible values are: + + - `created` The record has been created by the client and not yet saved to the adapter. + - `updated` The record has been updated by the client and not yet saved to the adapter. + - `deleted` The record has been deleted by the client and not yet saved to the adapter. + + Example + + ```javascript + var record = store.createRecord(App.Model); + record.get('dirtyType'); // 'created' + ``` + + @property dirtyType + @type {String} + @readOnly + */ dirtyType: retrieveFromCurrentState, + /** + If `true` the adapter reported that it was unable to save local + changes to the backend. This may also result in the record having + its `isValid` property become false if the adapter reported that + server-side validations failed. + + Example + + ```javascript + record.get('isError'); // false + record.set('foo', 'invalid value'); + record.save().then(null, function() { + record.get('isError'); // true + }); + ``` + + @property isError + @type {Boolean} + @readOnly + */ isError: false, + /** + If `true` the store is attempting to reload the record form the adapter. + + Example + + ```javascript + record.get('isReloading'); // false + record.reload(); + record.get('isReloading'); // true + ``` + + @property isReloading + @type {Boolean} + @readOnly + */ isReloading: false, + /** + The `clientId` property is a transient numerical identifier + generated at runtime by the data store. It is important + primarily because newly created objects may not yet have an + externally generated id. + + @property clientId + @private + @type {Number|String} + */ clientId: null, + /** + All ember models have an id property. This is an identifier + managed by an external source. These are always coerced to be + strings before being used internally. Note when declaring the + attributes for a model it is an error to declare an id + attribute. + + ```javascript + var record = store.createRecord(App.Model); + record.get('id'); // null + + store.find('model', 1).then(function(model) { + model.get('id'); // '1' + }); + ``` + + @property id + @type {String} + */ id: null, transaction: null, + /** + @property currentState + @private + @type {Object} + */ currentState: null, + /** + When the record is in the `invalid` state this object will contain + any errors returned by the adapter. When present the errors hash + typically contains keys coresponding to the invalid property names + and values which are an array of error messages. + + ```javascript + record.get('errors'); // null + record.set('foo', 'invalid value'); + record.save().then(null, function() { + record.get('errors'); // {foo: ['foo should be a number.']} + }); + ``` + + @property errors + @type {Object} + */ errors: null, /** Create a JSON representation of the record, using the serialization strategy of the store's adapter. - @method serialize - @param {Object} options Available options: + `serialize` takes an optional hash as a parameter, currently + supported options are: - * `includeId`: `true` if the record's ID should be included in the + - `includeId`: `true` if the record's ID should be included in the JSON representation. + @method serialize + @param {Object} options @returns {Object} an object whose values are primitive JSON values only */ serialize: function(options) { @@ -3468,15 +4329,17 @@ DS.Model = Ember.Object.extend(Ember.Evented, { }, /** - Use {{#crossLink "DS.JSONSerializer"}}DS.JSONSerializer{{/crossLink}} to + Use [DS.JSONSerializer](DS.JSONSerializer.html) to get the JSON representation of a record. - @method toJSON - @param {Object} options Available options: + `toJSON` takes an optional hash as a parameter, currently + supported options are: - * `includeId`: `true` if the record's ID should be included in the + - `includeId`: `true` if the record's ID should be included in the JSON representation. + @method toJSON + @param {Object} options @returns {Object} A JSON representation of the object. */ toJSON: function(options) { @@ -3492,13 +4355,6 @@ DS.Model = Ember.Object.extend(Ember.Evented, { */ didLoad: Ember.K, - /** - Fired when the record is reloaded from the server. - - @event didReload - */ - didReload: Ember.K, - /** Fired when the record is updated. @@ -3534,6 +4390,11 @@ DS.Model = Ember.Object.extend(Ember.Evented, { */ becameError: Ember.K, + /** + @property data + @private + @type {Object} + */ data: Ember.computed(function() { this._data = this._data || {}; return this._data; @@ -3556,6 +4417,12 @@ DS.Model = Ember.Object.extend(Ember.Evented, { this._relationships = {}; }, + /** + @method send + @private + @param {String} name + @param {Object} context + */ send: function(name, context) { var currentState = get(this, 'currentState'); @@ -3566,6 +4433,11 @@ DS.Model = Ember.Object.extend(Ember.Evented, { return currentState[name](this, context); }, + /** + @method transitionTo + @private + @param {String} name + */ transitionTo: function(name) { // POSSIBLE TODO: Remove this code and replace with // always having direct references to state objects @@ -3599,6 +4471,8 @@ DS.Model = Ember.Object.extend(Ember.Evented, { for (i=0, l=setups.length; i 1) { Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.constructor.toString(), key !== 'id'); var oldValue = this._attributes[key] || this._inFlightAttributes[key] || this._data[key]; - this.send('didSetProperty', { name: key, oldValue: oldValue, originalValue: this._data[key], value: value }); + + this.send('didSetProperty', { + name: key, + oldValue: oldValue, + originalValue: this._data[key], + value: value + }); + this._attributes[key] = value; return value; } else if (hasValue(this, key)) { @@ -4660,21 +5868,22 @@ var get = Ember.get, set = Ember.set, function asyncBelongsTo(type, options, meta) { return Ember.computed(function(key, value) { var data = get(this, 'data'), - store = get(this, 'store'); + store = get(this, 'store'), + promiseLabel = "DS: Async belongsTo " + this + " : " + key; if (arguments.length === 2) { Ember.assert("You can only add a '" + type + "' record to this relationship", !value || value instanceof store.modelFor(type)); - return value === undefined ? null : value; + return value === undefined ? null : DS.PromiseObject.create({ promise: Ember.RSVP.resolve(value, promiseLabel) }); } var link = data.links && data.links[key], belongsTo = data[key]; if(!isNone(belongsTo)) { - var promise = store.fetchRecord(belongsTo) || Ember.RSVP.resolve(belongsTo); - return DS.PromiseObject.create({promise: promise}); + var promise = store.fetchRecord(belongsTo) || Ember.RSVP.resolve(belongsTo, promiseLabel); + return DS.PromiseObject.create({ promise: promise}); } else if (link) { - var resolver = Ember.RSVP.defer(); + var resolver = Ember.RSVP.defer("DS: Async belongsTo (link) " + this + " : " + key); store.findBelongsTo(this, link, meta, resolver); return DS.PromiseObject.create({ promise: resolver.promise }); } else { @@ -4683,6 +5892,53 @@ function asyncBelongsTo(type, options, meta) { }).property('data').meta(meta); } +/** + `DS.belongsTo` is used to define One-To-One and One-To-Many + relationships on a [DS.Model](DS.Model.html). + + + `DS.belongsTo` takes an optional hash as a second parameter, currently + supported options are: + + - `async`: A boolean value used to explicitly declare this to be an async relationship. + - `inverse`: A string used to identify the inverse property on a + related model in a One-To-Many relationship. See [Explicit Inverses](#toc_explicit-inverses) + + #### One-To-One + To declare a one-to-one relationship between two models, use + `DS.belongsTo`: + + ```javascript + App.User = DS.Model.extend({ + profile: DS.belongsTo('profile') + }); + + App.Profile = DS.Model.extend({ + user: DS.belongsTo('user') + }); + ``` + + #### One-To-Many + To declare a one-to-many relationship between two models, use + `DS.belongsTo` in combination with `DS.hasMany`, like this: + + ```javascript + App.Post = DS.Model.extend({ + comments: DS.hasMany('comment') + }); + + App.Comment = DS.Model.extend({ + post: DS.belongsTo('post') + }); + ``` + + @namespace + @method belongsTo + @for DS + @param {String or DS.Model} type the model type of the relationship + @param {Object} options a hash of options + @return {Ember.computed} relationship +*/ DS.belongsTo = function(type, options) { if (typeof type === 'object') { options = type; @@ -4724,7 +5980,7 @@ DS.belongsTo = function(type, options) { }).property('data').meta(meta); }; -/* +/** These observers observe all `belongsTo` relationships on the record. See `relationships/ext` to see how these observers get their dependencies. @@ -4790,23 +6046,30 @@ var get = Ember.get, set = Ember.set, setProperties = Ember.setProperties; function asyncHasMany(type, options, meta) { return Ember.computed(function(key, value) { - if (this._relationships[key]) { return this._relationships[key]; } + var relationship = this._relationships[key], + promiseLabel = "DS: Async hasMany " + this + " : " + key; - var resolver = Ember.RSVP.defer(); + if (!relationship) { + var resolver = Ember.RSVP.defer(promiseLabel); + relationship = buildRelationship(this, key, options, function(store, data) { + var link = data.links && data.links[key]; + var rel; + if (link) { + rel = store.findHasMany(this, link, meta, resolver); + } else { + rel = store.findMany(this, data[key], meta.type, resolver); + } + // cache the promise so we can use it + // when we come back and don't need to rebuild + // the relationship. + set(rel, 'promise', resolver.promise); + return rel; + }); + } - var relationship = buildRelationship(this, key, options, function(store, data) { - var link = data.links && data.links[key]; - - if (link) { - return store.findHasMany(this, link, meta, resolver); - } else { - return store.findMany(this, data[key], meta.type, resolver); - } - }); - - var promise = resolver.promise.then(function() { + var promise = relationship.get('promise').then(function() { return relationship; - }); + }, null, "DS: Async hasMany records received"); return DS.PromiseArray.create({ promise: promise }); }).property('data').meta(meta); @@ -4845,6 +6108,84 @@ function hasRelationship(type, options) { }).property('data').meta(meta); } +/** + `DS.hasMany` is used to define One-To-Many and Many-To-Many + relationships on a [DS.Model](DS.Model.html). + + `DS.hasMany` takes an optional hash as a second parameter, currently + supported options are: + + - `async`: A boolean value used to explicitly declare this to be an async relationship. + - `inverse`: A string used to identify the inverse property on a related model. + + #### One-To-Many + To declare a one-to-many relationship between two models, use + `DS.belongsTo` in combination with `DS.hasMany`, like this: + + ```javascript + App.Post = DS.Model.extend({ + comments: DS.hasMany('comment') + }); + + App.Comment = DS.Model.extend({ + post: DS.belongsTo('post') + }); + ``` + + #### Many-To-Many + To declare a many-to-many relationship between two models, use + `DS.hasMany`: + + ```javascript + App.Post = DS.Model.extend({ + tags: DS.hasMany('tag') + }); + + App.Tag = DS.Model.extend({ + posts: DS.hasMany('post') + }); + ``` + + #### Explicit Inverses + + Ember Data will do its best to discover which relationships map to + one another. In the one-to-many code above, for example, Ember Data + can figure out that changing the `comments` relationship should update + the `post` relationship on the inverse because post is the only + relationship to that model. + + However, sometimes you may have multiple `belongsTo`/`hasManys` for the + same type. You can specify which property on the related model is + the inverse using `DS.hasMany`'s `inverse` option: + + ```javascript + var belongsTo = DS.belongsTo, + hasMany = DS.hasMany; + + App.Comment = DS.Model.extend({ + onePost: belongsTo('post'), + twoPost: belongsTo('post'), + redPost: belongsTo('post'), + bluePost: belongsTo('post') + }); + + App.Post = DS.Model.extend({ + comments: hasMany('comment', { + inverse: 'redPost' + }) + }); + ``` + + You can also specify an inverse on a `belongsTo`, which works how + you'd expect. + + @namespace + @method hasMany + @for DS + @param {String or DS.Model} type the model type of the relationship + @param {Object} options a hash of options + @return {Ember.computed} relationship +*/ DS.hasMany = function(type, options) { if (typeof type === 'object') { options = type; @@ -4887,9 +6228,11 @@ DS.Model.reopen({ This hook passes the class being set up, as well as the key and value being defined. So, for example, when the user does this: - DS.Model.extend({ - parent: DS.belongsTo('user') - }); + ```javascript + DS.Model.extend({ + parent: DS.belongsTo('user') + }); + ``` This hook would be called with "parent" as the key and the computed property returned by `DS.belongsTo` as the value. @@ -4941,9 +6284,11 @@ DS.Model.reopenClass({ For example, if you define a model like this: - App.Post = DS.Model.extend({ - comments: DS.hasMany('comment') - }); + ```javascript + App.Post = DS.Model.extend({ + comments: DS.hasMany('comment') + }); + ``` Calling `App.Post.typeForRelationship('comments')` will return `App.Comment`. @@ -5015,21 +6360,25 @@ DS.Model.reopenClass({ For example, given the following model definition: - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - posts: DS.hasMany('post') - }); + ```javascript + App.Blog = DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + posts: DS.hasMany('post') + }); + ``` This computed property would return a map describing these relationships, like this: - var relationships = Ember.get(App.Blog, 'relationships'); - relationships.get(App.User); - //=> [ { name: 'users', kind: 'hasMany' }, - // { name: 'owner', kind: 'belongsTo' } ] - relationships.get(App.Post); - //=> [ { name: 'posts', kind: 'hasMany' } ] + ```javascript + var relationships = Ember.get(App.Blog, 'relationships'); + relationships.get(App.User); + //=> [ { name: 'users', kind: 'hasMany' }, + // { name: 'owner', kind: 'belongsTo' } ] + relationships.get(App.Post); + //=> [ { name: 'posts', kind: 'hasMany' } ] + ``` @property relationships @static @@ -5065,20 +6414,24 @@ DS.Model.reopenClass({ by the relationship kind. For example, given a model with this definition: - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), + ```javascript + App.Blog = DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), - posts: DS.hasMany('post') - }); + posts: DS.hasMany('post') + }); + ``` This property would contain the following: - var relationshipNames = Ember.get(App.Blog, 'relationshipNames'); - relationshipNames.hasMany; - //=> ['users', 'posts'] - relationshipNames.belongsTo; - //=> ['owner'] + ```javascript + var relationshipNames = Ember.get(App.Blog, 'relationshipNames'); + relationshipNames.hasMany; + //=> ['users', 'posts'] + relationshipNames.belongsTo; + //=> ['owner'] + ``` @property relationshipNames @static @@ -5104,17 +6457,21 @@ DS.Model.reopenClass({ For example, given a model with this definition: - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); + ```javascript + App.Blog = DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), + + posts: DS.hasMany('post') + }); + ``` This property would contain the following: - var relatedTypes = Ember.get(App.Blog, 'relatedTypes'); - //=> [ App.User, App.Post ] + ```javascript + var relatedTypes = Ember.get(App.Blog, 'relatedTypes'); + //=> [ App.User, App.Post ] + ``` @property relatedTypes @static @@ -5155,20 +6512,24 @@ DS.Model.reopenClass({ For example, given a model with this definition: - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), + ```javascript + App.Blog = DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), - posts: DS.hasMany('post') - }); + posts: DS.hasMany('post') + }); + ``` This property would contain the following: - var relationshipsByName = Ember.get(App.Blog, 'relationshipsByName'); - relationshipsByName.get('users'); - //=> { key: 'users', kind: 'hasMany', type: App.User } - relationshipsByName.get('owner'); - //=> { key: 'owner', kind: 'belongsTo', type: App.User } + ```javascript + var relationshipsByName = Ember.get(App.Blog, 'relationshipsByName'); + relationshipsByName.get('users'); + //=> { key: 'users', kind: 'hasMany', type: App.User } + relationshipsByName.get('owner'); + //=> { key: 'owner', kind: 'belongsTo', type: App.User } + ``` @property relationshipsByName @static @@ -5207,25 +6568,28 @@ DS.Model.reopenClass({ For example: - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), + ```javascript - posts: DS.hasMany('post'), + App.Blog = DS.Model.extend({ + users: DS.hasMany('user'), + owner: DS.belongsTo('user'), - title: DS.attr('string') - }); + posts: DS.hasMany('post'), - var fields = Ember.get(App.Blog, 'fields'); - fields.forEach(function(field, kind) { - console.log(field, kind); - }); + title: DS.attr('string') + }); - // prints: - // users, hasMany - // owner, belongsTo - // posts, hasMany - // title, attribute + var fields = Ember.get(App.Blog, 'fields'); + fields.forEach(function(field, kind) { + console.log(field, kind); + }); + + // prints: + // users, hasMany + // owner, belongsTo + // posts, hasMany + // title, attribute + ``` @property fields @static @@ -5343,13 +6707,12 @@ DS.RecordArrayManager = Ember.Object.extend({ }, /** - This method is invoked whenever data is loaded into the store - by the adapter or updated by the adapter, or when an attribute - changes on a record. + This method is invoked whenever data is loaded into the store by the + adapter or updated by the adapter, or when a record has changed. - It updates all filters that a record belongs to. + It updates all record arrays that a record belongs to. - To avoid thrashing, it only runs once per run loop per record. + To avoid thrashing, it only runs at most once per run loop. @method updateRecordArrays @param {Class} type @@ -5357,31 +6720,49 @@ DS.RecordArrayManager = Ember.Object.extend({ */ updateRecordArrays: function() { forEach(this.changedRecords, function(record) { - var type = record.constructor, - recordArrays = this.filteredRecordArrays.get(type), - filter; - - forEach(recordArrays, function(array) { - filter = get(array, 'filterFunction'); - this.updateRecordArray(array, filter, type, record); - }, this); - - // loop through all manyArrays containing an unloaded copy of this - // clientId and notify them that the record was loaded. - var manyArrays = record._loadingRecordArrays; - - if (manyArrays) { - for (var i=0, l=manyArrays.length; i} The primary array that was returned in response + @returns {Array} The primary array that was returned in response to the original query. */ extractArray: function(store, primaryType, payload) { @@ -6532,7 +7905,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({ }], "comments": [{ "id": "1", - "body": "FIRST + "body": "FIRST" }], "users": [{ "id": "1", @@ -6545,6 +7918,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({ in data streaming in from your server structured the same way that fetches and saves are structured. + @method pushPayload @param {DS.Store} store @param {Object} payload */ @@ -6582,7 +7956,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({ @method typeForRoot @param {String} root - @returns String the model's typeKey + @returns {String} the model's typeKey */ typeForRoot: function(root) { return Ember.String.singularize(root); @@ -6768,7 +8142,7 @@ DS.RESTSerializer = DS.JSONSerializer.extend({ @method serializePolymorphicType @param {DS.Model} record @param {Object} json - @param relationship + @param {Object} relationship */ serializePolymorphicType: function(record, json, relationship) { var key = relationship.key, @@ -6820,7 +8194,7 @@ var forEach = Ember.ArrayPolyfills.forEach; ### Conventional Names - Attribute names in your JSON payload should be the camelcased versions of + Attribute names in your JSON payload should be the camelCased versions of the attributes in your Ember.js models. For example, if you have a `Person` model: @@ -6871,14 +8245,14 @@ var forEach = Ember.ArrayPolyfills.forEach; ### Headers customization - Some APIs require HTTP headers, eg to provide an API key. An array of + Some APIs require HTTP headers, e.g. to provide an API key. An array of headers can be added to the adapter which are passed with every request: ```js DS.RESTAdapter.reopen({ headers: { "API_KEY": "secret key", - "ANOTHER_HEADER": "asdsada" + "ANOTHER_HEADER": "Some header value" } }); ``` @@ -6895,9 +8269,11 @@ DS.RESTAdapter = DS.Adapter.extend({ Called by the store in order to fetch the JSON for a given type and ID. - It makes an Ajax request to a URL computed by `buildURL`, and returns a + The `find` method makes an Ajax request to a URL computed by `buildURL`, and returns a promise for the resulting payload. + This method performs an HTTP `GET` request with the id provided as part of the querystring. + @method find @see RESTAdapter/buildURL @see RESTAdapter/ajax @@ -6914,9 +8290,10 @@ DS.RESTAdapter = DS.Adapter.extend({ Called by the store in order to fetch a JSON array for all of the records for a given type. - It makes an Ajax request to a URL computed by `buildURL`, and returns a + The `findAll` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a promise for the resulting payload. + @private @method findAll @see RESTAdapter/buildURL @see RESTAdapter/ajax @@ -6939,12 +8316,13 @@ DS.RESTAdapter = DS.Adapter.extend({ Called by the store in order to fetch a JSON array for the records that match a particular query. - The query is a simple JavaScript object that will be passed directly - to the server as parameters. - - It makes an Ajax request to a URL computed by `buildURL`, and returns a + The `findQuery` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a promise for the resulting payload. + The `query` argument is a simple JavaScript object that will be passed directly + to the server as parameters. + + @private @method findQuery @see RESTAdapter/buildURL @see RESTAdapter/ajax @@ -6978,11 +8356,11 @@ DS.RESTAdapter = DS.Adapter.extend({ ids[]=1&ids[]=2&ids[]=3 ``` - Many servers, such as Rails and PHP, will automatically convert this + Many servers, such as Rails and PHP, will automatically convert this URL-encoded array into an Array for you on the server-side. If you want to encode the IDs, differently, just override this (one-line) method. - It makes an Ajax request to a URL computed by `buildURL`, and returns a + The `findMany` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a promise for the resulting payload. @method findMany @@ -7016,7 +8394,7 @@ DS.RESTAdapter = DS.Adapter.extend({ This method will be called with the parent record and `/posts/1/comments`. - It will make an Ajax request to the originally specified URL. + The `findHasMany` method will make an Ajax (HTTP GET) request to the originally specified URL. If the URL is host-relative (starting with a single slash), the request will use the host specified on the adapter (if any). @@ -7059,7 +8437,7 @@ DS.RESTAdapter = DS.Adapter.extend({ This method will be called with the parent record and `/people/1/group`. - It will make an Ajax request to the originally specified URL. + The `findBelongsTo` method will make an Ajax (HTTP GET) request to the originally specified URL. @method findBelongsTo @see RESTAdapter/buildURL @@ -7078,9 +8456,10 @@ DS.RESTAdapter = DS.Adapter.extend({ /** Called by the store when a newly created record is - `save`d. + saved via the `save` method on a model record instance. - It serializes the record, and `POST`s it to a URL generated by `buildURL`. + The `createRecord` method serializes the record and makes an Ajax (HTTP POST) request + to a URL computed by `buildURL`. See `serialize` for information on how to customize the serialized form of a record. @@ -7104,9 +8483,11 @@ DS.RESTAdapter = DS.Adapter.extend({ }, /** - Called by the store when an existing record is `save`d. + Called by the store when an existing record is saved + via the `save` method on a model record instance. - It serializes the record, and `POST`s it to a URL generated by `buildURL`. + The `updateRecord` method serializes the record and makes an Ajax (HTTP PUT) request + to a URL computed by `buildURL`. See `serialize` for information on how to customize the serialized form of a record. @@ -7132,9 +8513,9 @@ DS.RESTAdapter = DS.Adapter.extend({ }, /** - Called by the store when an deleted record is `save`d. + Called by the store when a record is deleted. - It serializes the record, and `POST`s it to a URL generated by `buildURL`. + The `deleteRecord` method makes an Ajax (HTTP DELETE) request to a URL computed by `buildURL`. @method deleteRecord @see RESTAdapter/buildURL @@ -7240,9 +8621,9 @@ DS.RESTAdapter = DS.Adapter.extend({ /** Takes an ajax response, and returns a relavant error. - By default, it has the following behavior: + By default, the `ajaxError` method has the following behavior: - * It simply returns the ajax response. + * It simply returns the ajax response (jqXHR). @method ajaxError @param jqXHR @@ -7263,7 +8644,7 @@ DS.RESTAdapter = DS.Adapter.extend({ or `extractArray` (depending on whether the original query was for one record or many records). - By default, it has the following behavior: + By default, `ajax` method has the following behavior: * It sets the response `dataType` to `"json"` * If the HTTP method is not `"GET"`, it sets the `Content-Type` to be @@ -7293,7 +8674,7 @@ DS.RESTAdapter = DS.Adapter.extend({ }; Ember.$.ajax(hash); - }); + }, "DS: RestAdapter#ajax " + type + " to " + url); }, ajaxOptions: function(url, type, hash) { @@ -7418,26 +8799,6 @@ DS.Model.reopen({ (function() { -//Copyright (C) 2011 by Living Social, Inc. - -//Permission is hereby granted, free of charge, to any person obtaining a copy of -//this software and associated documentation files (the "Software"), to deal in -//the Software without restriction, including without limitation the rights to -//use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -//of the Software, and to permit persons to whom the Software is furnished to do -//so, subject to the following conditions: - -//The above copyright notice and this permission notice shall be included in all -//copies or substantial portions of the Software. - -//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -//SOFTWARE. - /** Ember Data @@ -7465,7 +8826,7 @@ var BLANK_REGEX = /^\s*$/; function loadUncountable(rules, uncountable) { for (var i = 0, length = uncountable.length; i < length; i++) { - rules.uncountable[uncountable[i]] = true; + rules.uncountable[uncountable[i].toLowerCase()] = true; } } @@ -7475,8 +8836,8 @@ function loadIrregular(rules, irregularPairs) { for (var i = 0, length = irregularPairs.length; i < length; i++) { pair = irregularPairs[i]; - rules.irregular[pair[0]] = pair[1]; - rules.irregularInverse[pair[1]] = pair[0]; + rules.irregular[pair[0].toLowerCase()] = pair[1]; + rules.irregularInverse[pair[1].toLowerCase()] = pair[0]; } } @@ -7541,7 +8902,7 @@ function loadIrregular(rules, irregularPairs) { function Inflector(ruleSet) { ruleSet = ruleSet || {}; ruleSet.uncountable = ruleSet.uncountable || {}; - ruleSet.irregularPairs= ruleSet.irregularPairs|| {}; + ruleSet.irregularPairs = ruleSet.irregularPairs || {}; var rules = this.rules = { plurals: ruleSet.plurals || [], @@ -7562,7 +8923,7 @@ Inflector.prototype = { @param {String} string */ plural: function(regex, string) { - this.rules.plurals.push([regex, string]); + this.rules.plurals.push([regex, string.toLowerCase()]); }, /** @@ -7571,7 +8932,7 @@ Inflector.prototype = { @param {String} string */ singular: function(regex, string) { - this.rules.singular.push([regex, string]); + this.rules.singular.push([regex, string.toLowerCase()]); }, /** @@ -7579,7 +8940,7 @@ Inflector.prototype = { @param {String} regex */ uncountable: function(string) { - loadUncountable(this.rules, [string]); + loadUncountable(this.rules, [string.toLowerCase()]); }, /** @@ -7750,27 +9111,27 @@ Ember.Inflector.defaultRules = { (function() { -if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { - /** - See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}} - - @method pluralize - @for String - */ - String.prototype.pluralize = function() { - return Ember.String.pluralize(this); - }; - - /** - See {{#crossLink "Ember.String/singularize"}}{{/crossLink}} - - @method singularize - @for String - */ - String.prototype.singularize = function() { - return Ember.String.singularize(this); - }; -} +if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { + /** + See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}} + + @method pluralize + @for String + */ + String.prototype.pluralize = function() { + return Ember.String.pluralize(this); + }; + + /** + See {{#crossLink "Ember.String/singularize"}}{{/crossLink}} + + @method singularize + @for String + */ + String.prototype.singularize = function() { + return Ember.String.singularize(this); + }; +} })(); @@ -7830,26 +9191,9 @@ DS.ActiveModelSerializer = DS.RESTSerializer.extend({ }, /** - Serialize has-may relationship when it is configured as embedded objects. - - @method serializeHasMany + Does not serialize hasMany relationships by default. */ - serializeHasMany: function(record, json, relationship) { - var key = relationship.key, - attrs = get(this, 'attrs'), - embed = attrs && attrs[key] && attrs[key].embedded === 'always'; - - if (embed) { - json[this.keyForAttribute(key)] = get(record, key).map(function(relation) { - var data = relation.serialize(), - primaryKey = get(this, 'primaryKey'); - - data[primaryKey] = get(relation, primaryKey); - - return data; - }, this); - } - }, + serializeHasMany: Ember.K, /** Underscores the JSON root keys when serializing. @@ -7894,6 +9238,68 @@ DS.ActiveModelSerializer = DS.RESTSerializer.extend({ return Ember.String.singularize(camelized); }, + /** + Add extra step to `DS.RESTSerializer.normalize` so links are + normalized. + + If your payload looks like this + + ```js + { + "post": { + "id": 1, + "title": "Rails is omakase", + "links": { "flagged_comments": "api/comments/flagged" } + } + } + ``` + The normalized version would look like this + + ```js + { + "post": { + "id": 1, + "title": "Rails is omakase", + "links": { "flaggedComments": "api/comments/flagged" } + } + } + ``` + + @method normalize + @param {subclass of DS.Model} type + @param {Object} hash + @param {String} prop + @returns Object + */ + + normalize: function(type, hash, prop) { + this.normalizeLinks(hash); + + return this._super(type, hash, prop); + }, + + /** + Convert `snake_cased` links to `camelCase` + + @method normalizeLinks + @param {Object} hash + */ + + normalizeLinks: function(data){ + if (data.links) { + var links = data.links; + + for (var link in links) { + var camelizedLink = Ember.String.camelize(link); + + if (camelizedLink !== link) { + links[camelizedLink] = links[link]; + delete links[link]; + } + } + } + }, + /** Normalize the polymorphic type from the JSON. @@ -7944,8 +9350,66 @@ DS.ActiveModelSerializer = DS.RESTSerializer.extend({ } }, this); } + } +}); + +})(); + + + +(function() { +var get = Ember.get; +var forEach = Ember.EnumerableUtils.forEach; + +/** + The EmbeddedRecordsMixin allows you to add embedded record support to your + serializers. + To set up embedded records, you include the mixin into the serializer and then + define your embedded relations. + + ```js + App.PostSerializer = DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { + attrs: { + comments: {embedded: 'always'} + } + }) + ``` + + Currently only `{embedded: 'always'}` records are supported. + + @class EmbeddedRecordsMixin + @namespace DS +*/ +DS.EmbeddedRecordsMixin = Ember.Mixin.create({ + + /** + Serialize has-may relationship when it is configured as embedded objects. + + @method serializeHasMany + */ + serializeHasMany: function(record, json, relationship) { + var key = relationship.key, + attrs = get(this, 'attrs'), + embed = attrs && attrs[key] && attrs[key].embedded === 'always'; + + if (embed) { + json[this.keyForAttribute(key)] = get(record, key).map(function(relation) { + var data = relation.serialize(), + primaryKey = get(this, 'primaryKey'); + + data[primaryKey] = get(relation, primaryKey); + + return data; + }, this); + } }, + /** + Extract embedded objects out of the payload for a single object + and add them as sideloaded objects instead. + + @method extractSingle + */ extractSingle: function(store, primaryType, payload, recordId, requestType) { var root = this.keyForAttribute(primaryType.typeKey), partial = payload[root]; @@ -7955,6 +9419,12 @@ DS.ActiveModelSerializer = DS.RESTSerializer.extend({ return this._super(store, primaryType, payload, recordId, requestType); }, + /** + Extract embedded objects out of a standard payload + and add them as sideloaded objects instead. + + @method extractArray + */ extractArray: function(store, type, payload) { var root = this.keyForAttribute(type.typeKey), partials = payload[Ember.String.pluralize(root)]; @@ -7999,6 +9469,8 @@ function updatePayloadWithEmbedded(store, serializer, type, partial, payload) { payload[embeddedTypeKey] = payload[embeddedTypeKey] || []; forEach(partial[attribute], function(data) { + var embeddedType = store.modelFor(relationship.type.typeKey); + updatePayloadWithEmbedded(store, serializer, embeddedType, data, payload); ids.push(data[primaryKey]); payload[embeddedTypeKey].push(data); }); @@ -8008,7 +9480,6 @@ function updatePayloadWithEmbedded(store, serializer, type, partial, payload) { } }, serializer); } - })(); @@ -8027,6 +9498,10 @@ var forEach = Ember.EnumerableUtils.forEach; [active_model_serializers](http://github.com/rails-api/active_model_serializers) Ruby gem. + This adapter extends the DS.RESTAdapter by making consistent use of the camelization, + decamelization and pluralization methods to normalize the serialized JSON into a + format that is compatible with a conventional Rails backend and Ember Data. + ## JSON Structure The ActiveModelAdapter expects the JSON returned from your server to follow @@ -8068,8 +9543,8 @@ var forEach = Ember.EnumerableUtils.forEach; DS.ActiveModelAdapter = DS.RESTAdapter.extend({ defaultSerializer: '_ams', /** - The ActiveModelAdapter overrides the `pathForType` method - to build underscored URLs. + The ActiveModelAdapter overrides the `pathForType` method to build + underscored URLs by decamelizing and pluralizing the object type name. ```js this.pathForType("famousPerson"); @@ -8090,6 +9565,13 @@ DS.ActiveModelAdapter = DS.RESTAdapter.extend({ to return a DS.InvalidError for all 422 Unprocessable Entity responses. + A 422 HTTP response from the server generally implies that the request + was well formed but the API was unable to process it because the + content was not semantically correct or meaningful per the API. + + For more information on 422 HTTP Error code see 11.2 WebDAV RFC 4918 + https://tools.ietf.org/html/rfc4918#section-11.2 + @method ajaxError @param jqXHR @returns error diff --git a/vendor/assets/ember/development/ember.js b/vendor/assets/ember/development/ember.js index d5bb35ba..2d4e1392 100644 --- a/vendor/assets/ember/development/ember.js +++ b/vendor/assets/ember/development/ember.js @@ -1,16 +1,16 @@ +// Fetched from channel: release, with url http://builds.emberjs.com/release/ember.js +// Fetched on: 2014-01-04T21:05:01Z // ========================================================================== // Project: Ember - JavaScript Application Framework -// Copyright: ©2011-2013 Tilde Inc. and contributors -// Portions ©2006-2011 Strobe Inc. -// Portions ©2008-2011 Apple Inc. All rights reserved. +// Copyright: Copyright 2011-2013 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: v1.0.0-225-g56e5a22 -// Last commit: 56e5a22 (2013-10-03 13:41:25 -0700) - + // Version: 1.2.1+pre.ce3a6b7c (function() { /*global __fail__*/ @@ -65,7 +65,7 @@ Ember.assert = function(desc, test) { if (Ember.testing && !test) { // when testing, ensure test failures when assertions fail - throw new Error("Assertion Failed: " + desc); + throw new Ember.Error("Assertion Failed: " + desc); } }; @@ -117,7 +117,7 @@ Ember.deprecate = function(message, test) { if (arguments.length === 1) { test = false; } if (test) { return; } - if (Ember.ENV.RAISE_ON_DEPRECATION) { throw new Error(message); } + if (Ember.ENV.RAISE_ON_DEPRECATION) { throw new Ember.Error(message); } var error; @@ -188,17 +188,15 @@ if (!Ember.testing) { // ========================================================================== // Project: Ember - JavaScript Application Framework -// Copyright: ©2011-2013 Tilde Inc. and contributors -// Portions ©2006-2011 Strobe Inc. -// Portions ©2008-2011 Apple Inc. All rights reserved. +// Copyright: Copyright 2011-2013 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: v1.0.0-225-g56e5a22 -// Last commit: 56e5a22 (2013-10-03 13:41:25 -0700) - + // Version: 1.2.1+pre.ce3a6b7c (function() { var define, requireModule; @@ -263,7 +261,7 @@ var define, requireModule; @class Ember @static - @version 1.0.0 + @version 1.2.1+pre.ce3a6b7c */ if ('undefined' === typeof Ember) { @@ -290,10 +288,10 @@ Ember.toString = function() { return "Ember"; }; /** @property VERSION @type String - @default '1.0.0' + @default '1.2.1+pre.ce3a6b7c' @final */ -Ember.VERSION = '1.0.0'; +Ember.VERSION = '1.2.1+pre.ce3a6b7c'; /** Standard environmental variables. You can define these in a global `ENV` @@ -333,15 +331,28 @@ 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 an `ENV.ENABLE_ALL_FEATURES` config to force all features to - be enabled. + 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 */ Ember.FEATURES.isEnabled = function(feature) { - return Ember.ENV.ENABLE_ALL_FEATURES || Ember.FEATURES[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; + } }; // .......................................................... @@ -425,189 +436,6 @@ if ('undefined' === typeof Ember.deprecateFunc) { */ Ember.uuid = 0; -// .......................................................... -// LOGGER -// - -function consoleMethod(name) { - var consoleObj; - if (imports.console) { - consoleObj = imports.console; - } else if (typeof console !== 'undefined') { - consoleObj = console; - } - - var method = typeof consoleObj === 'object' ? consoleObj[name] : null; - - if (method) { - // Older IE doesn't support apply, but Chrome needs it - if (method.apply) { - return function() { - method.apply(consoleObj, arguments); - }; - } else { - return function() { - var message = Array.prototype.join.call(arguments, ', '); - method(message); - }; - } - } -} - -function assertPolyfill(test, message) { - if (!test) { - try { - // attempt to preserve the stack - throw new Error("assertion failed: " + message); - } catch(error) { - setTimeout(function() { - throw error; - }, 0); - } - } -} - -/** - Inside Ember-Metal, simply uses the methods from `imports.console`. - Override this to provide more robust logging functionality. - - @class Logger - @namespace Ember -*/ -Ember.Logger = { - /** - Logs the arguments to the console. - You can pass as many arguments as you want and they will be joined together with a space. - - ```javascript - var foo = 1; - Ember.Logger.log('log value of foo:', foo); // "log value of foo: 1" will be printed to the console - ``` - - @method log - @for Ember.Logger - @param {*} arguments - */ - log: consoleMethod('log') || Ember.K, - /** - Prints the arguments to the console with a warning icon. - You can pass as many arguments as you want and they will be joined together with a space. - - ```javascript - Ember.Logger.warn('Something happened!'); // "Something happened!" will be printed to the console with a warning icon. - ``` - - @method warn - @for Ember.Logger - @param {*} arguments - */ - warn: consoleMethod('warn') || Ember.K, - /** - Prints the arguments to the console with an error icon, red text and a stack race. - You can pass as many arguments as you want and they will be joined together with a space. - - ```javascript - Ember.Logger.error('Danger! Danger!'); // "Danger! Danger!" will be printed to the console in red text. - ``` - - @method error - @for Ember.Logger - @param {*} arguments - */ - error: consoleMethod('error') || Ember.K, - /** - Logs the arguments to the console. - You can pass as many arguments as you want and they will be joined together with a space. - - ```javascript - var foo = 1; - Ember.Logger.info('log value of foo:', foo); // "log value of foo: 1" will be printed to the console - ``` - - @method info - @for Ember.Logger - @param {*} arguments - */ - info: consoleMethod('info') || Ember.K, - /** - Logs the arguments to the console in blue text. - You can pass as many arguments as you want and they will be joined together with a space. - - ```javascript - var foo = 1; - Ember.Logger.debug('log value of foo:', foo); // "log value of foo: 1" will be printed to the console - ``` - - @method debug - @for Ember.Logger - @param {*} arguments - */ - debug: consoleMethod('debug') || consoleMethod('info') || Ember.K, - /** - - If the value passed into Ember.Logger.assert is not truthy it will throw an error with a stack trace. - - ```javascript - Ember.Logger.assert(true); // undefined - Ember.Logger.assert(true === false); // Throws an Assertion failed error. - ``` - - @method assert - @for Ember.Logger - @param {Boolean} bool Value to test - */ - assert: consoleMethod('assert') || assertPolyfill -}; - - -// .......................................................... -// ERROR HANDLING -// - -/** - A function may be assigned to `Ember.onerror` to be called when Ember - internals encounter an error. This is useful for specialized error handling - and reporting code. - - ```javascript - Ember.onerror = function(error) { - Em.$.ajax('/report-error', 'POST', { - stack: error.stack, - otherInformation: 'whatever app state you want to provide' - }); - }; - ``` - - @event onerror - @for Ember - @param {Exception} error the error object -*/ -Ember.onerror = null; - -/** - @private - - Wrap code block in a try/catch if `Ember.onerror` is set. - - @method handleErrors - @for Ember - @param {Function} func - @param [context] -*/ -Ember.handleErrors = function(func, context) { - // Unfortunately in some browsers we lose the backtrace if we rethrow the existing error, - // so in the event that we don't have an `onerror` handler we don't wrap in a try/catch - if ('function' === typeof Ember.onerror) { - try { - return func.call(context || this); - } catch (error) { - Ember.onerror(error); - } - } else { - return func.call(context || this); - } -}; - /** Merge the contents of two objects together into the first object. @@ -711,7 +539,7 @@ var platform = Ember.platform = {}; */ Ember.create = Object.create; -// IE8 has Object.create but it couldn't treat property descripters. +// IE8 has Object.create but it couldn't treat property descriptors. if (Ember.create) { if (Ember.create({a: 1}, {a: {value: 2}}).a !== 2) { Ember.create = null; @@ -955,11 +783,93 @@ if (Ember.SHIM_ES5) { +(function() { +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 +*/ +Ember.Error = function() { + var tmp = Error.apply(this, arguments); + + // 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]]; + } +}; + +Ember.Error.prototype = Ember.create(Error.prototype); + +// .......................................................... +// ERROR HANDLING +// + +/** + A function may be assigned to `Ember.onerror` to be called when Ember + internals encounter an error. This is useful for specialized error handling + and reporting code. + + ```javascript + Ember.onerror = function(error) { + Em.$.ajax('/report-error', 'POST', { + stack: error.stack, + otherInformation: 'whatever app state you want to provide' + }); + }; + ``` + + @event onerror + @for Ember + @param {Exception} error the error object +*/ +Ember.onerror = null; + +/** + @private + + Wrap code block in a try/catch if `Ember.onerror` is set. + + @method handleErrors + @for Ember + @param {Function} func + @param [context] +*/ +Ember.handleErrors = function(func, context) { + // Unfortunately in some browsers we lose the backtrace if we rethrow the existing error, + // so in the event that we don't have an `onerror` handler we don't wrap in a try/catch + if ('function' === typeof Ember.onerror) { + try { + return func.call(context || this); + } catch (error) { + Ember.onerror(error); + } + } else { + return func.call(context || this); + } +}; + +})(); + + + (function() { /** @module ember-metal */ +/** + @private + + Prefix used for guids through out Ember. + +*/ +Ember.GUID_PREFIX = 'ember'; + var o_defineProperty = Ember.platform.defineProperty, o_create = Ember.create, @@ -1014,13 +924,13 @@ var GUID_DESC = { @return {String} the guid */ Ember.generateGuid = function generateGuid(obj, prefix) { - if (!prefix) prefix = 'ember'; + if (!prefix) prefix = Ember.GUID_PREFIX; var ret = (prefix + (uuid++)); if (obj) { GUID_DESC.value = ret; o_defineProperty(obj, GUID_KEY, GUID_DESC); } - return ret ; + return ret; }; /** @@ -1557,9 +1467,9 @@ var toString = Object.prototype.toString; | Return Value | Meaning | |---------------|------------------------------------------------------| - | 'string' | String primitive | - | 'number' | Number primitive | - | 'boolean' | Boolean primitive | + | 'string' | String primitive or String object. | + | 'number' | Number primitive or Number object. | + | 'boolean' | Boolean primitive or Boolean object. | | 'null' | Null value | | 'undefined' | Undefined value | | 'function' | A function | @@ -1576,8 +1486,11 @@ var toString = Object.prototype.toString; Ember.typeOf(null); // 'null' Ember.typeOf(undefined); // 'undefined' Ember.typeOf('michael'); // 'string' + Ember.typeOf(new String('michael')); // 'string' Ember.typeOf(101); // 'number' + Ember.typeOf(new Number(101)); // 'number' Ember.typeOf(true); // 'boolean' + Ember.typeOf(new Boolean(true)); // 'boolean' Ember.typeOf(Ember.makeArray); // 'function' Ember.typeOf([1,2,90]); // 'array' Ember.typeOf(Ember.Object.extend()); // 'class' @@ -1754,6 +1667,8 @@ Ember.Instrumentation.instrument = function(name, payload, callback, binding) { @param {String} [pattern] Namespaced event name. @param {Object} [object] Before and After hooks. + + @return {Subscriber} */ Ember.Instrumentation.subscribe = function(pattern, object) { var paths = pattern.split("."), path, regex = []; @@ -2018,7 +1933,7 @@ var normalizeTuple = Ember.normalizeTuple = function(target, path) { } // must return some kind of path to be valid else other things will break. - if (!path || path.length===0) throw new Error('Invalid Path'); + if (!path || path.length===0) throw new Ember.Error('Invalid Path'); return [ target, path ]; }; @@ -2704,6 +2619,7 @@ Ember.overrideChains = function(obj, keyName, m) { /** @method beginPropertyChanges @chainable + @private */ function beginPropertyChanges() { deferred++; @@ -2713,6 +2629,7 @@ Ember.beginPropertyChanges = beginPropertyChanges; /** @method endPropertyChanges + @private */ function endPropertyChanges() { deferred--; @@ -2885,12 +2802,12 @@ function setPath(root, path, value, tolerant) { } if (!keyName || keyName.length === 0) { - throw new Error('You passed an empty path'); + throw new Ember.Error('You passed an empty path'); } if (!root) { if (tolerant) { return; } - else { throw new Error('Object in path '+path+' could not be found or was destroyed.'); } + else { throw new Ember.Error('Object in path '+path+' could not be found or was destroyed.'); } } return set(root, keyName, value); @@ -3298,6 +3215,142 @@ MapWithDefault.prototype.copy = function() { +(function() { +function consoleMethod(name) { + var consoleObj; + if (Ember.imports.console) { + consoleObj = Ember.imports.console; + } else if (typeof console !== 'undefined') { + consoleObj = console; + } + + var method = typeof consoleObj === 'object' ? consoleObj[name] : null; + + if (method) { + // Older IE doesn't support apply, but Chrome needs it + if (method.apply) { + return function() { + method.apply(consoleObj, arguments); + }; + } else { + return function() { + var message = Array.prototype.join.call(arguments, ', '); + method(message); + }; + } + } +} + +function assertPolyfill(test, message) { + if (!test) { + try { + // attempt to preserve the stack + throw new Ember.Error("assertion failed: " + message); + } catch(error) { + setTimeout(function() { + throw error; + }, 0); + } + } +} + +/** + Inside Ember-Metal, simply uses the methods from `imports.console`. + Override this to provide more robust logging functionality. + + @class Logger + @namespace Ember +*/ +Ember.Logger = { + /** + Logs the arguments to the console. + You can pass as many arguments as you want and they will be joined together with a space. + + ```javascript + var foo = 1; + Ember.Logger.log('log value of foo:', foo); // "log value of foo: 1" will be printed to the console + ``` + + @method log + @for Ember.Logger + @param {*} arguments + */ + log: consoleMethod('log') || Ember.K, + /** + Prints the arguments to the console with a warning icon. + You can pass as many arguments as you want and they will be joined together with a space. + + ```javascript + Ember.Logger.warn('Something happened!'); // "Something happened!" will be printed to the console with a warning icon. + ``` + + @method warn + @for Ember.Logger + @param {*} arguments + */ + warn: consoleMethod('warn') || Ember.K, + /** + Prints the arguments to the console with an error icon, red text and a stack race. + You can pass as many arguments as you want and they will be joined together with a space. + + ```javascript + Ember.Logger.error('Danger! Danger!'); // "Danger! Danger!" will be printed to the console in red text. + ``` + + @method error + @for Ember.Logger + @param {*} arguments + */ + error: consoleMethod('error') || Ember.K, + /** + Logs the arguments to the console. + You can pass as many arguments as you want and they will be joined together with a space. + + ```javascript + var foo = 1; + Ember.Logger.info('log value of foo:', foo); // "log value of foo: 1" will be printed to the console + ``` + + @method info + @for Ember.Logger + @param {*} arguments + */ + info: consoleMethod('info') || Ember.K, + /** + Logs the arguments to the console in blue text. + You can pass as many arguments as you want and they will be joined together with a space. + + ```javascript + var foo = 1; + Ember.Logger.debug('log value of foo:', foo); // "log value of foo: 1" will be printed to the console + ``` + + @method debug + @for Ember.Logger + @param {*} arguments + */ + debug: consoleMethod('debug') || consoleMethod('info') || Ember.K, + /** + + If the value passed into Ember.Logger.assert is not truthy it will throw an error with a stack trace. + + ```javascript + Ember.Logger.assert(true); // undefined + Ember.Logger.assert(true === false); // Throws an Assertion failed error. + ``` + + @method assert + @for Ember.Logger + @param {Boolean} bool Value to test + */ + assert: consoleMethod('assert') || assertPolyfill +}; + + +})(); + + + (function() { /** @module ember-metal @@ -4005,14 +4058,14 @@ function isKeyName(path) { @param obj @param {String} keyName */ -Ember.watch = function(obj, keyPath) { +Ember.watch = function(obj, _keyPath) { // can't watch length on Array - it is special... - if (keyPath === 'length' && typeOf(obj) === 'array') { return; } + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } - if (isKeyName(keyPath)) { - watchKey(obj, keyPath); + if (isKeyName(_keyPath)) { + watchKey(obj, _keyPath); } else { - watchPath(obj, keyPath); + watchPath(obj, _keyPath); } }; @@ -4023,14 +4076,14 @@ Ember.isWatching = function isWatching(obj, key) { Ember.watch.flushPending = Ember.flushPendingChains; -Ember.unwatch = function(obj, keyPath) { +Ember.unwatch = function(obj, _keyPath) { // can't watch length on Array - it is special... - if (keyPath === 'length' && typeOf(obj) === 'array') { return; } + if (_keyPath === 'length' && typeOf(obj) === 'array') { return; } - if (isKeyName(keyPath)) { - unwatchKey(obj, keyPath); + if (isKeyName(_keyPath)) { + unwatchKey(obj, _keyPath); } else { - unwatchPath(obj, keyPath); + unwatchPath(obj, _keyPath); } }; @@ -4050,7 +4103,7 @@ Ember.rewatch = function(obj) { // make sure the object has its own guid. if (GUID_KEY in obj && !obj.hasOwnProperty(GUID_KEY)) { - generateGuid(obj, 'ember'); + generateGuid(obj); } // make sure any chained watchers update. @@ -4376,6 +4429,8 @@ ComputedPropertyPrototype.readOnly = function(readOnly) { @chainable */ ComputedPropertyPrototype.property = function() { + var addArg; + var args = []; for (var i = 0, l = arguments.length; i < l; i++) { args.push(arguments[i]); @@ -4507,7 +4562,7 @@ ComputedPropertyPrototype.set = function(obj, keyName, value) { funcArgLength, cachedValue, ret; if (this._readOnly) { - throw new Error('Cannot Set: ' + keyName + ' on: ' + obj.toString() ); + throw new Ember.Error('Cannot Set: ' + keyName + ' on: ' + obj.toString() ); } this._suspended = obj; @@ -4597,7 +4652,7 @@ Ember.computed = function(func) { } if (typeof func !== "function") { - throw new Error("Computed Property declared without a property function"); + throw new Ember.Error("Computed Property declared without a property function"); } var cp = new ComputedProperty(func); @@ -4620,7 +4675,7 @@ Ember.computed = function(func) { @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 {*} the cached value + @return {Object} the cached value */ Ember.cacheFor = function cacheFor(obj, key) { var cache = metaFor(obj, false).cache; @@ -4664,14 +4719,14 @@ function registerComputedWithProperties(name, macro) { property is null, an empty string, empty array, or empty function. Note: When using `Ember.computed.empty` to watch an array make sure to - use the `array.length` syntax so the computed can subscribe to transitions + use the `array.[]` syntax so the computed can subscribe to transitions from empty to non-empty states. Example ```javascript var ToDoList = Ember.Object.extend({ - done: Ember.computed.empty('todos.length') + done: Ember.computed.empty('todos.[]') // detect array changes }); var todoList = ToDoList.create({todos: ['Unit Test', 'Documentation', 'Release']}); todoList.get('done'); // false @@ -4696,13 +4751,13 @@ registerComputed('empty', function(dependentKey) { Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ hasStuff: Ember.computed.notEmpty('backpack') }); - var hampster = Hampster.create({backpack: ['Food', 'Sleeping Bag', 'Tent']}); - hampster.get('hasStuff'); // true - hampster.get('backpack').clear(); // [] - hampster.get('hasStuff'); // false + var hamster = Hamster.create({backpack: ['Food', 'Sleeping Bag', 'Tent']}); + hamster.get('hasStuff'); // true + hamster.get('backpack').clear(); // [] + hamster.get('hasStuff'); // false ``` @method computed.notEmpty @@ -4723,15 +4778,15 @@ registerComputed('notEmpty', function(dependentKey) { Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ isHungry: Ember.computed.none('food') }); - var hampster = Hampster.create(); - hampster.get('isHungry'); // true - hampster.set('food', 'Banana'); - hampster.get('isHungry'); // false - hampster.set('food', null); - hampster.get('isHungry'); // true + 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 @@ -4775,23 +4830,23 @@ registerComputed('not', function(dependentKey) { into a boolean value. ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ hasBananas: Ember.computed.bool('numBananas') }); - var hampster = Hampster.create(); - hampster.get('hasBananas'); // false - hampster.set('numBananas', 0); - hampster.get('hasBananas'); // false - hampster.set('numBananas', 1); - hampster.get('hasBananas'); // true - hampster.set('numBananas', null); - hampster.get('hasBananas'); // false + 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 convert + @return {Ember.ComputedProperty} computed property which converts to boolean the original value for property */ registerComputed('bool', function(dependentKey) { @@ -4813,7 +4868,7 @@ registerComputed('bool', function(dependentKey) { user.get('hasValidEmail'); // false user.set('email', ''); user.get('hasValidEmail'); // false - user.set('email', 'ember_hampster@example.com'); + user.set('email', 'ember_hamster@example.com'); user.get('hasValidEmail'); // true ``` @@ -4826,7 +4881,7 @@ registerComputed('bool', function(dependentKey) { */ registerComputed('match', function(dependentKey, regexp) { var value = get(this, dependentKey); - return typeof value === 'string' ? !!value.match(regexp) : false; + return typeof value === 'string' ? regexp.test(value) : false; }); /** @@ -4836,15 +4891,15 @@ registerComputed('match', function(dependentKey, regexp) { Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ napTime: Ember.computed.equal('state', 'sleepy') }); - var hampster = Hampster.create(); - hampster.get('napTime'); // false - hampster.set('state', 'sleepy'); - hampster.get('napTime'); // true - hampster.set('state', 'hungry'); - hampster.get('napTime'); // false + 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 @@ -4865,15 +4920,15 @@ registerComputed('equal', function(dependentKey, value) { Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ hasTooManyBananas: Ember.computed.gt('numBananas', 10) }); - var hampster = Hampster.create(); - hampster.get('hasTooManyBananas'); // false - hampster.set('numBananas', 3); - hampster.get('hasTooManyBananas'); // false - hampster.set('numBananas', 11); - hampster.get('hasTooManyBananas'); // true + 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 @@ -4894,15 +4949,15 @@ registerComputed('gt', function(dependentKey, value) { Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ hasTooManyBananas: Ember.computed.gte('numBananas', 10) }); - var hampster = Hampster.create(); - hampster.get('hasTooManyBananas'); // false - hampster.set('numBananas', 3); - hampster.get('hasTooManyBananas'); // false - hampster.set('numBananas', 10); - hampster.get('hasTooManyBananas'); // true + 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 @@ -4923,15 +4978,15 @@ registerComputed('gte', function(dependentKey, value) { Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ needsMoreBananas: Ember.computed.lt('numBananas', 3) }); - var hampster = Hampster.create(); - hampster.get('needsMoreBananas'); // true - hampster.set('numBananas', 3); - hampster.get('needsMoreBananas'); // false - hampster.set('numBananas', 2); - hampster.get('needsMoreBananas'); // true + 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 @@ -4952,15 +5007,15 @@ registerComputed('lt', function(dependentKey, value) { Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ needsMoreBananas: Ember.computed.lte('numBananas', 3) }); - var hampster = Hampster.create(); - hampster.get('needsMoreBananas'); // true - hampster.set('numBananas', 5); - hampster.get('needsMoreBananas'); // false - hampster.set('numBananas', 3); - hampster.get('needsMoreBananas'); // true + 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 @@ -4978,24 +5033,23 @@ registerComputed('lte', function(dependentKey, value) { A computed property that performs a logical `and` on the original values for the provided dependent properties. - Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ readyForCamp: Ember.computed.and('hasTent', 'hasBackpack') }); - var hampster = Hampster.create(); - hampster.get('readyForCamp'); // false - hampster.set('hasTent', true); - hampster.get('readyForCamp'); // false - hampster.set('hasBackpack', true); - hampster.get('readyForCamp'); // true + 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, [dependentKey...] + @param {String} dependentKey* @return {Ember.ComputedProperty} computed property which performs a logical `and` on the values of all the original values for properties. */ @@ -5009,24 +5063,24 @@ registerComputedWithProperties('and', function(properties) { }); /** - A computed property that which performs a logical `or` on the + A computed property which performs a logical `or` on the original values for the provided dependent properties. Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ readyForRain: Ember.computed.or('hasJacket', 'hasUmbrella') }); - var hampster = Hampster.create(); - hampster.get('readyForRain'); // false - hampster.set('hasJacket', true); - hampster.get('readyForRain'); // true + var hamster = Hamster.create(); + hamster.get('readyForRain'); // false + hamster.set('hasJacket', true); + hamster.get('readyForRain'); // true ``` @method computed.or @for Ember - @param {String} dependentKey, [dependentKey...] + @param {String} dependentKey* @return {Ember.ComputedProperty} computed property which performs a logical `or` on the values of all the original values for properties. */ @@ -5046,18 +5100,18 @@ registerComputedWithProperties('or', function(properties) { Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ hasClothes: Ember.computed.any('hat', 'shirt') }); - var hampster = Hampster.create(); - hampster.get('hasClothes'); // null - hampster.set('shirt', 'Hawaiian Shirt'); - hampster.get('hasClothes'); // 'Hawaiian 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, [dependentKey...] + @param {String} dependentKey* @return {Ember.ComputedProperty} computed property which returns the first truthy value of given list of properties. */ @@ -5077,19 +5131,19 @@ registerComputedWithProperties('any', function(properties) { Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ clothes: Ember.computed.map('hat', 'shirt') }); - var hampster = Hampster.create(); - hampster.get('clothes'); // [null, null] - hampster.set('hat', 'Camp Hat'); - hampster.set('shirt', 'Camp Shirt'); - hampster.get('clothes'); // ['Camp Hat', 'Camp 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.map @for Ember - @param {String} dependentKey, [dependentKey...] + @param {String} dependentKey* @return {Ember.ComputedProperty} computed property which maps values of all passed properties in to an array. */ @@ -5176,7 +5230,7 @@ Ember.computed.alias = function(dependentKey) { @method computed.oneWay @for Ember @param {String} dependentKey - @return {Ember.ComputedProperty} computed property which creates an + @return {Ember.ComputedProperty} computed property which creates a one way computed property to the original value for property. */ Ember.computed.oneWay = function(dependentKey) { @@ -5188,20 +5242,20 @@ Ember.computed.oneWay = function(dependentKey) { /** A computed property that acts like a standard getter and setter, - but retruns the value at the provided `defaultPath` if the + but returns the value at the provided `defaultPath` if the property itself has not been set to a value Example ```javascript - var Hampster = Ember.Object.extend({ + var Hamster = Ember.Object.extend({ wishList: Ember.computed.defaultTo('favoriteFood') }); - var hampster = Hampster.create({favoriteFood: 'Banana'}); - hampster.get('wishList'); // 'Banana' - hampster.set('wishList', 'More Unit Tests'); - hampster.get('wishList'); // 'More Unit Tests' - hampster.get('favoriteFood'); // 'Banana' + 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 @@ -5220,7 +5274,6 @@ Ember.computed.defaultTo = function(defaultPath) { }; - })(); @@ -5231,8 +5284,8 @@ Ember.computed.defaultTo = function(defaultPath) { @module ember-metal */ -var AFTER_OBSERVERS = ':change'; -var BEFORE_OBSERVERS = ':before'; +var AFTER_OBSERVERS = ':change', + BEFORE_OBSERVERS = ':before'; function changeEvent(keyName) { return keyName+AFTER_OBSERVERS; @@ -5249,9 +5302,10 @@ function beforeEvent(keyName) { @param {Object|Function} targetOrMethod @param {Function|String} [method] */ -Ember.addObserver = function(obj, path, target, method) { - Ember.addListener(obj, changeEvent(path), target, method); - Ember.watch(obj, path); +Ember.addObserver = function(obj, _path, target, method) { + Ember.addListener(obj, changeEvent(_path), target, method); + Ember.watch(obj, _path); + return this; }; @@ -5266,9 +5320,9 @@ Ember.observersFor = function(obj, path) { @param {Object|Function} targetOrMethod @param {Function|String} [method] */ -Ember.removeObserver = function(obj, path, target, method) { - Ember.unwatch(obj, path); - Ember.removeListener(obj, changeEvent(path), target, method); +Ember.removeObserver = function(obj, _path, target, method) { + Ember.unwatch(obj, _path); + Ember.removeListener(obj, changeEvent(_path), target, method); return this; }; @@ -5279,9 +5333,9 @@ Ember.removeObserver = function(obj, path, target, method) { @param {Object|Function} targetOrMethod @param {Function|String} [method] */ -Ember.addBeforeObserver = function(obj, path, target, method) { - Ember.addListener(obj, beforeEvent(path), target, method); - Ember.watch(obj, path); +Ember.addBeforeObserver = function(obj, _path, target, method) { + Ember.addListener(obj, beforeEvent(_path), target, method); + Ember.watch(obj, _path); return this; }; @@ -5320,11 +5374,12 @@ Ember.beforeObserversFor = function(obj, path) { @param {Object|Function} targetOrMethod @param {Function|String} [method] */ -Ember.removeBeforeObserver = function(obj, path, target, method) { - Ember.unwatch(obj, path); - Ember.removeListener(obj, beforeEvent(path), target, method); +Ember.removeBeforeObserver = function(obj, _path, target, method) { + Ember.unwatch(obj, _path); + Ember.removeListener(obj, beforeEvent(_path), target, method); return this; }; + })(); @@ -5556,7 +5611,12 @@ define("backburner", debouncees = [], timers = [], autorun, laterTimer, laterTimerExpiresAt, - global = this; + global = this, + NUMBER = /\d+/; + + function isCoercableNumber(number) { + return typeof number === 'number' || NUMBER.test(number); + } function Backburner(queueNames, options) { this.queueNames = queueNames; @@ -5671,32 +5731,60 @@ define("backburner", }, setTimeout: function() { - var self = this, - wait = pop.call(arguments), - target = arguments[0], - method = arguments[1], - executeAt = (+new Date()) + wait; + var args = slice.call(arguments); + var length = args.length; + var method, wait, target; + var self = this; + var methodOrTarget, methodOrWait, methodOrArgs; - if (!method) { - method = target; - target = null; + if (length === 0) { + return; + } else if (length === 1) { + method = args.shift(); + wait = 0; + } else if (length === 2) { + methodOrTarget = args[0]; + methodOrWait = args[1]; + + if (typeof methodOrWait === 'function' || typeof methodOrTarget[methodOrWait] === 'function') { + 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(); + } + + methodOrTarget = args[0]; + methodOrArgs = args[1]; + + if (typeof methodOrArgs === 'function' || (typeof methodOrArgs === 'string' && + methodOrTarget !== null && + methodOrArgs in methodOrTarget)) { + target = args.shift(); + method = args.shift(); + } else { + method = args.shift(); + } } + var executeAt = (+new Date()) + parseInt(wait, 10); + if (typeof method === 'string') { method = target[method]; } - var fn, args; - if (arguments.length > 2) { - args = slice.call(arguments, 2); - - fn = function() { - method.apply(target, args); - }; - } else { - fn = function() { - method.call(target); - }; + function fn() { + method.apply(target, args); } // find position to insert - TODO: binary search @@ -5726,7 +5814,7 @@ define("backburner", throttle: function(target, method /* , args, wait */) { var self = this, args = arguments, - wait = pop.call(args), + wait = parseInt(pop.call(args), 10), throttler; for (var i = 0, l = throttlers.length; i < l; i++) { @@ -5761,13 +5849,14 @@ define("backburner", index, debouncee; - if (typeof immediate === "number") { + if (typeof immediate === "number" || typeof immediate === "string") { wait = immediate; immediate = false; } else { wait = pop.call(args); } + wait = parseInt(wait, 10); // Remove debouncee index = findDebouncee(target, method); @@ -5897,6 +5986,7 @@ define("backburner", __exports__.Backburner = Backburner; }); + })(); @@ -7032,9 +7122,7 @@ function applyConcatenatedProperties(obj, key, value, values) { return Ember.makeArray(baseValue).concat(value); } } else { - // Make sure this mixin has its own array so it is not - // accidentally mutated by another child's interactions - return Ember.makeArray(value).slice(); + return Ember.makeArray(value); } } @@ -7551,9 +7639,9 @@ Ember.aliasMethod = function(methodName) { ```javascript Ember.Object.extend({ - valueObserver: Ember.observer(function() { + valueObserver: Ember.observer('value', function() { // Executes whenever the "value" property changes - }, 'value') + }) }); ``` @@ -7565,12 +7653,25 @@ Ember.aliasMethod = function(methodName) { @method observer @for Ember - @param {Function} func @param {String} propertyNames* + @param {Function} func @return func */ -Ember.observer = function(func) { - var paths = a_slice.call(arguments, 1); +Ember.observer = function() { + var func = a_slice.call(arguments, -1)[0]; + 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); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.observer called without a function"); + } + func.__ember_observes__ = paths; return func; }; @@ -7580,9 +7681,9 @@ Ember.observer = function(func) { ```javascript Ember.Object.extend({ - valueObserver: Ember.immediateObserver(function() { + valueObserver: Ember.immediateObserver('value', function() { // Executes whenever the "value" property changes - }, 'value') + }) }); ``` @@ -7594,8 +7695,8 @@ Ember.observer = function(func) { @method immediateObserver @for Ember - @param {Function} func @param {String} propertyNames* + @param {Function} func @return func */ Ember.immediateObserver = function() { @@ -7622,22 +7723,22 @@ Ember.immediateObserver = function() { friends: [{ name: 'Tom' }, { name: 'Stefan' }, { name: 'Kris' }], - valueWillChange: Ember.beforeObserver(function(obj, keyName) { + valueWillChange: Ember.beforeObserver('content.value', function(obj, keyName) { this.changingFrom = obj.get(keyName); - }, 'content.value'), + }), - valueDidChange: Ember.observer(function(obj, keyName) { + valueDidChange: Ember.observer('content.value', function(obj, keyName) { // only run if updating a value already in the DOM if (this.get('state') === 'inDOM') { var color = obj.get(keyName) > this.changingFrom ? 'green' : 'red'; // logic } - }, 'content.value'), + }), - friendsDidChange: Ember.observer(function(obj, keyName) { + friendsDidChange: Ember.observer('friends.@each.name', function(obj, keyName) { // some logic // obj.get(keyName) returns friends array - }, 'friends.@each.name') + }) }); ``` @@ -7646,12 +7747,25 @@ Ember.immediateObserver = function() { @method beforeObserver @for Ember - @param {Function} func @param {String} propertyNames* + @param {Function} func @return func */ -Ember.beforeObserver = function(func) { - var paths = a_slice.call(arguments, 1); +Ember.beforeObserver = function() { + var func = a_slice.call(arguments, -1)[0]; + 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); + } + + if (typeof func !== "function") { + throw new Ember.Error("Ember.beforeObserver called without a function"); + } + func.__ember_observesBefore__ = paths; return func; }; @@ -8619,21 +8733,13 @@ define("container", ``` @method register - @param {String} type - @param {String} name + @param {String} fullName @param {Function} factory @param {Object} options */ - register: function(type, name, factory, options) { - var fullName; - - if (type.indexOf(':') !== -1) { - options = factory; - factory = name; - fullName = type; - } else { - Ember.deprecate('register("'+type +'", "'+ name+'") is now deprecated in-favour of register("'+type+':'+name+'");', false); - fullName = type + ":" + name; + register: function(fullName, factory, options) { + if (fullName.indexOf(':') === -1) { + throw new TypeError("malformed fullName, expected: `type:name` got: " + fullName + ""); } if (factory === undefined) { @@ -8642,6 +8748,10 @@ define("container", var normalizedName = this.normalize(fullName); + if (this.cache.has(normalizedName)) { + throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.'); + } + this.registry.set(normalizedName, factory); this._options.set(normalizedName, options || {}); }, @@ -9570,30 +9680,2000 @@ if (!Ember.keys || Ember.create.isSimulated) { }; } -// .......................................................... -// ERROR -// +})(); -var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var STRING_DASHERIZE_REGEXP = (/[ _]/g); +var STRING_DASHERIZE_CACHE = {}; +var STRING_DECAMELIZE_REGEXP = (/([a-z\d])([A-Z])/g); +var STRING_CAMELIZE_REGEXP = (/(\-|_|\.|\s)+(.)?/g); +var STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g); +var STRING_UNDERSCORE_REGEXP_2 = (/\-|\s+/g); /** - A subclass of the JavaScript Error object for use in Ember. + 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. - @class Error - @namespace Ember - @extends Error - @constructor + @property STRINGS + @for Ember + @type Hash */ -Ember.Error = function() { - var tmp = Error.apply(this, arguments); +Ember.STRINGS = {}; - // 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]]; +/** + 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 +*/ +Ember.String = { + + /** + 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: function(str, formats) { + // 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 = formats[argIndex]; + return (s === null) ? '(null)' : (s === undefined) ? '' : Ember.inspect(s); + }) ; + }, + + /** + 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: function(str, formats) { + str = Ember.STRINGS[str] || str; + return Ember.String.fmt(str, formats) ; + }, + + /** + 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 {String} split string + */ + w: function(str) { return str.split(/\s+/); }, + + /** + 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: function(str) { + return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase(); + }, + + /** + 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: function(str) { + var cache = STRING_DASHERIZE_CACHE, + hit = cache.hasOwnProperty(str), + ret; + + if (hit) { + return cache[str]; + } else { + ret = Ember.String.decamelize(str).replace(STRING_DASHERIZE_REGEXP,'-'); + cache[str] = ret; + } + + return ret; + }, + + /** + 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: function(str) { + return str.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) { + return chr ? chr.toUpperCase() : ''; + }).replace(/^([A-Z])/, function(match, separator, chr) { + return match.toLowerCase(); + }); + }, + + /** + 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: function(str) { + var parts = str.split("."), + out = []; + + for (var i=0, l=parts.length; i= 0) { + var baseValue = this[keyName]; + + if (baseValue) { + if ('function' === typeof baseValue.concat) { + value = baseValue.concat(value); + } else { + value = Ember.makeArray(baseValue).concat(value); + } + } else { + value = Ember.makeArray(value); + } + } + + if (desc) { + desc.set(this, keyName, value); + } else { + if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { + this.setUnknownProperty(keyName, value); + } else if (MANDATORY_SETTER) { + Ember.defineProperty(this, keyName, null, value); // setup mandatory setter + } else { + this[keyName] = value; + } + } + } + } + } + finishPartial(this, m); + this.init.apply(this, arguments); + 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() { + applyMixin(this, arguments, 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: Ember.K, + + /** + @private + + Invoked by the run loop to actually destroy the object. This is + scheduled for execution by the `destroy` method. + + @method _scheduledDestroy + */ + _scheduledDestroy: function() { + if (this.isDestroyed) { return; } + destroy(this); + this.isDestroyed = true; + }, + + bind: function(to, from) { + if (!(from instanceof Ember.Binding)) { from = Ember.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. + + 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: + + 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. + + 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', + 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: Ember.required(), + + PrototypeMixin: Ember.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 `Ember.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 = Ember.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 {Ember.Mixin} [mixins]* One or more Ember.Mixin classes + @param {Object} [arguments]* Object containing values to use within the new class + */ + extend: function() { + var Class = makeCtor(), 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; + if (arguments.length>0) { this._initMixins(arguments); } + 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; + if (arguments.length>0) { this._initProperties(arguments); } + 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(); + reopen.apply(this.PrototypeMixin, arguments); + 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() { + reopen.apply(this.ClassMixin, arguments); + 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 desc = meta(this.proto(), false).descs[key]; + + Ember.assert("metaForProperty() could not find a computed property with key '"+key+"'.", !!desc && desc instanceof Ember.ComputedProperty); + return desc._meta || {}; + }, + + /** + 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 proto = this.proto(), + descs = meta(proto).descs, + empty = {}, + property; + + for (var name in descs) { + property = descs[name]; + + if (property instanceof Ember.ComputedProperty) { + callback.call(binding || this, name, property._meta || empty); + } + } + } + +}); + +ClassMixin.ownerConstructor = CoreObject; + +if (Ember.config.overrideClassMixin) { + Ember.config.overrideClassMixin(ClassMixin); +} + +CoreObject.ClassMixin = ClassMixin; +ClassMixin.apply(CoreObject); + +Ember.CoreObject = CoreObject; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +/** + `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 +*/ +Ember.Object = Ember.CoreObject.extend(Ember.Observable); +Ember.Object.toString = function() { return "Ember.Object"; }; + +})(); + + + +(function() { +/** +@module ember +@submodule ember-runtime +*/ + +var get = Ember.get, indexOf = Ember.ArrayPolyfills.indexOf; + +/** + 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 = Ember.Namespace = Ember.Object.extend({ + isNamespace: true, + + init: function() { + Ember.Namespace.NAMESPACES.push(this); + Ember.Namespace.PROCESSED = false; + }, + + toString: function() { + var name = get(this, 'name'); + if (name) { return name; } + + findNamespaces(); + return this[Ember.GUID_KEY+'_name']; + }, + + nameClasses: function() { + processNamespace([this.toString()], this, {}); + }, + + destroy: function() { + var namespaces = Ember.Namespace.NAMESPACES; + Ember.lookup[this.toString()] = undefined; + 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, + guidFor = Ember.guidFor; + +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 +} + +function findNamespaces() { + var Namespace = Ember.Namespace, lookup = Ember.lookup, obj, isNamespace; + + if (Namespace.PROCESSED) { return; } + + for (var prop in lookup) { + // These don't raise exceptions but can cause warnings + if (prop === "parent" || prop === "top" || prop === "frameElement" || prop === "webkitStorageInfo") { continue; } + + // get(window.globalStorage, 'isNamespace') would try to read the storage for domain isNamespace and cause exception in Firefox. + // globalStorage is a storage obsoleted by the WhatWG storage specification. See https://developer.mozilla.org/en/DOM/Storage#globalStorage + if (prop === "globalStorage" && lookup.StorageList && lookup.globalStorage instanceof lookup.StorageList) { 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. + try { + obj = Ember.lookup[prop]; + isNamespace = obj && obj.isNamespace; + } catch (e) { + continue; + } + + if (isNamespace) { + Ember.deprecate("Namespaces should not begin with lowercase.", /^[A-Z]/.test(prop)); + obj[NAME_KEY] = prop; + } + } +} + +var NAME_KEY = Ember.NAME_KEY = Ember.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, + unprocessedMixins = Ember.anyUnprocessedMixins; + + if (unprocessedNamespaces) { + findNamespaces(); + Namespace.PROCESSED = true; + } + + if (unprocessedNamespaces || unprocessedMixins) { + var namespaces = Namespace.NAMESPACES, namespace; + for (var i=0, l=namespaces.length; i= 0; --sliceIndex) { - itemIndex = index + sliceIndex; + for (sliceIndex = normalizedRemoveCount - 1; sliceIndex >= 0; --sliceIndex) { + itemIndex = normalizedIndex + sliceIndex; + if (itemIndex >= length) { break; } + item = dependentArray.objectAt(itemIndex); forEach(itemPropertyKeys, removeObservers, this); @@ -11276,31 +13373,35 @@ DependentArraysObserver.prototype = { }, dependentArrayDidChange: function (dependentArray, index, removedCount, addedCount) { + if (this.suspended) { return; } + var addedItem = this.callbacks.addedItem, guid = guidFor(dependentArray), dependentKey = this.dependentKeysByGuid[guid], observerContexts = new Array(addedCount), itemPropertyKeys = this.cp._itemPropertyKeys[dependentKey], + length = get(dependentArray, 'length'), + normalizedIndex = normalizeIndex(index, length, addedCount), changeMeta, observerContext; - forEach(dependentArray.slice(index, index + addedCount), function (item, sliceIndex) { + forEach(dependentArray.slice(normalizedIndex, normalizedIndex + addedCount), function (item, sliceIndex) { if (itemPropertyKeys) { observerContext = observerContexts[sliceIndex] = - this.createPropertyObserverContext(dependentArray, index + sliceIndex, this.trackedArraysByGuid[dependentKey]); + this.createPropertyObserverContext(dependentArray, normalizedIndex + sliceIndex, this.trackedArraysByGuid[dependentKey]); forEach(itemPropertyKeys, function (propertyKey) { addBeforeObserver(item, propertyKey, this, observerContext.beforeObserver); addObserver(item, propertyKey, this, observerContext.observer); }, this); } - changeMeta = createChangeMeta(dependentArray, item, index + sliceIndex, this.instanceMeta.propertyName, this.cp); + changeMeta = createChangeMeta(dependentArray, item, normalizedIndex + sliceIndex, this.instanceMeta.propertyName, this.cp); this.setValue( addedItem.call( this.instanceMeta.context, this.getValue(), item, changeMeta, this.instanceMeta.sugarMeta)); }, this); - this.addTransformation(dependentKey, index, observerContexts); + this.trackAdd(dependentKey, normalizedIndex, observerContexts); }, itemPropertyWillChange: function (obj, keyName, array, observerContext) { @@ -11341,6 +13442,20 @@ DependentArraysObserver.prototype = { } }; +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 createChangeMeta(dependentArray, item, index, propertyName, property, previousValues) { var meta = { arrayChanged: dependentArray, @@ -11459,30 +13574,32 @@ function ReduceComputedProperty(options) { reset.call(this, cp, propertyName); - forEach(cp._dependentKeys, function (dependentKey) { - var dependentArray = get(this, dependentKey), - previousDependentArray = meta.dependentArrays[dependentKey]; + meta.dependentArraysObserver.suspendArrayObservers(function () { + forEach(cp._dependentKeys, function (dependentKey) { + var dependentArray = get(this, dependentKey), + 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 (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 (previousDependentArray) { + meta.dependentArraysObserver.teardownObservers(previousDependentArray, dependentKey); + } - if (dependentArray) { - meta.dependentArraysObserver.setupObservers(dependentArray, dependentKey); + if (dependentArray) { + meta.dependentArraysObserver.setupObservers(dependentArray, dependentKey); + } } - } + }, this); }, this); forEach(cp._dependentKeys, function(dependentKey) { @@ -11541,13 +13658,11 @@ ReduceComputedProperty.prototype._instanceMeta = function (context, propertyName }; ReduceComputedProperty.prototype.initialValue = function () { - switch (typeof this.options.initialValue) { - case 'undefined': - throw new Error("reduce computed properties require an initial value: did you forget to pass one to Ember.reduceComputed?"); - case 'function': - return this.options.initialValue(); - default: - return this.options.initialValue; + if (typeof this.options.initialValue === 'function') { + return this.options.initialValue(); + } + else { + return this.options.initialValue; } }; @@ -11570,25 +13685,25 @@ ReduceComputedProperty.prototype.clearItemPropertyKeys = function (dependentArra ReduceComputedProperty.prototype.property = function () { var cp = this, args = a_slice.call(arguments), - propertyArgs = [], + propertyArgs = new Ember.Set(), match, dependentArrayKey, itemPropertyKey; forEach(a_slice.call(arguments), function (dependentKey) { if (doubleEachPropertyPattern.test(dependentKey)) { - throw new Error("Nested @each properties not supported: " + dependentKey); + throw new Ember.Error("Nested @each properties not supported: " + dependentKey); } else if (match = eachPropertyPattern.exec(dependentKey)) { dependentArrayKey = match[1]; itemPropertyKey = match[2]; cp.itemPropertyKey(dependentArrayKey, itemPropertyKey); - propertyArgs.push(dependentArrayKey); + propertyArgs.add(dependentArrayKey); } else { - propertyArgs.push(dependentKey); + propertyArgs.add(dependentKey); } }); - return ComputedProperty.prototype.property.apply(this, propertyArgs); + return ComputedProperty.prototype.property.apply(this, propertyArgs.toArray()); }; /** @@ -11707,7 +13822,7 @@ ReduceComputedProperty.prototype.property = function () { }; ``` - Dependent keys may refer to `@self` to observe changes to the object itself, + 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. @@ -11718,7 +13833,7 @@ ReduceComputedProperty.prototype.property = function () { App.PeopleController = Ember.ArrayController.extend({ itemController: 'person', - sortedPeople: Ember.computed.sort('@self.@each.reversedName', function(personA, personB) { + 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 @@ -11753,11 +13868,11 @@ Ember.reduceComputed = function (options) { } if (typeof options !== "object") { - throw new Error("Reduce Computed Property declared without an options hash"); + throw new Ember.Error("Reduce Computed Property declared without an options hash"); } - if (Ember.isNone(options.initialValue)) { - throw new Error("Reduce Computed Property declared without an initial value"); + if (!('initialValue' in options)) { + throw new Ember.Error("Reduce Computed Property declared without an initial value"); } var cp = new ReduceComputedProperty(options); @@ -11936,7 +14051,7 @@ Ember.arrayComputed = function (options) { } if (typeof options !== "object") { - throw new Error("Array Computed Property declared without an options hash"); + throw new Ember.Error("Array Computed Property declared without an options hash"); } var cp = new ArrayComputedProperty(options); @@ -11964,7 +14079,8 @@ var get = Ember.get, merge = Ember.merge, a_slice = [].slice, forEach = Ember.EnumerableUtils.forEach, - map = Ember.EnumerableUtils.map; + map = Ember.EnumerableUtils.map, + SearchProxy; /** A computed property that calculates the maximum value in the @@ -12064,14 +14180,14 @@ Ember.computed.min = function (dependentKey) { Example ```javascript - App.Hampster = Ember.Object.extend({ + App.Hamster = Ember.Object.extend({ excitingChores: Ember.computed.map('chores', function(chore) { return chore.toUpperCase() + '!'; }) }); - var hampster = App.Hampster.create({chores: ['cook', 'clean', 'write more unit tests']}); - hampster.get('excitingChores'); // ['COOK!', 'CLEAN!', 'WRITE MORE UNIT TESTS!'] + var hamster = App.Hamster.create({chores: ['cook', 'clean', 'write more unit tests']}); + hamster.get('excitingChores'); // ['COOK!', 'CLEAN!', 'WRITE MORE UNIT TESTS!'] ``` @method computed.map @@ -12148,18 +14264,18 @@ Ember.computed.mapProperty = Ember.computed.mapBy; Example ```javascript - App.Hampster = Ember.Object.extend({ + App.Hamster = Ember.Object.extend({ remainingChores: Ember.computed.filter('chores', function(chore) { return !chore.done; }) }); - var hampster = App.Hampster.create({chores: [ + var hamster = App.Hamster.create({chores: [ {name: 'cook', done: true}, {name: 'clean', done: true}, {name: 'write more unit tests', done: false} ]}); - hampster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] + hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] ``` @method computed.filter @@ -12205,16 +14321,16 @@ Ember.computed.filter = function(dependentKey, callback) { Example ```javascript - App.Hampster = Ember.Object.extend({ + App.Hamster = Ember.Object.extend({ remainingChores: Ember.computed.filterBy('chores', 'done', false) }); - var hampster = App.Hampster.create({chores: [ + var hamster = App.Hamster.create({chores: [ {name: 'cook', done: true}, {name: 'clean', done: true}, {name: 'write more unit tests', done: false} ]}); - hampster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] + hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] ``` @method computed.filterBy @@ -12257,17 +14373,17 @@ Ember.computed.filterProperty = Ember.computed.filterBy; Example ```javascript - App.Hampster = Ember.Object.extend({ + App.Hamster = Ember.Object.extend({ uniqueFruits: Ember.computed.uniq('fruits') }); - var hampster = App.Hampster.create({fruits: [ + var hamster = App.Hamster.create({fruits: [ 'banana', 'grape', 'kale', 'banana' ]}); - hampster.get('uniqueFruits'); // ['banana', 'grape', 'kale'] + hamster.get('uniqueFruits'); // ['banana', 'grape', 'kale'] ``` @method computed.uniq @@ -12402,16 +14518,16 @@ Ember.computed.intersect = function () { Example ```javascript - App.Hampster = Ember.Object.extend({ + App.Hamster = Ember.Object.extend({ likes: ['banana', 'grape', 'kale'], wants: Ember.computed.setDiff('likes', 'fruits') }); - var hampster = App.Hampster.create({fruits: [ + var hamster = App.Hamster.create({fruits: [ 'grape', 'kale', ]}); - hampster.get('wants'); // ['banana'] + hamster.get('wants'); // ['banana'] ``` @method computed.setDiff @@ -12424,7 +14540,7 @@ Ember.computed.intersect = function () { */ Ember.computed.setDiff = function (setAProperty, setBProperty) { if (arguments.length !== 2) { - throw new Error("setDiff requires exactly two dependent arrays."); + throw new Ember.Error("setDiff requires exactly two dependent arrays."); } return Ember.arrayComputed.call(null, setAProperty, setBProperty, { addedItem: function (array, item, changeMeta, instanceMeta) { @@ -12492,13 +14608,16 @@ function binarySearch(array, item, low, high) { return mid; function _guidFor(item) { - if (Ember.ObjectProxy.detectInstance(item)) { + if (SearchProxy.detectInstance(item)) { return guidFor(get(item, 'content')); } return guidFor(item); } } + +SearchProxy = Ember.ObjectProxy.extend(); + /** A computed property which returns a new array with all the properties from the first dependent array sorted based on a property @@ -12640,10 +14759,10 @@ Ember.computed.sort = function (itemsKey, sortDefinition) { if (changeMeta.previousValues) { proxyProperties = merge({ content: item }, changeMeta.previousValues); - searchItem = Ember.ObjectProxy.create(proxyProperties); - } else { - searchItem = item; - } + searchItem = SearchProxy.create(proxyProperties); + } else { + searchItem = item; + } index = instanceMeta.binarySearch(array, searchItem); array.removeAt(index); @@ -12672,420 +14791,6 @@ Ember.RSVP = requireModule('rsvp'); -(function() { -/** -@module ember -@submodule ember-runtime -*/ - -var STRING_DASHERIZE_REGEXP = (/[ _]/g); -var STRING_DASHERIZE_CACHE = {}; -var STRING_DECAMELIZE_REGEXP = (/([a-z])([A-Z])/g); -var STRING_CAMELIZE_REGEXP = (/(\-|_|\.|\s)+(.)?/g); -var STRING_UNDERSCORE_REGEXP_1 = (/([a-z\d])([A-Z]+)/g); -var STRING_UNDERSCORE_REGEXP_2 = (/\-|\s+/g); - -/** - 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 -*/ -Ember.String = { - - /** - 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: function(str, formats) { - // 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 = formats[argIndex]; - return (s === null) ? '(null)' : (s === undefined) ? '' : Ember.inspect(s); - }) ; - }, - - /** - 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: function(str, formats) { - str = Ember.STRINGS[str] || str; - return Ember.String.fmt(str, formats) ; - }, - - /** - 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 {String} split string - */ - w: function(str) { return str.split(/\s+/); }, - - /** - 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: function(str) { - return str.replace(STRING_DECAMELIZE_REGEXP, '$1_$2').toLowerCase(); - }, - - /** - 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: function(str) { - var cache = STRING_DASHERIZE_CACHE, - hit = cache.hasOwnProperty(str), - ret; - - if (hit) { - return cache[str]; - } else { - ret = Ember.String.decamelize(str).replace(STRING_DASHERIZE_REGEXP,'-'); - cache[str] = ret; - } - - return ret; - }, - - /** - 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: function(str) { - return str.replace(STRING_CAMELIZE_REGEXP, function(match, separator, chr) { - return chr ? chr.toUpperCase() : ''; - }).replace(/^([A-Z])/, function(match, separator, chr) { - return match.toLowerCase(); - }); - }, - - /** - 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: function(str) { - var parts = str.split("."), - out = []; - - for (var i=0, l=parts.length; i get(this, 'length')) throw new Error(OUT_OF_RANGE_EXCEPTION) ; + if (idx > get(this, 'length')) throw new Ember.Error(OUT_OF_RANGE_EXCEPTION) ; this.replace(idx, 0, [object]) ; return this ; }, @@ -13726,7 +15431,7 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,/** if ('number' === typeof start) { if ((start < 0) || (start >= get(this, 'length'))) { - throw new Error(OUT_OF_RANGE_EXCEPTION); + throw new Ember.Error(OUT_OF_RANGE_EXCEPTION); } // fast case @@ -13920,497 +15625,6 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,/** -(function() { -/** -@module ember -@submodule ember-runtime -*/ - -var get = Ember.get, - set = Ember.set, - slice = Array.prototype.slice, - getProperties = Ember.getProperties; - -/** - ## 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 -*/ -Ember.Observable = Ember.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.getEach('firstName', 'lastName').compact().join(' '); - }.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 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 getProperties.apply(null, [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; - }, - - /** - To set multiple properties at once, call `setProperties` - with a Hash: - - ```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 Ember.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() { - Ember.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() { - Ember.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) { - Ember.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) { - Ember.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) { - Ember.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. - @return {Ember.Object} self - */ - addObserver: function(key, target, method) { - Ember.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. - @return {Ember.Observable} receiver - */ - removeObserver: function(key, target, method) { - Ember.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 Ember.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 Ember.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 (Ember.isNone(increment)) { increment = 1; } - Ember.assert("Must pass a numeric value to incrementProperty", (!isNaN(parseFloat(increment)) && isFinite(increment))); - set(this, keyName, (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 (Ember.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 Ember.cacheFor(this, keyName); - }, - - // intended for debugging purposes - observersForKey: function(keyName) { - return Ember.observersFor(this, keyName); - } -}); - -})(); - - - (function() { /** @module ember @@ -14520,6 +15734,13 @@ Ember.TargetActionSupport = Ember.Mixin.create({ target = opts.target || get(this, 'targetObject'), 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; } @@ -14528,10 +15749,10 @@ Ember.TargetActionSupport = Ember.Mixin.create({ var ret; if (target.send) { - ret = target.send.apply(target, [action, actionContext]); + 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, [actionContext]); + ret = target[action].apply(target, args(actionContext)); } if (ret !== false) ret = true; @@ -14783,7 +16004,7 @@ Ember.DeferredMixin = Ember.Mixin.create({ @submodule ember-runtime */ -var get = Ember.get; +var get = Ember.get, typeOf = Ember.typeOf; /** The `Ember.ActionHandler` mixin implements support for moving an `actions` @@ -14809,9 +16030,21 @@ Ember.ActionHandler = Ember.Mixin.create({ @method willMergeMixin */ willMergeMixin: function(props) { - if (props.actions && !props._actions) { - props._actions = Ember.merge(props._actions || {}, props.actions); - delete props.actions; + var hashName; + + if (!props._actions) { + 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 = Ember.merge(props._actions || {}, props[hashName]); + } + + delete props[hashName]; } }, @@ -14856,16 +16089,15 @@ var set = Ember.set, get = Ember.get, @submodule ember-runtime */ -function installPromise(proxy, promise) { +function observePromise(proxy, promise) { promise.then(function(value) { set(proxy, 'isFulfilled', true); set(proxy, 'content', value); - - return value; }, function(reason) { set(proxy, 'isRejected', true); set(proxy, 'reason', reason); - }).fail(rethrow); + // don't re-throw, as we are merely observing + }); } /** @@ -14943,10 +16175,10 @@ Ember.PromiseProxyMixin = Ember.Mixin.create({ promise: Ember.computed(function(key, promise) { if (arguments.length === 2) { promise = resolve(promise); - installPromise(this, promise); - return promise; + observePromise(this, promise); + return promise.then(); // fork the promise. } else { - throw new Error("PromiseProxy's promise must be set"); + throw new Ember.Error("PromiseProxy's promise must be set"); } }), @@ -14956,6 +16188,7 @@ Ember.PromiseProxyMixin = Ember.Mixin.create({ }); + })(); @@ -14989,9 +16222,9 @@ Ember.TrackedArray = function (items) { var length = get(items, 'length'); if (length) { - this._content = [new ArrayOperation(RETAIN, length, items)]; + this._operations = [new ArrayOperation(RETAIN, length, items)]; } else { - this._content = []; + this._operations = []; } }; @@ -15009,8 +16242,10 @@ Ember.TrackedArray.prototype = { @param newItems */ addItems: function (index, newItems) { - var count = get(newItems, 'length'), - match = this._findArrayOperation(index), + var count = get(newItems, 'length'); + if (count < 1) { return; } + + var match = this._findArrayOperation(index), arrayOperation = match.operation, arrayOperationIndex = match.index, arrayOperationRangeStart = match.rangeStart, @@ -15025,7 +16260,7 @@ Ember.TrackedArray.prototype = { if (arrayOperation) { if (!match.split) { // insert left of arrayOperation - this._content.splice(arrayOperationIndex, 0, newArrayOperation); + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); composeIndex = arrayOperationIndex; } else { this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); @@ -15033,7 +16268,7 @@ Ember.TrackedArray.prototype = { } } else { // insert at end - this._content.push(newArrayOperation); + this._operations.push(newArrayOperation); composeIndex = arrayOperationIndex; } @@ -15048,6 +16283,8 @@ Ember.TrackedArray.prototype = { @param count */ removeItems: function (index, count) { + if (count < 1) { return; } + var match = this._findArrayOperation(index), arrayOperation = match.operation, arrayOperationIndex = match.index, @@ -15058,7 +16295,7 @@ Ember.TrackedArray.prototype = { newArrayOperation = new ArrayOperation(DELETE, count); if (!match.split) { // insert left of arrayOperation - this._content.splice(arrayOperationIndex, 0, newArrayOperation); + this._operations.splice(arrayOperationIndex, 0, newArrayOperation); composeIndex = arrayOperationIndex; } else { this._split(arrayOperationIndex, index - arrayOperationRangeStart, newArrayOperation); @@ -15073,12 +16310,11 @@ Ember.TrackedArray.prototype = { 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}` -* + * {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 @@ -15087,16 +16323,16 @@ array of the first item for this operation. var items = [], offset = 0; - forEach(this._content, function (arrayOperation) { - callback(arrayOperation.items, offset, arrayOperation.operation); + forEach(this._operations, function (arrayOperation) { + callback(arrayOperation.items, offset, arrayOperation.type); - if (arrayOperation.operation !== DELETE) { + if (arrayOperation.type !== DELETE) { offset += arrayOperation.count; items = items.concat(arrayOperation.items); } }); - this._content = [new ArrayOperation(RETAIN, items.length, items)]; + this._operations = [new ArrayOperation(RETAIN, items.length, items)]; }, /** @@ -15118,10 +16354,10 @@ array of the first item for this operation. // 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._content.length; arrayOperationIndex < len; ++arrayOperationIndex) { - arrayOperation = this._content[arrayOperationIndex]; + for (arrayOperationIndex = arrayOperationRangeStart = 0, len = this._operations.length; arrayOperationIndex < len; ++arrayOperationIndex) { + arrayOperation = this._operations[arrayOperationIndex]; - if (arrayOperation.operation === DELETE) { continue; } + if (arrayOperation.type === DELETE) { continue; } arrayOperationRangeEnd = arrayOperationRangeStart + arrayOperation.count - 1; @@ -15139,25 +16375,24 @@ array of the first item for this operation. }, _split: function (arrayOperationIndex, splitIndex, newArrayOperation) { - var arrayOperation = this._content[arrayOperationIndex], + var arrayOperation = this._operations[arrayOperationIndex], splitItems = arrayOperation.items.slice(splitIndex), - splitArrayOperation = new ArrayOperation(arrayOperation.operation, splitItems.length, splitItems); + splitArrayOperation = new ArrayOperation(arrayOperation.type, splitItems.length, splitItems); // truncate LHS arrayOperation.count = splitIndex; arrayOperation.items = arrayOperation.items.slice(0, splitIndex); - this._content.splice(arrayOperationIndex + 1, 0, newArrayOperation, splitArrayOperation); + this._operations.splice(arrayOperationIndex + 1, 0, newArrayOperation, splitArrayOperation); }, - // TODO: unify _composeInsert, _composeDelete // see SubArray for a better implementation. _composeInsert: function (index) { - var newArrayOperation = this._content[index], - leftArrayOperation = this._content[index-1], // may be undefined - rightArrayOperation = this._content[index+1], // may be undefined - leftOp = leftArrayOperation && leftArrayOperation.operation, - rightOp = rightArrayOperation && rightArrayOperation.operation; + var newArrayOperation = this._operations[index], + leftArrayOperation = this._operations[index-1], // may be undefined + rightArrayOperation = this._operations[index+1], // may be undefined + leftOp = leftArrayOperation && leftArrayOperation.type, + rightOp = rightArrayOperation && rightArrayOperation.type; if (leftOp === INSERT) { // merge left @@ -15165,30 +16400,31 @@ array of the first item for this operation. leftArrayOperation.items = leftArrayOperation.items.concat(newArrayOperation.items); if (rightOp === INSERT) { - // also merge right + // also merge right (we have split an insert with an insert) leftArrayOperation.count += rightArrayOperation.count; leftArrayOperation.items = leftArrayOperation.items.concat(rightArrayOperation.items); - this._content.splice(index, 2); + this._operations.splice(index, 2); } else { // only merge left - this._content.splice(index, 1); + this._operations.splice(index, 1); } } else if (rightOp === INSERT) { // merge right newArrayOperation.count += rightArrayOperation.count; newArrayOperation.items = newArrayOperation.items.concat(rightArrayOperation.items); - this._content.splice(index + 1, 1); + this._operations.splice(index + 1, 1); } }, _composeDelete: function (index) { - var arrayOperation = this._content[index], + var arrayOperation = this._operations[index], deletesToGo = arrayOperation.count, - leftArrayOperation = this._content[index-1], // may be undefined - leftOp = leftArrayOperation && leftArrayOperation.operation, + leftArrayOperation = this._operations[index-1], // may be undefined + leftOp = leftArrayOperation && leftArrayOperation.type, nextArrayOperation, nextOp, nextCount, + removeNewAndNextOp = false, removedItems = []; if (leftOp === DELETE) { @@ -15197,8 +16433,8 @@ array of the first item for this operation. } for (var i = index + 1; deletesToGo > 0; ++i) { - nextArrayOperation = this._content[i]; - nextOp = nextArrayOperation.operation; + nextArrayOperation = this._operations[i]; + nextOp = nextArrayOperation.type; nextCount = nextArrayOperation.count; if (nextOp === DELETE) { @@ -15207,6 +16443,7 @@ array of the first item for this operation. } 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; @@ -15218,29 +16455,57 @@ array of the first item for this operation. 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) { - this._content.splice(index+1, i-1-index); + // 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 - this._content.splice(index, 1); + // 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 + @property {string} type The type of the operation. One of + `Ember.TrackedArray.{RETAIN, INSERT, DELETE}` + @property {number} count The number of items in this operation. + @property {array} items The items of the operation, if included. RETAIN and + INSERT include their items, DELETE does not. +*/ function ArrayOperation (operation, count, items) { - this.operation = operation; // RETAIN | INSERT | DELETE + this.type = operation; // RETAIN | INSERT | DELETE this.count = count; this.items = items; } @@ -15378,6 +16643,8 @@ Ember.SubArray.prototype = { self._operations.splice(operationIndex, 1); self._composeAt(operationIndex); } + }, function() { + throw new Ember.Error("Can't remove an item that has never been added."); }); return returnValue; @@ -15458,981 +16725,6 @@ Ember.Container.set = Ember.set; -(function() { -/** -@module ember -@submodule ember-runtime -*/ - - -// NOTE: this object should never be included directly. Instead use `Ember.Object`. -// We only define this separately so that `Ember.Set` can depend on it. - - -var set = Ember.set, get = Ember.get, - o_create = Ember.create, - o_defineProperty = Ember.platform.defineProperty, - GUID_KEY = Ember.GUID_KEY, - guidFor = Ember.guidFor, - generateGuid = Ember.generateGuid, - meta = Ember.meta, - rewatch = Ember.rewatch, - finishChains = Ember.finishChains, - sendEvent = Ember.sendEvent, - destroy = Ember.destroy, - schedule = Ember.run.schedule, - Mixin = Ember.Mixin, - applyMixin = Mixin._apply, - finishPartial = Mixin.finishPartial, - reopen = Mixin.prototype.reopen, - MANDATORY_SETTER = Ember.ENV.MANDATORY_SETTER, - indexOf = Ember.EnumerableUtils.indexOf; - -var undefinedDescriptor = { - configurable: true, - writable: true, - enumerable: false, - value: undefined -}; - -function makeCtor() { - - // Note: avoid accessing any properties on the object since it makes the - // method a lot faster. This is glue code so we want it to be as fast as - // possible. - - var wasApplied = false, initMixins, initProperties; - - var Class = function() { - if (!wasApplied) { - Class.proto(); // prepare prototype... - } - o_defineProperty(this, GUID_KEY, undefinedDescriptor); - o_defineProperty(this, '_super', undefinedDescriptor); - var m = meta(this), proto = m.proto; - m.proto = this; - if (initMixins) { - // capture locally so we can clear the closed over variable - var mixins = initMixins; - initMixins = null; - this.reopen.apply(this, mixins); - } - if (initProperties) { - // capture locally so we can clear the closed over variable - var props = initProperties; - initProperties = null; - - var concatenatedProperties = this.concatenatedProperties; - - for (var i = 0, l = props.length; i < l; i++) { - var properties = props[i]; - - Ember.assert("Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead.", !(properties instanceof Ember.Mixin)); - - if (Ember.typeOf(properties) !== 'object') { continue; } - - var keyNames = Ember.keys(properties); - for (var j = 0, ll = keyNames.length; j < ll; j++) { - var keyName = keyNames[j]; - if (!properties.hasOwnProperty(keyName)) { continue; } - - var value = properties[keyName], - IS_BINDING = Ember.IS_BINDING; - - if (IS_BINDING.test(keyName)) { - var bindings = m.bindings; - if (!bindings) { - bindings = m.bindings = {}; - } else if (!m.hasOwnProperty('bindings')) { - bindings = m.bindings = o_create(m.bindings); - } - bindings[keyName] = value; - } - - var desc = m.descs[keyName]; - - Ember.assert("Ember.Object.create no longer supports defining computed properties.", !(value instanceof Ember.ComputedProperty)); - Ember.assert("Ember.Object.create no longer supports defining methods that call _super.", !(typeof value === 'function' && value.toString().indexOf('._super') !== -1)); - Ember.assert("`actions` must be provided at extend time, not at create time, when Ember.ActionHandler is used (i.e. views, controllers & routes).", !((keyName === 'actions') && Ember.ActionHandler.detect(this))); - - if (concatenatedProperties && indexOf(concatenatedProperties, keyName) >= 0) { - var baseValue = this[keyName]; - - if (baseValue) { - if ('function' === typeof baseValue.concat) { - value = baseValue.concat(value); - } else { - value = Ember.makeArray(baseValue).concat(value); - } - } else { - value = Ember.makeArray(value); - } - } - - if (desc) { - desc.set(this, keyName, value); - } else { - if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { - this.setUnknownProperty(keyName, value); - } else if (MANDATORY_SETTER) { - Ember.defineProperty(this, keyName, null, value); // setup mandatory setter - } else { - this[keyName] = value; - } - } - } - } - } - finishPartial(this, m); - this.init.apply(this, arguments); - 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() { - applyMixin(this, arguments, 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() { - this._super(); - 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: Ember.K, - - /** - @private - - Invoked by the run loop to actually destroy the object. This is - scheduled for execution by the `destroy` method. - - @method _scheduledDestroy - */ - _scheduledDestroy: function() { - if (this.isDestroyed) { return; } - destroy(this); - this.isDestroyed = true; - }, - - bind: function(to, from) { - if (!(from instanceof Ember.Binding)) { from = Ember.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. - - 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: - - 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. - - 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', - 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: Ember.required(), - - PrototypeMixin: Ember.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 `Ember.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 = Ember.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 {Ember.Mixin} [mixins]* One or more Ember.Mixin classes - @param {Object} [arguments]* Object containing values to use within the new class - */ - extend: function() { - var Class = makeCtor(), 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, 'ember'); - 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; - if (arguments.length>0) { this._initMixins(arguments); } - 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; - if (arguments.length>0) { this._initProperties(arguments); } - 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(); - reopen.apply(this.PrototypeMixin, arguments); - 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(); - ``` - - To add functions and properties to instances of - a constructor by extending the constructor's prototype - see `reopen` - - @method reopenClass - */ - reopenClass: function() { - reopen.apply(this.ClassMixin, arguments); - 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 desc = meta(this.proto(), false).descs[key]; - - Ember.assert("metaForProperty() could not find a computed property with key '"+key+"'.", !!desc && desc instanceof Ember.ComputedProperty); - return desc._meta || {}; - }, - - /** - 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 proto = this.proto(), - descs = meta(proto).descs, - empty = {}, - property; - - for (var name in descs) { - property = descs[name]; - - if (property instanceof Ember.ComputedProperty) { - callback.call(binding || this, name, property._meta || empty); - } - } - } - -}); - -ClassMixin.ownerConstructor = CoreObject; - -if (Ember.config.overrideClassMixin) { - Ember.config.overrideClassMixin(ClassMixin); -} - -CoreObject.ClassMixin = ClassMixin; -ClassMixin.apply(CoreObject); - -Ember.CoreObject = CoreObject; - -})(); - - - -(function() { -/** -@module ember -@submodule ember-runtime -*/ - -if (Ember.FEATURES.isEnabled("em-o")) { - /** - Shorthand for `Ember.Object.create(properties)`. - - Wraps a vanilla/native object in an `Ember.Object` instance with the same - properties. The `properties` argument will not be altered. - - If you pass an instance of `Ember.Object` as the `properties` argument, the - same object will be returned. - - Example: - - ```javascript - var john1 = Ember.O({name: 'John'}); - //...has the same effect as: - var john2 = Ember.Object.create({name: 'John'}); - - console.log(john1 === Em.O(john1); //true - ``` - - @method O - @for Ember - @param {Object} [properties] - @returns Ember.Object - */ - Ember.O = function(properties) { - return Ember.Object.detectInstance(properties) ? properties : Ember.Object.create(properties); - }; -} - -/** - `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 -*/ -Ember.Object = Ember.CoreObject.extend(Ember.Observable); -Ember.Object.toString = function() { return "Ember.Object"; }; - -})(); - - - -(function() { -/** -@module ember -@submodule ember-runtime -*/ - -var get = Ember.get, indexOf = Ember.ArrayPolyfills.indexOf; - -/** - 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 = Ember.Namespace = Ember.Object.extend({ - isNamespace: true, - - init: function() { - Ember.Namespace.NAMESPACES.push(this); - Ember.Namespace.PROCESSED = false; - }, - - toString: function() { - var name = get(this, 'name'); - if (name) { return name; } - - findNamespaces(); - return this[Ember.GUID_KEY+'_name']; - }, - - nameClasses: function() { - processNamespace([this.toString()], this, {}); - }, - - destroy: function() { - var namespaces = Ember.Namespace.NAMESPACES; - Ember.lookup[this.toString()] = undefined; - 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, - guidFor = Ember.guidFor; - -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 -} - -function findNamespaces() { - var Namespace = Ember.Namespace, lookup = Ember.lookup, obj, isNamespace; - - if (Namespace.PROCESSED) { return; } - - for (var prop in lookup) { - // These don't raise exceptions but can cause warnings - if (prop === "parent" || prop === "top" || prop === "frameElement" || prop === "webkitStorageInfo") { continue; } - - // get(window.globalStorage, 'isNamespace') would try to read the storage for domain isNamespace and cause exception in Firefox. - // globalStorage is a storage obsoleted by the WhatWG storage specification. See https://developer.mozilla.org/en/DOM/Storage#globalStorage - if (prop === "globalStorage" && lookup.StorageList && lookup.globalStorage instanceof lookup.StorageList) { 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. - try { - obj = Ember.lookup[prop]; - isNamespace = obj && obj.isNamespace; - } catch (e) { - continue; - } - - if (isNamespace) { - Ember.deprecate("Namespaces should not begin with lowercase.", /^[A-Z]/.test(prop)); - obj[NAME_KEY] = prop; - } - } -} - -var NAME_KEY = Ember.NAME_KEY = Ember.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, - unprocessedMixins = Ember.anyUnprocessedMixins; - - if (unprocessedNamespaces) { - findNamespaces(); - Namespace.PROCESSED = true; - } - - if (unprocessedNamespaces || unprocessedMixins) { - var namespaces = Namespace.NAMESPACES, namespace; - for (var i=0, l=namespaces.length; i get(this, 'content.length')) throw new Error(OUT_OF_RANGE_EXCEPTION); + if (idx > get(this, 'content.length')) throw new Ember.Error(OUT_OF_RANGE_EXCEPTION); this._replace(idx, 0, [object]); return this; }, @@ -16688,7 +16980,7 @@ Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,/** @scope Ember.Array indices = [], i; if ((start < 0) || (start >= get(this, 'length'))) { - throw new Error(OUT_OF_RANGE_EXCEPTION); + throw new Ember.Error(OUT_OF_RANGE_EXCEPTION); } if (len === undefined) len = 1; @@ -16772,159 +17064,6 @@ Ember.ArrayProxy = Ember.Object.extend(Ember.MutableArray,/** @scope Ember.Array -(function() { -/** -@module ember -@submodule ember-runtime -*/ - -var get = Ember.get, - set = Ember.set, - fmt = Ember.String.fmt, - addBeforeObserver = Ember.addBeforeObserver, - addObserver = Ember.addObserver, - removeBeforeObserver = Ember.removeBeforeObserver, - removeObserver = Ember.removeObserver, - propertyWillChange = Ember.propertyWillChange, - propertyDidChange = Ember.propertyDidChange, - meta = Ember.meta, - defineProperty = Ember.defineProperty; - -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.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 -*/ -Ember.ObjectProxy = Ember.Object.extend(/** @scope Ember.ObjectProxy.prototype */ { - /** - The object whose properties will be forwarded. - - @property content - @type Ember.Object - @default null - */ - content: null, - _contentDidChange: Ember.observer(function() { - Ember.assert("Can't set ObjectProxy's content to itself", this.get('content') !== this); - }, 'content'), - - isTruthy: Ember.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); - } - -}); - -})(); - - - (function() { /** @module ember @@ -17258,7 +17397,7 @@ Ember.NativeArray = NativeArray; 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 garentee that `Ember.EXTEND_PROTOTYPES` + ember or when you can not guarantee that `Ember.EXTEND_PROTOTYPES` will be `true`. Example @@ -17455,7 +17594,7 @@ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Emb @return {Ember.Set} An empty Set */ clear: function() { - if (this.isFrozen) { throw new Error(Ember.FROZEN_ERROR); } + if (this.isFrozen) { throw new Ember.Error(Ember.FROZEN_ERROR); } var len = get(this, 'length'); if (len === 0) { return this; } @@ -17565,7 +17704,7 @@ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Emb @return {Object} The removed object from the set or null. */ pop: function() { - if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR); + if (get(this, 'isFrozen')) throw new Ember.Error(Ember.FROZEN_ERROR); var obj = this.length > 0 ? this[this.length-1] : null; this.remove(obj); return obj; @@ -17682,7 +17821,7 @@ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Emb // implements Ember.MutableEnumerable addObject: function(obj) { - if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR); + if (get(this, 'isFrozen')) throw new Ember.Error(Ember.FROZEN_ERROR); if (isNone(obj)) return this; // nothing to do var guid = guidFor(obj), @@ -17710,7 +17849,7 @@ Ember.Set = Ember.CoreObject.extend(Ember.MutableEnumerable, Ember.Copyable, Emb // implements Ember.MutableEnumerable removeObject: function(obj) { - if (get(this, 'isFrozen')) throw new Error(Ember.FROZEN_ERROR); + if (get(this, 'isFrozen')) throw new Ember.Error(Ember.FROZEN_ERROR); if (isNone(obj)) return this; // nothing to do var guid = guidFor(obj), @@ -18102,7 +18241,7 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, { return content; }), - _contentWillChange: Ember.beforeObserver(function() { + _contentWillChange: Ember.beforeObserver('content', function() { var content = get(this, 'content'), sortProperties = get(this, 'sortProperties'); @@ -18115,18 +18254,18 @@ Ember.SortableMixin = Ember.Mixin.create(Ember.MutableEnumerable, { } this._super(); - }, 'content'), + }), - sortAscendingWillChange: Ember.beforeObserver(function() { + sortAscendingWillChange: Ember.beforeObserver('sortAscending', function() { this._lastSortAscending = get(this, 'sortAscending'); - }, 'sortAscending'), + }), - sortAscendingDidChange: Ember.observer(function() { + sortAscendingDidChange: Ember.observer('sortAscending', function() { if (get(this, 'sortAscending') !== this._lastSortAscending) { var arrangedContent = get(this, 'arrangedContent'); arrangedContent.reverseObjects(); } - }, 'sortAscending'), + }), contentArrayWillChange: function(array, idx, removedCount, addedCount) { var isSorted = get(this, 'isSorted'); @@ -18417,7 +18556,7 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin, fullName = "controller:" + controllerClass; if (!container.has(fullName)) { - throw new Error('Could not resolve itemController: "' + controllerClass + '"'); + throw new Ember.Error('Could not resolve itemController: "' + controllerClass + '"'); } subController = container.lookupFactory(fullName).create({ @@ -18497,7 +18636,11 @@ Ember Runtime @submodule ember-views */ -var jQuery = Ember.imports.jQuery; +var jQuery = this.jQuery || (Ember.imports && Ember.imports.jQuery); +if (!jQuery && typeof require === 'function') { + jQuery = require('jquery'); +} + Ember.assert("Ember Views require jQuery 1.7, 1.8, 1.9, 1.10, or 2.0", jQuery && (jQuery().jquery.match(/^((1\.(7|8|9|10))|2.0)(\.\d+)?(pre|rc\d?)?/) || Ember.ENV.FORCE_JQUERY)); /** @@ -18739,6 +18882,19 @@ function escapeAttribute(value) { return string.replace(BAD_CHARS_REGEXP, escapeChar); } +// IE 6/7 have bugs arond setting names on inputs during creation. +// From http://msdn.microsoft.com/en-us/library/ie/ms536389(v=vs.85).aspx: +// "To include the NAME attribute at run time on objects created with the createElement method, use the eTag." +var canSetNameOnInputs = (function() { + var div = document.createElement('div'), + el = document.createElement('input'); + + el.setAttribute('name', 'foo'); + div.appendChild(el); + + return !!div.innerHTML.match('foo'); +})(); + /** `Ember.RenderBuffer` gathers information regarding the a view and generates the final representation. `Ember.RenderBuffer` will generate HTML which can be pushed @@ -19098,14 +19254,22 @@ Ember._RenderBuffer.prototype = generateElement: function() { var tagName = this.tagNames.pop(), // pop since we don't need to close - element = document.createElement(tagName), - $element = Ember.$(element), id = this.elementId, classes = this.classes, attrs = this.elementAttributes, props = this.elementProperties, style = this.elementStyle, - styleBuffer = '', attr, prop; + styleBuffer = '', attr, prop, tagString; + + if (attrs && attrs.name && !canSetNameOnInputs) { + // IE allows passing a tag to createElement. See note on `canSetNameOnInputs` above as well. + tagString = '<'+stripTagName(tagName)+' name="'+escapeAttribute(attrs.name)+'">'; + } else { + tagString = tagName; + } + + var element = document.createElement(tagString), + $element = Ember.$(element); if (id) { $element.attr('id', id); @@ -19466,7 +19630,7 @@ Ember.ControllerMixin.reopen({ set(this, '_childContainers', {}); }, - _modelDidChange: Ember.observer(function() { + _modelDidChange: Ember.observer('model', function() { var containers = get(this, '_childContainers'); for (var prop in containers) { @@ -19475,7 +19639,7 @@ Ember.ControllerMixin.reopen({ } set(this, '_childContainers', {}); - }, 'model') + }) }); })(); @@ -19521,7 +19685,7 @@ var childViewsProperty = Ember.computed(function() { Ember.deprecate("Manipulating an Ember.ContainerView through its childViews property is deprecated. Please use the ContainerView instance itself as an Ember.MutableArray."); return view.replace(idx, removedCount, addedViews); } - throw new Error("childViews is immutable"); + throw new Ember.Error("childViews is immutable"); }; return ret; @@ -20346,9 +20510,8 @@ Ember.View = Ember.CoreView.extend( /** The name of the template to lookup if no template is provided. - `Ember.View` will look for a template with this name in this view's - `templates` object. By default, this will be a global object - shared in `Ember.TEMPLATES`. + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). @property templateName @type String @@ -20359,9 +20522,8 @@ Ember.View = Ember.CoreView.extend( /** The name of the layout to lookup if no layout is provided. - `Ember.View` will look for a template with this name in this view's - `templates` object. By default, this will be a global object - shared in `Ember.TEMPLATES`. + By default `Ember.View` will lookup a template with this name in + `Ember.TEMPLATES` (a shared global object). @property layoutName @type String @@ -20369,15 +20531,6 @@ Ember.View = Ember.CoreView.extend( */ layoutName: null, - /** - The hash in which to look for `templateName`. - - @property templates - @type Ember.Object - @default Ember.TEMPLATES - */ - templates: Ember.TEMPLATES, - /** 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 @@ -20512,9 +20665,9 @@ Ember.View = Ember.CoreView.extend( @method _contextDidChange */ - _contextDidChange: Ember.observer(function() { + _contextDidChange: Ember.observer('context', function() { this.rerender(); - }, 'context'), + }), /** If `false`, the view will appear hidden in DOM. @@ -20541,21 +20694,21 @@ Ember.View = Ember.CoreView.extend( // When it's a virtual view, we need to notify the parent that their // childViews will change. - _childViewsWillChange: Ember.beforeObserver(function() { + _childViewsWillChange: Ember.beforeObserver('childViews', function() { if (this.isVirtual) { var parentView = get(this, 'parentView'); if (parentView) { Ember.propertyWillChange(parentView, 'childViews'); } } - }, 'childViews'), + }), // When it's a virtual view, we need to notify the parent that their // childViews did change. - _childViewsDidChange: Ember.observer(function() { + _childViewsDidChange: Ember.observer('childViews', function() { if (this.isVirtual) { var parentView = get(this, 'parentView'); if (parentView) { Ember.propertyDidChange(parentView, 'childViews'); } } - }, 'childViews'), + }), /** Return the nearest ancestor that is an instance of the provided @@ -20637,7 +20790,7 @@ Ember.View = Ember.CoreView.extend( @method _parentViewDidChange */ - _parentViewDidChange: Ember.observer(function() { + _parentViewDidChange: Ember.observer('_parentView', function() { if (this.isDestroying) { return; } this.trigger('parentViewDidChange'); @@ -20645,9 +20798,9 @@ Ember.View = Ember.CoreView.extend( if (get(this, 'parentView.controller') && !get(this, 'controller')) { this.notifyPropertyChange('controller'); } - }, '_parentView'), + }), - _controllerDidChange: Ember.observer(function() { + _controllerDidChange: Ember.observer('controller', function() { if (this.isDestroying) { return; } this.rerender(); @@ -20655,7 +20808,7 @@ Ember.View = Ember.CoreView.extend( this.forEachChildView(function(view) { view.propertyDidChange('controller'); }); - }, 'controller'), + }), cloneKeywords: function() { var templateData = get(this, 'templateData'); @@ -21211,8 +21364,8 @@ Ember.View = Ember.CoreView.extend( If you write a `willDestroyElement()` handler, you can assume that your `didInsertElement()` handler was called earlier for the same element. - Normally you will not call or override this method yourself, but you may - want to implement the above callbacks when it is run. + You should not call or override this method yourself, but you may + want to implement the above callbacks. @method destroyElement @return {Ember.View} receiver @@ -21258,11 +21411,11 @@ Ember.View = Ember.CoreView.extend( @method _elementDidChange */ - _elementDidChange: Ember.observer(function() { + _elementDidChange: Ember.observer('element', function() { this.forEachChildView(function(view) { delete meta(view).cache.element; }); - }, 'element'), + }), /** Called when the parentView property has changed. @@ -21643,7 +21796,7 @@ Ember.View = Ember.CoreView.extend( @method _isVisibleDidChange */ - _isVisibleDidChange: Ember.observer(function() { + _isVisibleDidChange: Ember.observer('isVisible', function() { var $el = this.$(); if (!$el) { return; } @@ -21658,7 +21811,7 @@ Ember.View = Ember.CoreView.extend( } else { this._notifyBecameHidden(); } - }, 'isVisible'), + }), _notifyBecameVisible: function() { this.trigger('becameVisible'); @@ -22280,7 +22433,7 @@ Ember.merge(inDOM, { } view.addBeforeObserver('elementId', function() { - throw new Error("Changing a view's elementId after creation is not allowed"); + throw new Ember.Error("Changing a view's elementId after creation is not allowed"); }); }, @@ -22676,20 +22829,20 @@ Ember.ContainerView = Ember.View.extend(Ember.MutableArray, { currentView: null, - _currentViewWillChange: Ember.beforeObserver(function() { + _currentViewWillChange: Ember.beforeObserver('currentView', function() { var currentView = get(this, 'currentView'); if (currentView) { currentView.destroy(); } - }, 'currentView'), + }), - _currentViewDidChange: Ember.observer(function() { + _currentViewDidChange: Ember.observer('currentView', function() { var currentView = get(this, 'currentView'); if (currentView) { Ember.assert("You tried to set a current view that already has a parent. Make sure you don't have multiple outlets in the same view.", !get(currentView, '_parentView')); this.pushObject(currentView); } - }, 'currentView'), + }), _ensureChildrenAreInDOM: function () { this.currentState.ensureChildrenAreInDOM(this); @@ -22704,7 +22857,7 @@ Ember.merge(states._default, { Ember.merge(states.inBuffer, { childViewsDidChange: function(parentView, views, start, added) { - throw new Error('You cannot modify child views while in the inBuffer state'); + throw new Ember.Error('You cannot modify child views while in the inBuffer state'); } }); @@ -22979,13 +23132,13 @@ Ember.CollectionView = Ember.ContainerView.extend(/** @scope Ember.CollectionVie @method _contentWillChange */ - _contentWillChange: Ember.beforeObserver(function() { + _contentWillChange: Ember.beforeObserver('content', function() { var content = this.get('content'); if (content) { content.removeArrayObserver(this); } var len = content ? get(content, 'length') : 0; this.arrayWillChange(content, 0, len); - }, 'content'), + }), /** @private @@ -22997,7 +23150,7 @@ Ember.CollectionView = Ember.ContainerView.extend(/** @scope Ember.CollectionVie @method _contentDidChange */ - _contentDidChange: Ember.observer(function() { + _contentDidChange: Ember.observer('content', function() { var content = get(this, 'content'); if (content) { @@ -23007,7 +23160,7 @@ Ember.CollectionView = Ember.ContainerView.extend(/** @scope Ember.CollectionVie var len = content ? get(content, 'length') : 0; this.arrayDidChange(content, 0, null, len); - }, 'content'), + }), /** @private @@ -23196,7 +23349,9 @@ Ember.CollectionView.CONTAINER_MAP = { (function() { -var get = Ember.get, set = Ember.set, isNone = Ember.isNone; +var get = Ember.get, set = Ember.set, isNone = Ember.isNone, + a_slice = Array.prototype.slice; + /** @module ember @@ -23333,62 +23488,88 @@ Ember.Component = Ember.View.extend(Ember.TargetActionSupport, { }).property('_parentView'), /** - Sends an action to component's controller. A component inherits its - controller from the context in which it is used. + Triggers a named action on the controller context where the component is used if + this controller has registered for notifications of the action. - By default, calling `sendAction()` will send an action with the name - of the component's `action` property. + For example a component for playing or pausing music may translate click events + into action notifications of "play" or "stop" depending on some internal state + of the component: - For example, if the component had a property `action` with the value - `"addItem"`, calling `sendAction()` would send the `addItem` action - to the component's controller. - - If you provide the `action` argument to `sendAction()`, that key will - be used to look up the action name. - - For example, if the component had a property `playing` with the value - `didStartPlaying`, calling `sendAction('playing')` would send the - `didStartPlaying` action to the component's controller. - - Whether or not you are using the default action or a named action, if - the action name is not defined on the component, calling `sendAction()` - does not have any effect. - - For example, if you call `sendAction()` on a component that does not have - an `action` property defined, no action will be sent to the controller, - nor will an exception be raised. - - You can send a context object with the action by supplying the `context` - argument. The context will be supplied as the first argument in the - target's action method. Example: ```javascript - App.MyTreeComponent = Ember.Component.extend({ - click: function() { - this.sendAction('didClickTreeNode', this.get('node')); - } - }); - - App.CategoriesController = Ember.Controller.extend({ - actions: { - didClickCategory: function(category) { - //Do something with the node/category that was clicked + App.PlayButtonComponent = Ember.Component.extend({ + click: function(){ + if (this.get('isPlaying')) { + this.triggerAction('play'); + } else { + this.triggerAction('stop'); } } }); ``` + When used inside a template these component actions are configured to + trigger actions in the outer application context: + ```handlebars - {{! categories.hbs}} - {{my-tree didClickTreeNode='didClickCategory'}} + {{! application.hbs }} + {{play-button play="musicStarted" stop="musicStopped"}} + ``` + + When the component receives a browser `click` event it translate this + interaction into application-specific semantics ("play" or "stop") and + triggers the specified action name on the controller for the template + where the component is used: + + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + actions: { + musicStarted: function(){ + // called when the play button is clicked + // and the music started playing + }, + musicStopped: function(){ + // called when the play button is clicked + // and the music stopped playing + } + } + }); + ``` + + If no action name is passed to `sendAction` a default name of "action" + is assumed. + + ```javascript + App.NextButtonComponent = Ember.Component.extend({ + click: function(){ + this.sendAction(); + } + }); + ``` + + ```handlebars + {{! application.hbs }} + {{next-button action="playNextSongInAlbum"}} + ``` + + ```javascript + App.ApplicationController = Ember.Controller.extend({ + actions: { + playNextSongInAlbum: function(){ + ... + } + } + }); ``` @method sendAction @param [action] {String} the action to trigger @param [context] {*} a context to send with the action */ - sendAction: function(action, context) { - var actionName; + sendAction: function(action) { + var actionName, + contexts = a_slice.call(arguments, 1); // Send the default action if (action === undefined) { @@ -23404,7 +23585,7 @@ Ember.Component = Ember.View.extend(Ember.TargetActionSupport, { this.triggerAction({ action: actionName, - actionContext: context + actionContext: contexts }); } }); @@ -23984,8 +24165,8 @@ if (!Handlebars && typeof require === 'function') { Handlebars = require('handlebars'); } -Ember.assert("Ember Handlebars requires Handlebars version 1.0.0. 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.0, COMPILER_REVISION expected: 4, got: " + Handlebars.COMPILER_REVISION + " - Please note: Builds of master may have other COMPILER_REVISION values.", Handlebars.COMPILER_REVISION === 4); +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 @@ -24274,7 +24455,8 @@ if (Handlebars.compile) { })(); (function() { -var slice = Array.prototype.slice; +var slice = Array.prototype.slice, + originalTemplate = Ember.Handlebars.template; /** @private @@ -24406,13 +24588,10 @@ Ember.Handlebars.registerHelper('helperMissing', function(path) { var options = arguments[arguments.length - 1]; - if (Ember.FEATURES.isEnabled('container-renderables')) { + var helper = Ember.Handlebars.resolveHelper(options.data.view.container, path); - var helper = Ember.Handlebars.resolveHelper(options.data.view.container, path); - - if (helper) { - return helper.apply(this, slice.call(arguments, 1)); - } + if (helper) { + return helper.apply(this, slice.call(arguments, 1)); } error = "%@ Handlebars error: Could not find property '%@' on object %@."; @@ -24441,13 +24620,12 @@ Ember.Handlebars.registerHelper('blockHelperMissing', function(path) { var options = arguments[arguments.length - 1]; - if (Ember.FEATURES.isEnabled('container-renderables')) { + Ember.assert("`blockHelperMissing` was invoked without a helper name, which is most likely due to a mismatch between the version of Ember.js you're running now and the one used to precompile your templates. Please make sure the version of `ember-handlebars-compiler` you're using is up to date.", path); - var helper = Ember.Handlebars.resolveHelper(options.data.view.container, path); + var helper = Ember.Handlebars.resolveHelper(options.data.view.container, path); - if (helper) { - return helper.apply(this, slice.call(arguments, 1)); - } + if (helper) { + return helper.apply(this, slice.call(arguments, 1)); } return Handlebars.helpers.blockHelperMissing.apply(this, arguments); @@ -24732,7 +24910,7 @@ function evaluateUnboundHelper(context, fn, normalizedProperties, options) { for(loc = 0, len = normalizedProperties.length; loc < len; ++loc) { property = normalizedProperties[loc]; - args.push(Ember.Handlebars.get(context, property.path, options)); + args.push(Ember.Handlebars.get(property.root, property.path, options)); } args.push(options); return fn.apply(context, args); @@ -24746,10 +24924,10 @@ function evaluateUnboundHelper(context, fn, normalizedProperties, options) { @method template @for Ember.Handlebars - @param {String} template spec + @param {String} spec */ Ember.Handlebars.template = function(spec) { - var t = Handlebars.template(spec); + var t = originalTemplate(spec); t.isTop = true; return t; }; @@ -25376,6 +25554,8 @@ function bind(property, options, preserveContext, shouldDisplay, valueNormalizer } } +EmberHandlebars.bind = bind; + function simpleBind(currentContext, property, options) { var data = options.data, view = data.view, @@ -25445,12 +25625,9 @@ EmberHandlebars.registerHelper('_triageMustache', function(property, options) { return helpers[property].call(this, options); } - if (Ember.FEATURES.isEnabled('container-renderables')) { - - var helper = Ember.Handlebars.resolveHelper(options.data.view.container, property); - if (helper) { - return helper.call(this, options); - } + var helper = Ember.Handlebars.resolveHelper(options.data.view.container, property); + if (helper) { + return helper.call(this, options); } return helpers.bind.call(this, property, options); @@ -25987,10 +26164,17 @@ function makeBindings(thisContext, options) { for (var prop in hash) { if (hashType[prop] === 'ID') { - hash[prop + 'Binding'] = hash[prop]; - hashType[prop + 'Binding'] = 'STRING'; - delete hash[prop]; - delete hashType[prop]; + + var value = hash[prop]; + + if (Ember.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]; + } } } @@ -26502,7 +26686,7 @@ Ember.Handlebars.registerHelper('collection', function(path, options) { var controller = data.keywords.controller; Ember.assert('You specified an itemView, but the current context has no container to look the itemView up in. This probably means that you created a view manually, instead of through the container. Instead, use container.lookup("view:viewName"), which will properly instantiate your view.', controller && controller.container); var container = controller.container; - itemViewClass = container.resolve('view:' + Ember.String.camelize(hash.itemView)); + itemViewClass = container.resolve('view:' + hash.itemView); Ember.assert('You specified the itemView ' + hash.itemView + ", but it was not found at " + container.describe("view:" + hash.itemView) + " (and it was not registered in the container)", !!itemViewClass); } else if (hash.itemViewClass) { itemViewClass = handlebarsGet(collectionPrototype, hash.itemViewClass, options); @@ -27134,24 +27318,48 @@ Ember.Handlebars.registerHelper('template', function(name, options) { */ /** - `partial` renders a template directly using the current context. - If needed the context can be set using the `{{#with foo}}` helper. + The `partial` helper renders another template without + changing the template context: - ```html - + ```handlebars + {{foo}} + {{partial "nav"}} ``` - The `data-template-name` attribute of a partial template - is prefixed with an underscore. + 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. - ```html - + 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 @@ -27160,6 +27368,30 @@ Ember.Handlebars.registerHelper('template', function(name, options) { */ Ember.Handlebars.registerHelper('partial', function(name, options) { + + var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; + + 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 = Ember.Handlebars.get(context, name, fnOptions); + renderPartial(context, partialName, fnOptions); + }; + + return Ember.Handlebars.bind.call(context, name, options, true, exists); + } else { + // Render the partial right into parent template. + renderPartial(context, name, options); + } +}); + +function exists(value) { + return !Ember.isNone(value); +} + +function renderPartial(context, name, options) { var nameParts = name.split("/"), lastPart = nameParts[nameParts.length - 1]; @@ -27174,8 +27406,8 @@ Ember.Handlebars.registerHelper('partial', function(name, options) { template = template || deprecatedTemplate; - template(this, { data: options.data }); -}); + template(context, { data: options.data }); +} })(); @@ -27248,11 +27480,11 @@ var get = Ember.get, set = Ember.set; {{#labeled-textfield value=someProperty}} First name: - {{/my-component}} + {{/labeled-textfield}} ``` ```handlebars - + @@ -27595,7 +27827,7 @@ var get = Ember.get, set = Ember.set; 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. + See [handlebars.helpers.input](Ember.Handlebars.helpers.html#method_input) for usage details. ## Layout and LayoutName properties @@ -27818,14 +28050,14 @@ Ember.TextArea = Ember.Component.extend(Ember.TextSupport, { rows: null, cols: null, - _updateElementValue: Ember.observer(function() { + _updateElementValue: Ember.observer('value', function() { // We do this check so cursor position doesn't get affected in IE var value = get(this, 'value'), $el = this.$(); if ($el && value !== $el.val()) { $el.val(value); } - }, 'value'), + }), init: function() { this._super(); @@ -27883,7 +28115,7 @@ Ember.SelectOption = Ember.View.extend({ } }).property('content', 'parentView.selection'), - labelPathDidChange: Ember.observer(function() { + labelPathDidChange: Ember.observer('parentView.optionLabelPath', function() { var labelPath = get(this, 'parentView.optionLabelPath'); if (!labelPath) { return; } @@ -27891,9 +28123,9 @@ Ember.SelectOption = Ember.View.extend({ Ember.defineProperty(this, 'label', Ember.computed(function() { return get(this, labelPath); }).property(labelPath)); - }, 'parentView.optionLabelPath'), + }), - valuePathDidChange: Ember.observer(function() { + valuePathDidChange: Ember.observer('parentView.optionValuePath', function() { var valuePath = get(this, 'parentView.optionValuePath'); if (!valuePath) { return; } @@ -27901,7 +28133,7 @@ Ember.SelectOption = Ember.View.extend({ Ember.defineProperty(this, 'value', Ember.computed(function() { return get(this, valuePath); }).property(valuePath)); - }, 'parentView.optionValuePath') + }) }); Ember.SelectOptgroup = Ember.CollectionView.extend({ @@ -28395,7 +28627,7 @@ function program7(depth0,data) { } }, - selectionDidChange: Ember.observer(function() { + selectionDidChange: Ember.observer('selection.@each', function() { var selection = get(this, 'selection'); if (get(this, 'multiple')) { if (!isArray(selection)) { @@ -28406,9 +28638,9 @@ function program7(depth0,data) { } else { this._selectionDidChangeSingle(); } - }, 'selection.@each'), + }), - valueDidChange: Ember.observer(function() { + valueDidChange: Ember.observer('value', function() { var content = get(this, 'content'), value = get(this, 'value'), valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''), @@ -28422,7 +28654,7 @@ function program7(depth0,data) { this.set('selection', selection); } - }, 'value'), + }), _triggerChange: function() { @@ -28910,7 +29142,7 @@ Ember.Handlebars.bootstrap = function(ctx) { // Check if template of same name already exists if (Ember.TEMPLATES[templateName] !== undefined) { - throw new Error('Template named "' + templateName + '" already exists.'); + throw new Ember.Error('Template named "' + templateName + '" already exists.'); } // For templates which have a name, we save them and then remove them from the DOM @@ -28975,24 +29207,11 @@ Ember.onLoad('Ember.Application', function(Application) { initialize: bootstrap }); - var useNewComponentLookup = false; - if (Ember.FEATURES.isEnabled('container-renderables')) { - useNewComponentLookup = true; - } - - if (useNewComponentLookup) { - Application.initializer({ - name: 'registerComponentLookup', - after: 'domTemplates', - initialize: registerComponentLookup - }); - } else { - Application.initializer({ - name: 'registerComponents', - after: 'domTemplates', - initialize: registerComponents - }); - } + Application.initializer({ + name: 'registerComponentLookup', + after: 'domTemplates', + initialize: registerComponentLookup + }); }); })(); @@ -29247,7 +29466,7 @@ define("route-recognizer", return states.sort(function(a, b) { if (a.types.stars !== b.types.stars) { return a.types.stars - b.types.stars; } if (a.types.dynamics !== b.types.dynamics) { return a.types.dynamics - b.types.dynamics; } - if (a.types.statics !== b.types.statics) { return a.types.statics - b.types.statics; } + if (a.types.statics !== b.types.statics) { return b.types.statics - a.types.statics; } return 0; }); @@ -29613,8 +29832,8 @@ define("route-recognizer", (function() { define("router", - ["route-recognizer","rsvp"], - function(RouteRecognizer, RSVP) { + ["route-recognizer","rsvp","exports"], + function(__dependency1__, __dependency2__, __exports__) { "use strict"; /** @private @@ -29634,6 +29853,8 @@ define("router", * `{Object} context`: the active context for the handler */ + var RouteRecognizer = __dependency1__; + var RSVP = __dependency2__; var slice = Array.prototype.slice; @@ -29668,6 +29889,11 @@ define("router", providedModels: null, resolvedModels: null, params: null, + pivotHandler: null, + resolveIndex: 0, + handlerInfos: null, + + isActive: true, /** The Transition's internal promise. Calling `.then` on this property @@ -29711,6 +29937,7 @@ define("router", if (this.isAborted) { return this; } log(this.router, this.sequence, this.targetName + ": transition was aborted"); this.isAborted = true; + this.isActive = false; this.router.activeTransition = null; return this; }, @@ -29751,6 +29978,25 @@ define("router", return this; }, + /** + 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. + + @param {Boolean} ignoreFailure the name of the event to fire + @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.handlerInfos.slice(0, this.resolveIndex + 1), ignoreFailure, args); + }, + toString: function() { return "Transition (sequence " + this.sequence + ")"; } @@ -29760,6 +30006,10 @@ define("router", this.recognizer = new RouteRecognizer(); } + // TODO: separate into module? + Router.Transition = Transition; + + __exports__['default'] = Router; /** @@ -29875,6 +30125,10 @@ define("router", return doTransition(this, arguments); }, + intermediateTransitionTo: function(name) { + doTransition(this, arguments, true); + }, + /** Identical to `transitionTo` except that the current URL will be replaced if possible. @@ -30085,7 +30339,10 @@ define("router", throw new Error("More context objects were passed than there are dynamic segments for the route: " + handlers[handlers.length - 1].handler); } - return { matchPoint: matchPoint, providedModels: providedModels, params: params, handlerParams: handlerParams }; + var pivotHandlerInfo = currentHandlerInfos[matchPoint - 1], + pivotHandler = pivotHandlerInfo && pivotHandlerInfo.handler; + + return { matchPoint: matchPoint, providedModels: providedModels, params: params, handlerParams: handlerParams, pivotHandler: pivotHandler }; } function getMatchPointObject(objects, handlerName, activeTransition, paramName, params) { @@ -30108,7 +30365,7 @@ define("router", } function isParam(object) { - return (typeof object === "string" || object instanceof String || !isNaN(object)); + return (typeof object === "string" || object instanceof String || typeof object === "number" || object instanceof Number); } @@ -30234,20 +30491,20 @@ define("router", /** @private */ - function createQueryParamTransition(router, queryParams) { + function createQueryParamTransition(router, queryParams, isIntermediate) { var currentHandlers = router.currentHandlerInfos, currentHandler = currentHandlers[currentHandlers.length - 1], name = currentHandler.name; log(router, "Attempting query param transition"); - return createNamedTransition(router, [name, queryParams]); + return createNamedTransition(router, [name, queryParams], isIntermediate); } /** @private */ - function createNamedTransition(router, args) { + function createNamedTransition(router, args, isIntermediate) { var partitionedArgs = extractQueryParams(args), pureArgs = partitionedArgs[0], queryParams = partitionedArgs[1], @@ -30257,28 +30514,46 @@ define("router", log(router, "Attempting transition to " + pureArgs[0]); - return performTransition(router, handlerInfos, slice.call(pureArgs, 1), router.currentParams, queryParams); + return performTransition(router, + handlerInfos, + slice.call(pureArgs, 1), + router.currentParams, + queryParams, + null, + isIntermediate); } /** @private */ - function createURLTransition(router, url) { + function createURLTransition(router, url, isIntermediate) { var results = router.recognizer.recognize(url), currentHandlerInfos = router.currentHandlerInfos, - queryParams = {}; + queryParams = {}, + i, len; log(router, "Attempting URL transition to " + url); + if (results) { + // Make sure this route is actually accessible by URL. + for (i = 0, len = results.length; i < len; ++i) { + + if (router.getHandler(results[i].handler).inaccessibleByURL) { + results = null; + break; + } + } + } + if (!results) { return errorTransition(router, new Router.UnrecognizedURLError(url)); } - for(var i = 0; i < results.length; i++) { + for(i = 0, len = results.length; i < len; i++) { merge(queryParams, results[i].queryParams); } - return performTransition(router, results, [], {}, queryParams); + return performTransition(router, results, [], {}, queryParams, null, isIntermediate); } @@ -30369,7 +30644,7 @@ define("router", } catch(e) { if (!(e instanceof Router.TransitionAborted)) { // Trigger the `error` event starting from this failed handler. - trigger(transition.router, currentHandlerInfos.concat(handlerInfo), true, ['error', e, transition]); + transition.trigger(true, 'error', e, transition, handler); } // Propagate the error so that the transition promise will reject. @@ -30558,18 +30833,38 @@ define("router", } } + function performIntermediateTransition(router, recogHandlers, matchPointResults) { + + var handlerInfos = generateHandlerInfos(router, recogHandlers); + for (var i = 0; i < handlerInfos.length; ++i) { + var handlerInfo = handlerInfos[i]; + handlerInfo.context = matchPointResults.providedModels[handlerInfo.name]; + } + + var stubbedTransition = { + router: router, + isAborted: false + }; + + setupContexts(stubbedTransition, handlerInfos); + } + /** @private Creates, begins, and returns a Transition. */ - function performTransition(router, recogHandlers, providedModelsArray, params, queryParams, data) { + function performTransition(router, recogHandlers, providedModelsArray, params, queryParams, data, isIntermediate) { var matchPointResults = getMatchPoint(router, recogHandlers, providedModelsArray, params, queryParams), targetName = recogHandlers[recogHandlers.length - 1].handler, wasTransitioning = false, currentHandlerInfos = router.currentHandlerInfos; + if (isIntermediate) { + return performIntermediateTransition(router, recogHandlers, matchPointResults); + } + // Check if there's already a transition underway. if (router.activeTransition) { if (transitionsIdentical(router.activeTransition, targetName, providedModelsArray, queryParams)) { @@ -30588,9 +30883,11 @@ define("router", transition.params = matchPointResults.params; transition.data = data || {}; transition.queryParams = queryParams; + transition.pivotHandler = matchPointResults.pivotHandler; router.activeTransition = transition; var handlerInfos = generateHandlerInfos(router, recogHandlers); + transition.handlerInfos = handlerInfos; // Fire 'willTransition' event on current handlers, but don't fire it // if a transition was already underway. @@ -30599,7 +30896,7 @@ define("router", } log(router, transition.sequence, "Beginning validation for transition to " + transition.targetName); - validateEntry(transition, handlerInfos, 0, matchPointResults.matchPoint, matchPointResults.handlerParams) + validateEntry(transition, matchPointResults.matchPoint, matchPointResults.handlerParams) .then(transitionSuccess, transitionFailure); return transition; @@ -30608,14 +30905,7 @@ define("router", checkAbort(transition); try { - log(router, transition.sequence, "Validation succeeded, finalizing transition;"); - - // Don't overwrite contexts / update URL if this was a noop transition. - if (!currentHandlerInfos || !currentHandlerInfos.length || - !router.recognizer.hasRoute(currentHandlerInfos[currentHandlerInfos.length - 1].name) || - currentHandlerInfos.length !== matchPointResults.matchPoint) { - finalizeTransition(transition, handlerInfos); - } + finalizeTransition(transition, handlerInfos); // currentHandlerInfos was updated in finalizeTransition trigger(router, router.currentHandlerInfos, true, ['didTransition']); @@ -30627,6 +30917,7 @@ define("router", log(router, transition.sequence, "TRANSITION COMPLETE."); // Resolve with the final handler. + transition.isActive = false; deferred.resolve(handlerInfos[handlerInfos.length - 1].handler); } catch(e) { deferred.reject(e); @@ -30657,7 +30948,6 @@ define("router", var handlerObj = recogHandlers[i], isDynamic = handlerObj.isDynamic || (handlerObj.names && handlerObj.names.length); - var handlerInfo = { isDynamic: !!isDynamic, name: handlerObj.handler, @@ -30700,9 +30990,12 @@ define("router", */ function finalizeTransition(transition, handlerInfos) { + log(transition.router, transition.sequence, "Validation succeeded, finalizing transition;"); + var router = transition.router, seq = transition.sequence, handlerName = handlerInfos[handlerInfos.length - 1].name, + urlMethod = transition.urlMethod, i; // Collect params for URL. @@ -30713,6 +31006,10 @@ define("router", var providedModel = providedModels.pop(); objects.unshift(isParam(providedModel) ? providedModel.toString() : handlerInfo.context); } + + if (handlerInfo.handler.inaccessibleByURL) { + urlMethod = null; + } } var newQueryParams = {}; @@ -30726,8 +31023,6 @@ define("router", router.currentParams = params; - - var urlMethod = transition.urlMethod; if (urlMethod) { var url = router.recognizer.generate(handlerName, params); @@ -30750,7 +31045,10 @@ define("router", and `afterModel` in promises, and checks for redirects/aborts between each. */ - function validateEntry(transition, handlerInfos, index, matchPoint, handlerParams) { + function validateEntry(transition, matchPoint, handlerParams) { + + var handlerInfos = transition.handlerInfos, + index = transition.resolveIndex; if (index === handlerInfos.length) { // No more contexts to resolve. @@ -30774,6 +31072,8 @@ define("router", return proceed(); } + transition.trigger(true, 'willResolveModel', transition, handler); + return RSVP.resolve().then(handleAbort) .then(beforeModel) .then(handleAbort) @@ -30794,7 +31094,7 @@ define("router", } function handleError(reason) { - if (reason instanceof Router.TransitionAborted) { + if (reason instanceof Router.TransitionAborted || transition.isAborted) { // if the transition was aborted and *no additional* error was thrown, // reject with the Router.TransitionAborted instance return RSVP.reject(reason); @@ -30807,7 +31107,7 @@ define("router", // An error was thrown / promise rejected, so fire an // `error` event from this handler info up to root. - trigger(router, handlerInfos.slice(0, index + 1), true, ['error', reason, transition]); + transition.trigger(true, 'error', reason, transition, handlerInfo.handler); // Propagate the original error. return RSVP.reject(reason); @@ -30861,7 +31161,8 @@ define("router", log(router, seq, handlerName + ": validation succeeded, proceeding"); handlerInfo.context = transition.resolvedModels[handlerInfo.name]; - return validateEntry(transition, handlerInfos, index + 1, matchPoint, handlerParams); + transition.resolveIndex++; + return validateEntry(transition, matchPoint, handlerParams); } } @@ -30931,16 +31232,16 @@ define("router", @param {Array[Object]} args arguments passed to transitionTo, replaceWith, or handleURL */ - function doTransition(router, args) { + function doTransition(router, args, isIntermediate) { // Normalize blank transitions to root URL transitions. var name = args[0] || '/'; if(args.length === 1 && args[0].hasOwnProperty('queryParams')) { - return createQueryParamTransition(router, args[0]); + return createQueryParamTransition(router, args[0], isIntermediate); } else if (name.charAt(0) === '/') { - return createURLTransition(router, name); + return createURLTransition(router, name, isIntermediate); } else { - return createNamedTransition(router, slice.call(args)); + return createNamedTransition(router, slice.call(args), isIntermediate); } } @@ -30980,9 +31281,6 @@ define("router", } return object; } - - - return Router; }); })(); @@ -31017,11 +31315,14 @@ DSL.prototype = { if (callback) { var dsl = new DSL(name); + route(dsl, 'loading'); + route(dsl, 'error', { path: "/_unused_dummy_error_path_route_" + name + "/:error" }); callback.call(dsl); this.push(options.path, name, dsl.generate(), options.queryParams); } else { this.push(options.path, name, null, options.queryParams); } + }, push: function(url, name, callback, queryParams) { @@ -31032,19 +31333,7 @@ DSL.prototype = { }, route: function(name, options) { - Ember.assert("You must use `this.resource` to nest", typeof options !== 'function'); - - options = options || {}; - - if (typeof options.path !== 'string') { - options.path = "/" + name; - } - - if (this.parent && this.parent !== 'application') { - name = this.parent + "." + name; - } - - this.push(options.path, name, null, options.queryParams); + route(this, name, options); }, generate: function() { @@ -31057,17 +31346,28 @@ DSL.prototype = { return function(match) { for (var i=0, l=dslMatches.length; i= 0; --i) { + var 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; + } + } else { + // Don't fire an assertion if we found an error substate. + return; + } + + Ember.Logger.assert(false, 'Error while loading route: ' + Ember.inspect(error)); + }, + + 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 findChildRouteName(parentRoute, originatingChildRoute, name) { + var router = parentRoute.router, + childName, + targetChildRouteName = originatingChildRoute.routeName.split('.').pop(), + namespace = parentRoute.routeName === 'application' ? '' : parentRoute.routeName + '.'; + + 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 Error("Could not trigger event '" + name + "'. There are no active handlers"); + throw new Ember.Error("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; - for (var i=handlerInfos.length-1; i>=0; i--) { + for (var i = handlerInfos.length - 1; i >= 0; i--) { var handlerInfo = handlerInfos[i], handler = handlerInfo.handler; @@ -31465,21 +31856,46 @@ function triggerEvent(handlerInfos, ignoreFailure, args) { } else { return; } - } else if (handler.events && handler.events[name]) { - Ember.deprecate('Action handlers contained in an `events` object are deprecated in favor of putting them in an `actions` object (' + name + ' on ' + handler + ')', false); - if (handler.events[name].apply(handler, args) === true) { - eventWasHandled = true; - } else { - return; - } } } + if (defaultActionHandlers[name]) { + defaultActionHandlers[name].apply(null, args); + return; + } + if (!eventWasHandled && !ignoreFailure) { - throw new Error("Nothing handled the event '" + name + "'."); + throw new Ember.Error("Nothing handled the action '" + name + "'."); } } +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, + path = Ember.Router._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); +} + + Ember.Router.reopenClass({ router: null, map: function(callback) { @@ -31509,10 +31925,6 @@ Ember.Router.reopenClass({ return router; }, - _defaultErrorHandler: function(error, transition) { - Ember.Logger.assert(false, 'Error while loading route: ' + Ember.inspect(error)); - }, - _routePath: function(handlerInfos) { var path = []; @@ -31527,6 +31939,9 @@ Ember.Router.reopenClass({ } }); +Router.Transition.prototype.send = Router.Transition.prototype.trigger; + + })(); @@ -31545,6 +31960,7 @@ var get = Ember.get, set = Ember.set, a_forEach = Ember.EnumerableUtils.forEach, a_replace = Ember.EnumerableUtils.replace; + /** The `Ember.Route` class is used to define individual routes. Refer to the [routing guide](http://emberjs.com/guides/routing/) for documentation. @@ -31554,6 +31970,7 @@ var get = Ember.get, set = Ember.set, @extends Ember.Object */ Ember.Route = Ember.Object.extend(Ember.ActionHandler, { + /** @private @@ -31807,8 +32224,8 @@ Ember.Route = Ember.Object.extend(Ember.ActionHandler, { deactivate: Ember.K, /** - This hook is executed when the router enters the route for the first time. - It is not executed when the model for the route changes. + This hook is executed when the router enters the route. It is not executed + when the model for the route changes. @method activate */ @@ -31842,6 +32259,24 @@ Ember.Route = Ember.Object.extend(Ember.ActionHandler, { }); ``` + 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 @@ -31873,6 +32308,26 @@ Ember.Route = Ember.Object.extend(Ember.ActionHandler, { return router.transitionTo.apply(router, arguments); }, + /** + Perform a synchronous transition into another route with out 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. + */ + intermediateTransitionTo: function() { + var router = this.router; + router.intermediateTransitionTo.apply(router, 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. @@ -31903,7 +32358,7 @@ Ember.Route = Ember.Object.extend(Ember.ActionHandler, { */ replaceWith: function() { var router = this.router; - return this.router.replaceWith.apply(this.router, arguments); + return router.replaceWith.apply(router, arguments); }, /** @@ -31964,10 +32419,6 @@ Ember.Route = Ember.Object.extend(Ember.ActionHandler, { var args = [controller, context]; - if (Ember.FEATURES.isEnabled("query-params")) { - args.push(queryParams); - } - if (this.setupControllers) { Ember.deprecate("Ember.Route.setupControllers is deprecated. Please use Ember.Route.setupController(controller, model) instead."); this.setupControllers(controller, context); @@ -32318,6 +32769,7 @@ Ember.Route = Ember.Object.extend(Ember.ActionHandler, { instance would be used. Example + ```js App.PostRoute = Ember.Route.extend({ setupController: function(controller, model) { @@ -32542,9 +32994,18 @@ Ember.Route = Ember.Object.extend(Ember.ActionHandler, { } options = options || {}; - name = name ? name.replace(/\//g, '.') : this.routeName; + + var templateName; + + if (name) { + name = name.replace(/\//g, '.'); + templateName = name; + } else { + name = this.routeName; + templateName = this.templateName || name; + } + var viewName = options.view || this.viewName || name; - var templateName = this.templateName || name; var container = this.container, view = container.lookup('view:' + viewName), @@ -32989,12 +33450,10 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { length = paths.length, path, i, normalizedPath; - if (Ember.FEATURES.isEnabled('link-to-non-block')) { - var linkTextPath = helperParameters.options.linkTextPath; - if (linkTextPath) { - normalizedPath = Ember.Handlebars.normalizePath(templateContext, linkTextPath, helperParameters.options.data); - this.registerObserver(normalizedPath.root, normalizedPath.path, this, this.rerender); - } + var linkTextPath = helperParameters.options.linkTextPath; + if (linkTextPath) { + normalizedPath = Ember.Handlebars.normalizePath(templateContext, linkTextPath, helperParameters.options.data); + this.registerObserver(normalizedPath.root, normalizedPath.path, this, this.rerender); } for(i=0; i < length; i++) { @@ -33007,15 +33466,6 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { normalizedPath = Ember.Handlebars.normalizePath(templateContext, path, helperParameters.options.data); this.registerObserver(normalizedPath.root, normalizedPath.path, this, this._paramsChanged); } - - - if (Ember.FEATURES.isEnabled("query-params")) { - var queryParams = get(this, '_potentialQueryParams') || []; - - for(i=0; i < queryParams.length; i++) { - this.registerObserver(this, queryParams[i], this, this._queryParamsChanged); - } - } }, /** @@ -33163,15 +33613,6 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { types = options.types, data = options.data; - if (Ember.FEATURES.isEnabled("query-params")) { - if (parameters.params.length === 0) { - var appController = this.container.lookup('controller:application'); - return [get(appController, 'currentRouteName')]; - } else { - return resolveParams(parameters.context, parameters.params, { types: types, data: data }); - } - } - // Original implementation if query params not enabled return resolveParams(parameters.context, parameters.params, { types: types, data: data }); }).property(), @@ -33205,12 +33646,6 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { } } - if (Ember.FEATURES.isEnabled("query-params")) { - var queryParams = get(this, 'queryParams'); - - if (queryParams || queryParams === false) { resolvedParams.push({queryParams: queryParams}); } - } - return resolvedParams; }).property('resolvedParams', 'queryParams', 'router.url'), @@ -33312,44 +33747,44 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { To override this option for your entire application, see "Overriding Application-wide Defaults". - + ### Disabling the `link-to` helper - By default `{{link-to}}` is enabled. + 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 + + ```javascript Ember.LinkView.reopen({ disabled: Ember.computed(function(key, value) { - if (value !== undefined) { - this.set('_isDisabled', value === true); + 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 @@ -33527,21 +33962,19 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { hash.disabledBinding = hash.disabledWhen; - if (Ember.FEATURES.isEnabled('link-to-non-block')) { - 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 Ember.Handlebars.get(context, linkTitle, options); - }; - } else { - options.fn = function() { - return linkTitle; - }; - } + 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 Ember.Handlebars.get(context, linkTitle, options); + }; + } else { + options.fn = function() { + return linkTitle; + }; } } @@ -33687,13 +34120,13 @@ var get = Ember.get, set = Ember.set; Ember.onLoad('Ember.Handlebars', function(Handlebars) { /** - Calling ``{{render}}`` from within a template will insert another + 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. @@ -33705,17 +34138,17 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { }); ``` - ```handelbars + ```handlebars Hello, {{who}}. ``` ```handelbars - +

My great app

- {{render navigaton}} + {{render navigation}} ``` - + ```html

My great app

@@ -33723,7 +34156,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
``` - Optionally you may provide a second argument: a property path + 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 @@ -33854,9 +34287,15 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { var keys = ["alt", "shift", "meta", "ctrl"]; - var isAllowedClick = function(event, allowedKeys) { + var POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/; + + var isAllowedEvent = function(event, allowedKeys) { if (typeof allowedKeys === "undefined") { - return isSimpleClick(event); + if (POINTER_EVENT_TYPE_REGEX.test(event.type)) { + return isSimpleClick(event); + } else { + allowedKeys = []; + } } if (allowedKeys.indexOf("any") >= 0) { @@ -33880,7 +34319,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { ActionHelper.registeredActions[actionId] = { eventName: options.eventName, handler: function(event) { - if (!isAllowedClick(event, allowedKeys)) { return true; } + if (!isAllowedEvent(event, allowedKeys)) { return true; } event.preventDefault(); @@ -33916,16 +34355,16 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { /** The `{{action}}` helper registers an HTML element within a template for DOM - event handling and forwards that interaction to the view's controller + event handling and forwards that interaction to the templates's controller or supplied `target` option (see 'Specifying a Target'). - If the view's controller does not implement the event, the event is sent + 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. - Given the following Handlebars template on the page + Given the following application Handlebars template on the page ```handlebars
@@ -33936,19 +34375,13 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { And application code ```javascript - AController = Ember.Controller.extend({ + App.ApplicationController = Ember.Controller.extend({ actions: { - anActionName: function() {} + anActionName: function() { + + } } }); - - AView = Ember.View.extend({ - controller: AController.create(), - templateName: 'a-template' - }); - - aView = AView.create(); - aView.appendTo('body'); ``` Will result in the following rendered HTML @@ -33961,9 +34394,8 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
``` - Clicking "click me" will trigger the `anActionName` method in the `actions - hash of the `AController`. In this case, no additional parameters will be - passed. + 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: @@ -33996,11 +34428,9 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { 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 @@ -34018,11 +34448,9 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { 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. @@ -34030,11 +34458,9 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { Alternatively, supply "any" to the `allowedKeys` option to accept any combination of modifier keys. ```handlebars - +
+ click me with any key pressed +
``` ### Specifying a Target @@ -34050,43 +34476,21 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { to an object, accessible in the current context: ```handlebars - + {{! the application template }} +
+ click me +
``` - Clicking "click me" in the rendered HTML of the above template will trigger - the `anActionName` method of the object at `MyApplication.someObject`. - - If an action's target does not implement a method that matches the supplied - action name an error will be thrown. - - ```handlebars - - ``` - - With the following application code - ```javascript - AView = Ember.View.extend({ - templateName; 'a-template', - // note: no method 'aMethodNameThatIsMissing' - anActionName: function(event) {} + App.ApplicationView = Ember.View.extend({ + actions: { + anActionName: function(){} + } }); - aView = AView.create(); - aView.appendTo('body'); ``` - Will throw `Uncaught TypeError: Cannot call method 'call' of undefined` when - "click me" is clicked. - ### Additional Parameters You may specify additional parameters to the `{{action}}` helper. These @@ -34094,17 +34498,15 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) { implementing the action. ```handlebars - + {{#each person in people}} +
+ click me +
+ {{/each}} ``` - Clicking "click me" will trigger the `edit` method on the current view's - controller with the current person as a parameter. + 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 @@ -34776,19 +35178,6 @@ Ember.HashLocation = Ember.Object.extend({ @method getURL */ getURL: function() { - if (Ember.FEATURES.isEnabled("query-params")) { - // location.hash is not used because it is inconsistently - // URL-decoded between browsers. - var href = get(this, 'location').href, - hashIndex = href.indexOf('#'); - - if ( hashIndex === -1 ) { - return ""; - } else { - return href.substr(hashIndex + 1); - } - } - // Default implementation without feature flag enabled return get(this, 'location').hash.substr(1); }, @@ -34943,11 +35332,6 @@ Ember.HistoryLocation = Ember.Object.extend({ rootURL = rootURL.replace(/\/$/, ''); var url = path.replace(rootURL, ''); - if (Ember.FEATURES.isEnabled("query-params")) { - var search = location.search || ''; - url += search; - } - return url; }, @@ -35180,7 +35564,7 @@ DAG.prototype.addEdge = function(fromName, toName) { } function checkCycle(vertex, path) { if (vertex.name === toName) { - throw new Error("cycle detected: " + toName + " <- " + path.join(" <- ")); + throw new Ember.Error("cycle detected: " + toName + " <- " + path.join(" <- ")); } } visit(from, checkCycle); @@ -36113,10 +36497,10 @@ var Application = Ember.Application = Ember.Namespace.extend(Ember.DeferredMixin container = this.__container__, graph = new Ember.DAG(), namespace = this, - i, initializer; + name, initializer; - for (i=0; iu;u++)"exports"===a[u]?s.push(c={}):s.push(t(a[u]));var l=o.apply(this,s);return n[e]=c||l}}(),function(){"undefined"==typeof DS&&(DS=Ember.Namespace.create({VERSION:"1.0.0-beta.2"}),"undefined"!=typeof window&&(window.DS=DS),Ember.libraries&&Ember.libraries.registerCoreLibrary("Ember Data",DS.VERSION))}(),function(){function e(e){return function(){return this[e].apply(this,arguments)}}var t=Ember.get,r=(Ember.set,Ember.isNone);DS.JSONSerializer=Ember.Object.extend({primaryKey:"id",applyTransforms:function(e,t){return e.eachTransformedAttribute(function(e,r){var n=this.transformFor(r);t[e]=n.deserialize(t[e])},this),t},normalize:function(e,t){return t?(this.applyTransforms(e,t),t):t},serialize:function(e,r){var n={};if(r&&r.includeId){var i=t(e,"id");i&&(n[t(this,"primaryKey")]=t(e,"id"))}return e.eachAttribute(function(t,r){this.serializeAttribute(e,n,t,r)},this),e.eachRelationship(function(t,r){"belongsTo"===r.kind?this.serializeBelongsTo(e,n,r):"hasMany"===r.kind&&this.serializeHasMany(e,n,r)},this),n},serializeAttribute:function(e,r,n,i){var a=t(this,"attrs"),o=t(e,n),s=i.type;if(s){var c=this.transformFor(s);o=c.serialize(o)}n=a&&a[n]||(this.keyForAttribute?this.keyForAttribute(n):n),r[n]=o},serializeBelongsTo:function(e,n,i){var a=i.key,o=t(e,a);a=this.keyForRelationship?this.keyForRelationship(a,"belongsTo"):a,n[a]=r(o)?o:t(o,"id"),i.options.polymorphic&&this.serializePolymorphicType(e,n,i)},serializeHasMany:function(e,r,n){var i=n.key,a=DS.RelationshipChange.determineRelationshipType(e.constructor,n);("manyToNone"===a||"manyToMany"===a)&&(r[i]=t(e,i).mapBy("id"))},serializePolymorphicType:Ember.K,extract:function(e,t,r,n,i){this.extractMeta(e,t,r);var a="extract"+i.charAt(0).toUpperCase()+i.substr(1);return this[a](e,t,r,n,i)},extractFindAll:e("extractArray"),extractFindQuery:e("extractArray"),extractFindMany:e("extractArray"),extractFindHasMany:e("extractArray"),extractCreateRecord:e("extractSave"),extractUpdateRecord:e("extractSave"),extractDeleteRecord:e("extractSave"),extractFind:e("extractSingle"),extractFindBelongsTo:e("extractSingle"),extractSave:e("extractSingle"),extractSingle:function(e,t,r){return this.normalize(t,r)},extractArray:function(e,t,r){return this.normalize(t,r)},extractMeta:function(e,t,r){r&&r.meta&&(e.metaForType(t,r.meta),delete r.meta)},transformFor:function(e){var t=this.container.lookup("transform:"+e);return t}})}(),function(){var e=Ember.get,t=Ember.String.capitalize,r=Ember.String.underscore,n=window.DS;n.DebugAdapter=Ember.DataAdapter.extend({getFilters:function(){return[{name:"isNew",desc:"New"},{name:"isModified",desc:"Modified"},{name:"isClean",desc:"Clean"}]},detect:function(e){return e!==n.Model&&n.Model.detect(e)},columnsForType:function(n){var i=[{name:"id",desc:"Id"}],a=0,o=this;return e(n,"attributes").forEach(function(e){if(a++>o.attributeLimit)return!1;var n=t(r(e).replace("_"," "));i.push({name:e,desc:n})}),i},getRecords:function(e){return this.get("store").all(e)},getRecordColumnValues:function(t){var r=this,n=0,i={id:e(t,"id")};return t.eachAttribute(function(a){if(n++>r.attributeLimit)return!1;var o=e(t,a);i[a]=o}),i},getRecordKeywords:function(t){var r=[],n=Ember.A(["id"]);return t.eachAttribute(function(e){n.push(e)}),n.forEach(function(n){r.push(e(t,n))}),r},getRecordFilterValues:function(e){return{isNew:e.get("isNew"),isModified:e.get("isDirty")&&!e.get("isNew"),isClean:!e.get("isDirty")}},getRecordColor:function(e){var t="black";return e.get("isNew")?t="green":e.get("isDirty")&&(t="blue"),t},observeRecord:function(e,t){var r=Ember.A(),n=this,i=Ember.A(["id","isNew","isDirty"]);e.eachAttribute(function(e){i.push(e)}),i.forEach(function(i){var a=function(){t(n.wrapRecord(e))};Ember.addObserver(e,i,a),r.push(function(){Ember.removeObserver(e,i,a)})});var a=function(){r.forEach(function(e){e()})};return a}})}(),function(){DS.Transform=Ember.Object.extend({serialize:Ember.required(),deserialize:Ember.required()})}(),function(){DS.BooleanTransform=DS.Transform.extend({deserialize:function(e){var t=typeof e;return"boolean"===t?e:"string"===t?null!==e.match(/^true$|^t$|^1$/i):"number"===t?1===e:!1},serialize:function(e){return Boolean(e)}})}(),function(){DS.DateTransform=DS.Transform.extend({deserialize:function(e){var t=typeof e;return"string"===t?new Date(Ember.Date.parse(e)):"number"===t?new Date(e):null===e||void 0===e?e:null},serialize:function(e){if(e instanceof Date){var t=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],r=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],n=function(e){return 10>e?"0"+e:""+e},i=e.getUTCFullYear(),a=e.getUTCMonth(),o=e.getUTCDate(),s=e.getUTCDay(),c=e.getUTCHours(),u=e.getUTCMinutes(),d=e.getUTCSeconds(),l=t[s],h=n(o),f=r[a];return l+", "+h+" "+f+" "+i+" "+n(c)+":"+n(u)+":"+n(d)+" GMT"}return null}})}(),function(){var e=Ember.isEmpty;DS.NumberTransform=DS.Transform.extend({deserialize:function(t){return e(t)?null:Number(t)},serialize:function(t){return e(t)?null:Number(t)}})}(),function(){var e=Ember.isNone;DS.StringTransform=DS.Transform.extend({deserialize:function(t){return e(t)?null:String(t)},serialize:function(t){return e(t)?null:String(t)}})}(),function(){Ember.set,Ember.onLoad("Ember.Application",function(e){e.initializer({name:"store",initialize:function(e,t){t.register("store:main",t.Store||DS.Store),t.register("serializer:_default",DS.JSONSerializer),t.register("serializer:_rest",DS.RESTSerializer),t.register("adapter:_rest",DS.RESTAdapter),e.lookup("store:main")}}),e.initializer({name:"transforms",initialize:function(e,t){t.register("transform:boolean",DS.BooleanTransform),t.register("transform:date",DS.DateTransform),t.register("transform:number",DS.NumberTransform),t.register("transform:string",DS.StringTransform)}}),e.initializer({name:"dataAdapter",initialize:function(e,t){t.register("dataAdapter:main",DS.DebugAdapter)}}),e.initializer({name:"injectStore",initialize:function(e,t){t.inject("controller","store","store:main"),t.inject("route","store","store:main"),t.inject("serializer","store","store:main"),t.inject("dataAdapter","store","store:main")}})})}(),function(){Ember.Date=Ember.Date||{};var e=Date.parse,t=[1,4,5,6,7,10,11];Ember.Date.parse=function(r){var n,i,a=0;if(i=/^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(r)){for(var o,s=0;o=t[s];++s)i[o]=+i[o]||0;i[2]=(+i[2]||1)-1,i[3]=+i[3]||1,"Z"!==i[8]&&void 0!==i[9]&&(a=60*i[10]+i[11],"+"===i[9]&&(a=0-a)),n=Date.UTC(i[1],i[2],i[3],i[4],i[5]+a,i[6],i[7])}else n=e?e(r):0/0;return n},(Ember.EXTEND_PROTOTYPES===!0||Ember.EXTEND_PROTOTYPES.Date)&&(Date.parse=Ember.Date.parse)}(),function(){var e=Ember.get;Ember.set,DS.RecordArray=Ember.ArrayProxy.extend(Ember.Evented,{type:null,content:null,isLoaded:!1,isUpdating:!1,store:null,objectAtContent:function(t){var r=e(this,"content");return r.objectAt(t)},update:function(){if(!e(this,"isUpdating")){var t=e(this,"store"),r=e(this,"type");t.fetchAll(r,this)}},addRecord:function(t){e(this,"content").addObject(t)},removeRecord:function(t){e(this,"content").removeObject(t)},save:function(){var e=Ember.RSVP.all(this.invoke("save")).then(function(e){return Ember.A(e)});return DS.PromiseArray.create({promise:e})}})}(),function(){var e=Ember.get;DS.FilteredRecordArray=DS.RecordArray.extend({filterFunction:null,isLoaded:!0,replace:function(){var t=e(this,"type").toString();throw new Error("The result of a client-side filter (on "+t+") is immutable.")},updateFilter:Ember.observer(function(){var t=e(this,"manager");t.updateFilter(this,e(this,"type"),e(this,"filterFunction"))},"filterFunction")})}(),function(){var e=Ember.get;Ember.set,DS.AdapterPopulatedRecordArray=DS.RecordArray.extend({query:null,replace:function(){var t=e(this,"type").toString();throw new Error("The result of a server query (on "+t+") is immutable.")},load:function(t){var r=e(this,"store"),n=e(this,"type"),i=r.pushMany(n,t),a=r.metadataFor(n);this.setProperties({content:Ember.A(i),isLoaded:!0,meta:a}),Ember.run.once(this,"trigger","didLoad")}})}(),function(){var e=Ember.get,t=Ember.set,r=Ember.EnumerableUtils.map;DS.ManyArray=DS.RecordArray.extend({init:function(){this._super.apply(this,arguments),this._changesToSync=Ember.OrderedSet.create()},owner:null,isPolymorphic:!1,isLoaded:!1,loadingRecordsCount:function(e){this.loadingRecordsCount=e},loadedRecord:function(){this.loadingRecordsCount--,0===this.loadingRecordsCount&&(t(this,"isLoaded",!0),this.trigger("didLoad"))},fetch:function(){var t=e(this,"content"),r=e(this,"store"),n=e(this,"owner"),i=Ember.RSVP.defer(),a=t.filterProperty("isEmpty",!0);r.fetchMany(a,n,i)},replaceContent:function(e,t,n){n=r(n,function(e){return e},this),this._super(e,t,n)},arrangedContentDidChange:function(){Ember.run.once(this,"fetch")},arrayContentWillChange:function(t,r){var n=e(this,"owner"),i=e(this,"name");if(!n._suspendedRelationships)for(var a=t;t+r>a;a++){var o=e(this,"content").objectAt(a),s=DS.RelationshipChange.createChange(n,o,e(this,"store"),{parentType:n.constructor,changeType:"remove",kind:"hasMany",key:i});this._changesToSync.add(s)}return this._super.apply(this,arguments)},arrayContentDidChange:function(t,r,n){this._super.apply(this,arguments);var i=e(this,"owner"),a=e(this,"name"),o=e(this,"store");if(!i._suspendedRelationships){for(var s=t;t+n>s;s++){var c=e(this,"content").objectAt(s),u=DS.RelationshipChange.createChange(i,c,o,{parentType:i.constructor,changeType:"add",kind:"hasMany",key:a});u.hasManyName=a,this._changesToSync.add(u)}this._changesToSync.forEach(function(e){e.sync()}),this._changesToSync.clear()}},createRecord:function(t){var r,n=e(this,"owner"),i=e(n,"store"),a=e(this,"type");return r=i.createRecord.call(i,a,t),this.pushObject(r),r}})}(),function(){function e(e){var t=Ember.meta(e,!0),r="DS.Mappable",n=t[r];return n||(t[r]={}),t.hasOwnProperty(r)||(t[r]=Ember.create(t[r])),t[r]}Ember.get;var t=Ember.ArrayPolyfills.forEach,r=function(e){return e},n=function(e){return e},i=function(e,t){return t};DS._Mappable=Ember.Mixin.create({createInstanceMapFor:function(t){var r=e(this);if(r.values=r.values||{},r.values[t])return r.values[t];for(var n=r.values[t]=new Ember.Map,i=this.constructor;i&&i!==DS.Store;)this._copyMap(t,i,n),i=i.superclass;return r.values[t]=n,n},_copyMap:function(a,o,s){function c(e,t){var a=(o.transformMapKey||n)(e,t),c=(o.transformMapValue||i)(e,t),u=s.get(a),d=c;u&&(d=(this.constructor.resolveMapConflict||r)(u,d)),s.set(a,d)}var u=e(o),d=u[a];d&&t.call(d,c,this)}}),DS._Mappable.generateMapFunctionFor=function(t,r){return function(n,i){var a=e(this),o=a[t]||Ember.MapWithDefault.create({defaultValue:function(){return{}}});r.call(this,n,i,o),a[t]=o}}}(),function(){function e(e,r,i,a){return r.eachRelationship(function(r,o){if(i.links&&i.links[r])return a&&o.options.async&&(a._relationships[r]=null),void 0;var s=o.kind,c=i[r];null!=c&&("belongsTo"===s?t(e,i,r,o,c):"hasMany"===s&&n(e,i,r,o,c))}),i}function t(e,t,n,i,a){if(!(b(a)||a instanceof DS.Model)){var o;"number"==typeof a||"string"==typeof a?(o=r(i,n,t),t[n]=e.recordForId(o,a)):"object"==typeof a&&(t[n]=e.recordForId(a.type,a.id))}}function r(e,t,r){return e.options.polymorphic?r[t+"Type"]:e.type}function n(e,r,n,i,a){for(var o=0,s=a.length;s>o;o++)t(e,a,o,i,a[o])}function i(e){return DS.PromiseObject.create({promise:e})}function a(e){return DS.PromiseArray.create({promise:e})}function o(e,t,r){return e.lookup("serializer:"+t)||e.lookup("serializer:application")||e.lookup("serializer:"+r)||e.lookup("serializer:_default")}function s(e,t){var r=e.serializer,n=e.defaultSerializer,i=e.container;return i&&void 0===r&&(r=o(i,t.typeKey,n)),(null===r||void 0===r)&&(r={extract:function(e,t,r){return r}}),r}function c(e,t,r,n,i){var a=e.find(t,r,n),o=s(e,r);return S(a).then(function(e){return e=o.extract(t,r,e,n,"find"),t.push(r,e)},function(e){var i=t.getById(r,n);throw i.notFound(),e}).then(i.resolve,i.reject)}function u(e,t,r,n,i,a){var o=e.findMany(t,r,n,i),c=s(e,r);return S(o).then(function(e){e=c.extract(t,r,e,null,"findMany"),t.pushMany(r,e)}).then(a.resolve,a.reject)}function d(e,t,r,n,i,a){var o=e.findHasMany(t,r,n,i),c=s(e,i.type);return S(o).then(function(e){e=c.extract(t,i.type,e,null,"findHasMany");var n=t.pushMany(i.type,e);r.updateHasMany(i.key,n)}).then(a.resolve,a.reject)}function l(e,t,r,n,i,a){var o=e.findBelongsTo(t,r,n,i),c=s(e,i.type);return S(o).then(function(e){e=c.extract(t,i.type,e,null,"findBelongsTo");var r=t.push(i.type,e);return r.updateBelongsTo(i.key,r),r}).then(a.resolve,a.reject)}function h(e,t,r,n,i){var a=e.findAll(t,r,n),o=s(e,r);return S(a).then(function(e){return e=o.extract(t,r,e,null,"findAll"),t.pushMany(r,e),t.didUpdateAll(r),t.all(r)}).then(i.resolve,i.reject)}function f(e,t,r,n,i,a){var o=e.findQuery(t,r,n,i),c=s(e,r);return S(o).then(function(e){return e=c.extract(t,r,e,null,"findAll"),i.load(e),i}).then(a.resolve,a.reject)}function p(e,t,r,n,i){var a=n.constructor,o=e[r](t,a,n),c=s(e,a);return o.then(function(e){return e&&(e=c.extract(t,a,e,m(n,"id"),r)),t.didSaveRecord(n,e),n},function(e){throw e instanceof DS.InvalidError?t.recordWasInvalid(n,e.errors):t.recordWasError(n,e),e}).then(i.resolve,i.reject)}var m=Ember.get,y=Ember.set,g=Ember.run.once,b=Ember.isNone,v=Ember.EnumerableUtils.forEach,R=Ember.EnumerableUtils.indexOf,E=Ember.EnumerableUtils.map,S=Ember.RSVP.resolve,T=function(e){return null==e?null:e+""};DS.Store=Ember.Object.extend(DS._Mappable,{init:function(){this.typeMaps={},this.recordArrayManager=DS.RecordArrayManager.create({store:this}),this._relationshipChanges={},this._pendingSave=[]},adapter:"_rest",serialize:function(e,t){return this.serializerFor(e.constructor.typeKey).serialize(e,t)},defaultAdapter:Ember.computed(function(){var e=m(this,"adapter");return"string"==typeof e&&(e=this.container.lookup("adapter:"+e)||this.container.lookup("adapter:application")||this.container.lookup("adapter:_rest")),DS.Adapter.detect(e)&&(e=e.create({container:this.container})),e}).property("adapter"),createRecord:function(e,t){e=this.modelFor(e),t=t||{},b(t.id)&&(t.id=this._generateId(e)),t.id=T(t.id);var r=this.buildRecord(e,t.id);return r.loadedData(),r.setProperties(t),r},_generateId:function(e){var t=this.adapterFor(e);return t&&t.generateIdForRecord?t.generateIdForRecord(this):null},deleteRecord:function(e){e.deleteRecord()},unloadRecord:function(e){e.unloadRecord()},find:function(e,t){return void 0===t?this.findAll(e):"object"===Ember.typeOf(t)?this.findQuery(e,t):this.findById(e,T(t))},findById:function(e,t){e=this.modelFor(e);var r=this.recordForId(e,t),n=this.fetchRecord(r)||S(r);return i(n)},findByIds:function(e,t){var r=this;return a(Ember.RSVP.all(E(t,function(t){return r.findById(e,t)})).then(function(e){return Ember.A(e)}))},fetchRecord:function(e){if(b(e))return null;if(e._loadingPromise)return e._loadingPromise;if(!m(e,"isEmpty"))return null;var t=e.constructor,r=m(e,"id"),n=Ember.RSVP.defer();e.loadingData(n.promise);var i=this.adapterFor(t);return c(i,this,t,r,n),n.promise},getById:function(e,t){return e=this.modelFor(e),this.hasRecordForId(e,t)?this.recordForId(e,t):null},reloadRecord:function(e,t){var r=e.constructor,n=this.adapterFor(r),i=m(e,"id");return c(n,this,r,i,t)},fetchMany:function(e,t,r){if(e.length){var n=Ember.MapWithDefault.create({defaultValue:function(){return Ember.A()}});v(e,function(e){n.get(e.constructor).push(e)}),v(n,function(e,n){var i=n.mapProperty("id"),a=this.adapterFor(e);u(a,this,e,i,t,r)},this)}},hasRecordForId:function(e,t){return t=T(t),!!this.typeMapFor(e).idToRecord[t]},recordForId:function(e,t){e=this.modelFor(e),t=T(t);var r=this.typeMapFor(e).idToRecord[t];return r||(r=this.buildRecord(e,t)),r},findMany:function(e,t,r,n){r=this.modelFor(r),t=Ember.A(t);var i=t.filterProperty("isEmpty",!0),a=this.recordArrayManager.createManyArray(r,t);return v(i,function(e){e.loadingData()}),a.loadingRecordsCount=i.length,i.length?(v(i,function(e){this.recordArrayManager.registerWaitingRecordArray(e,a)},this),this.fetchMany(i,e,n)):(n&&n.resolve(),a.set("isLoaded",!0),Ember.run.once(a,"trigger","didLoad")),a},findHasMany:function(e,t,r,n){var i=this.adapterFor(e.constructor),a=this.recordArrayManager.createManyArray(r.type,Ember.A([]));return d(i,this,e,t,r,n),a},findBelongsTo:function(e,t,r,n){var i=this.adapterFor(e.constructor);l(i,this,e,t,r,n)},findQuery:function(e,t){e=this.modelFor(e);var r=DS.AdapterPopulatedRecordArray.create({type:e,query:t,content:Ember.A(),store:this}),n=this.adapterFor(e),i=Ember.RSVP.defer();return f(n,this,e,t,r,i),a(i.promise)},findAll:function(e){return e=this.modelFor(e),this.fetchAll(e,this.all(e))},fetchAll:function(e,t){var r=this.adapterFor(e),n=this.typeMapFor(e).metadata.since,i=Ember.RSVP.defer();return y(t,"isUpdating",!0),h(r,this,e,n,i),a(i.promise)},didUpdateAll:function(e){var t=this.typeMapFor(e).findAllCache;y(t,"isUpdating",!1)},all:function(e){e=this.modelFor(e);var t=this.typeMapFor(e),r=t.findAllCache;if(r)return r;var n=DS.RecordArray.create({type:e,content:Ember.A(),store:this,isLoaded:!0});return this.recordArrayManager.registerFilteredRecordArray(n,e),t.findAllCache=n,n},unloadAll:function(e){e=this.modelFor(e);for(var t,r=this.typeMapFor(e),n=r.records;t=n.pop();)t.unloadRecord()},filter:function(e,t,r){var n;3===arguments.length?n=this.findQuery(e,t):2===arguments.length&&(r=t),e=this.modelFor(e);var i=DS.FilteredRecordArray.create({type:e,content:Ember.A(),store:this,manager:this.recordArrayManager,filterFunction:r});return this.recordArrayManager.registerFilteredRecordArray(i,e,r),n?n.then(function(){return i}):i},recordIsLoaded:function(e,t){return this.hasRecordForId(e,t)?!m(this.recordForId(e,t),"isEmpty"):!1},metadataFor:function(e){return e=this.modelFor(e),this.typeMapFor(e).metadata},dataWasUpdated:function(e,t){m(t,"isDeleted")||m(t,"isLoaded")&&this.recordArrayManager.recordDidChange(t)},scheduleSave:function(e,t){e.adapterWillCommit(),this._pendingSave.push([e,t]),g(this,"flushPendingSave")},flushPendingSave:function(){var e=this._pendingSave.slice();this._pendingSave=[],v(e,function(e){var t,r=e[0],n=e[1],i=this.adapterFor(r.constructor);t=m(r,"isNew")?"createRecord":m(r,"isDeleted")?"deleteRecord":"updateRecord",p(i,this,t,r,n)},this)},didSaveRecord:function(t,r){r&&(r=e(this,t.constructor,r,t),this.updateId(t,r)),t.adapterDidCommit(r)},recordWasInvalid:function(e,t){e.adapterDidInvalidate(t)},recordWasError:function(e){e.adapterDidError()},updateId:function(e,t){var r=(m(e,"id"),T(t.id));this.typeMapFor(e.constructor).idToRecord[r]=e,y(e,"id",r)},typeMapFor:function(e){var t,r=m(this,"typeMaps"),n=Ember.guidFor(e);return(t=r[n])?t:(t={idToRecord:{},records:[],metadata:{}},r[n]=t,t)},_load:function(e,t,r){var n=T(t.id),i=this.recordForId(e,n);return i.setupData(t,r),this.recordArrayManager.recordDidChange(i),i},modelFor:function(e){if("string"!=typeof e)return e;var t=this.container.lookupFactory("model:"+e);return t.store=this,t.typeKey=e,t},push:function(t,r,n){return t=this.modelFor(t),r=e(this,t,r),this._load(t,r,n),this.recordForId(t,r.id)},pushPayload:function(e,t){var r=this.serializerFor(e);r.pushPayload(this,t)},update:function(e,t){return this.push(e,t,!0)},pushMany:function(e,t){return E(t,function(t){return this.push(e,t)},this)},metaForType:function(e,t){e=this.modelFor(e),Ember.merge(this.typeMapFor(e).metadata,t)},buildRecord:function(e,t,r){var n=this.typeMapFor(e),i=n.idToRecord,a=e._create({id:t,store:this,container:this.container});return r&&a.setupData(r),t&&(i[t]=a),n.records.push(a),a},dematerializeRecord:function(e){var t=e.constructor,r=this.typeMapFor(t),n=m(e,"id");e.updateRecordArrays(),n&&delete r.idToRecord[n];var i=R(r.records,e);r.records.splice(i,1)},addRelationshipChangeFor:function(e,t,r,n,i){var a=e.clientId,o=r?r:r,s=t+n,c=this._relationshipChanges;a in c||(c[a]={}),o in c[a]||(c[a][o]={}),s in c[a][o]||(c[a][o][s]={}),c[a][o][s][i.changeType]=i},removeRelationshipChangeFor:function(e,t,r,n,i){var a=e.clientId,o=r?r.clientId:r,s=this._relationshipChanges,c=t+n;a in s&&o in s[a]&&c in s[a][o]&&delete s[a][o][c][i]},relationshipChangePairsFor:function(e){var t=[];if(!e)return t;var r=this._relationshipChanges[e.clientId];for(var n in r)if(r.hasOwnProperty(n))for(var i in r[n])r[n].hasOwnProperty(i)&&t.push(r[n][i]);return t},adapterFor:function(e){var t,r=this.container;return r&&(t=r.lookup("adapter:"+e.typeKey)||r.lookup("adapter:application")),t||m(this,"defaultAdapter")},serializerFor:function(e){e=this.modelFor(e);var t=this.adapterFor(e);return o(this.container,e.typeKey,t&&t.defaultSerializer)}}),DS.PromiseArray=Ember.ArrayProxy.extend(Ember.PromiseProxyMixin),DS.PromiseObject=Ember.ObjectProxy.extend(Ember.PromiseProxyMixin)}(),function(){function e(t){var r,n={};for(var i in t)r=t[i],n[i]=r&&"object"==typeof r?e(r):r;return n}function t(e,t){for(var r in t)e[r]=t[r];return e}function r(r){var n=e(c);return t(n,r)}function n(e,r,i){e=t(r?Ember.create(r):{},e),e.parentState=r,e.stateName=i;for(var a in e)e.hasOwnProperty(a)&&"parentState"!==a&&"stateName"!==a&&"object"==typeof e[a]&&(e[a]=n(e[a],e,i+"."+a));return e}var i=Ember.get,a=Ember.set,o=function(e){var t,r,n,i=Ember.keys(e);for(t=0,r=i.length;r>t;t++)if(n=i[t],e.hasOwnProperty(n)&&e[n])return!0;return!1},s=function(e,t){t.value===t.originalValue?(delete e._attributes[t.name],e.send("propertyWasReset",t.name)):t.value!==t.oldValue&&e.send("becomeDirty"),e.updateRecordArraysLater()},c={initialState:"uncommitted",isDirty:!0,uncommitted:{didSetProperty:s,propertyWasReset:function(e){var t=!1;for(var r in e._attributes){t=!0;break}t||e.send("rolledBack")},pushedData:Ember.K,becomeDirty:Ember.K,willCommit:function(e){e.transitionTo("inFlight")},reloadRecord:function(e,t){i(e,"store").reloadRecord(e,t)},rolledBack:function(e){e.transitionTo("loaded.saved")},becameInvalid:function(e){e.transitionTo("invalid")},rollback:function(e){e.rollback()}},inFlight:{isSaving:!0,didSetProperty:s,becomeDirty:Ember.K,pushedData:Ember.K,willCommit:Ember.K,didCommit:function(e){var t=i(this,"dirtyType");e.transitionTo("saved"),e.send("invokeLifecycleCallbacks",t)},becameInvalid:function(e,t){a(e,"errors",t),e.transitionTo("invalid"),e.send("invokeLifecycleCallbacks")},becameError:function(e){e.transitionTo("uncommitted"),e.triggerLater("becameError",e)}},invalid:{isValid:!1,deleteRecord:function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()},didSetProperty:function(e,t){var r=i(e,"errors"),n=t.name;a(r,n,null),o(r)||e.send("becameValid"),s(e,t)},becomeDirty:Ember.K,rollback:function(e){e.send("becameValid"),e.send("rollback")},becameValid:function(e){e.transitionTo("uncommitted")},invokeLifecycleCallbacks:function(e){e.triggerLater("becameInvalid",e)}}},u=r({dirtyType:"created",isNew:!0});u.uncommitted.rolledBack=function(e){e.transitionTo("deleted.saved")};var d=r({dirtyType:"updated"});u.uncommitted.deleteRecord=function(e){e.clearRelationships(),e.transitionTo("deleted.saved")},u.uncommitted.rollback=function(e){c.uncommitted.rollback.apply(this,arguments),e.transitionTo("deleted.saved")},d.uncommitted.deleteRecord=function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()};var l={isEmpty:!1,isLoading:!1,isLoaded:!1,isDirty:!1,isSaving:!1,isDeleted:!1,isNew:!1,isValid:!0,rolledBack:Ember.K,propertyWasReset:Ember.K,empty:{isEmpty:!0,loadingData:function(e,t){e._loadingPromise=t,e.transitionTo("loading")},loadedData:function(e){e.transitionTo("loaded.created.uncommitted"),e.suspendRelationshipObservers(function(){e.notifyPropertyChange("data")})},pushedData:function(e){e.transitionTo("loaded.saved"),e.triggerLater("didLoad")}},loading:{isLoading:!0,exit:function(e){e._loadingPromise=null},pushedData:function(e){e.transitionTo("loaded.saved"),e.triggerLater("didLoad"),a(e,"isError",!1)},becameError:function(e){e.triggerLater("becameError",e)},notFound:function(e){e.transitionTo("empty")}},loaded:{initialState:"saved",isLoaded:!0,saved:{setup:function(e){var t=e._attributes,r=!1;for(var n in t)if(t.hasOwnProperty(n)){r=!0;break}r&&e.adapterDidDirty()},didSetProperty:s,pushedData:Ember.K,becomeDirty:function(e){e.transitionTo("updated.uncommitted")},willCommit:function(e){e.transitionTo("updated.inFlight")},reloadRecord:function(e,t){i(e,"store").reloadRecord(e,t)},deleteRecord:function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()},unloadRecord:function(e){e.clearRelationships(),e.transitionTo("deleted.saved")},didCommit:function(e){e.send("invokeLifecycleCallbacks",i(e,"lastDirtyType"))}},created:u,updated:d},deleted:{initialState:"uncommitted",dirtyType:"deleted",isDeleted:!0,isLoaded:!0,isDirty:!0,setup:function(e){var t=i(e,"store");t.recordArrayManager.remove(e)},uncommitted:{willCommit:function(e){e.transitionTo("inFlight")},rollback:function(e){e.rollback()},becomeDirty:Ember.K,deleteRecord:Ember.K,rolledBack:function(e){e.transitionTo("loaded.saved")}},inFlight:{isSaving:!0,willCommit:Ember.K,didCommit:function(e){e.transitionTo("saved"),e.send("invokeLifecycleCallbacks")},becameError:function(e){e.transitionTo("uncommitted"),e.triggerLater("becameError",e)}},saved:{isDirty:!1,setup:function(e){var t=i(e,"store");t.dematerializeRecord(e)},invokeLifecycleCallbacks:function(e){e.triggerLater("didDelete",e),e.triggerLater("didCommit",e)}}},invokeLifecycleCallbacks:function(e,t){"created"===t?e.triggerLater("didCreate",e):e.triggerLater("didUpdate",e),e.triggerLater("didCommit",e)}};l=n(l,null,"root"),DS.RootState=l}(),function(){var e=Ember.get,t=Ember.set,r=Ember.merge,n=Ember.run.once,i=Ember.computed(function(t){return e(e(this,"currentState"),t)}).property("currentState").readOnly();DS.Model=Ember.Object.extend(Ember.Evented,{isEmpty:i,isLoading:i,isLoaded:i,isDirty:i,isSaving:i,isDeleted:i,isNew:i,isValid:i,dirtyType:i,isError:!1,isReloading:!1,clientId:null,id:null,transaction:null,currentState:null,errors:null,serialize:function(t){var r=e(this,"store");return r.serialize(this,t)},toJSON:function(e){var t=DS.JSONSerializer.create({container:this.container});return t.serialize(this,e)},didLoad:Ember.K,didReload:Ember.K,didUpdate:Ember.K,didCreate:Ember.K,didDelete:Ember.K,becameInvalid:Ember.K,becameError:Ember.K,data:Ember.computed(function(){return this._data=this._data||{},this._data}).property(),_data:null,init:function(){t(this,"currentState",DS.RootState.empty),this._super(),this._setup()},_setup:function(){this._changesToSync={},this._deferredTriggers=[],this._data={},this._attributes={},this._inFlightAttributes={},this._relationships={}},send:function(t,r){var n=e(this,"currentState");return n[t]||this._unhandledEvent(n,t,r),n[t](this,r)},transitionTo:function(r){var n=r.split(".",1),i=e(this,"currentState"),a=i;do a.exit&&a.exit(this),a=a.parentState;while(!a.hasOwnProperty(n));var o,s,c=r.split("."),u=[],d=[];for(o=0,s=c.length;s>o;o++)a=a[c[o]],a.enter&&d.push(a),a.setup&&u.push(a);for(o=0,s=d.length;s>o;o++)d[o].enter(this);for(t(this,"currentState",a),o=0,s=u.length;s>o;o++)u[o].setup(this)},_unhandledEvent:function(e,t,r){var n="Attempted to handle event `"+t+"` ";throw n+="on "+String(this)+" while in state ",n+=e.stateName+". ",void 0!==r&&(n+="Called with "+Ember.inspect(r)+"."),new Ember.Error(n)},withTransaction:function(t){var r=e(this,"transaction");r&&t(r)},loadingData:function(e){this.send("loadingData",e)},loadedData:function(){this.send("loadedData")},notFound:function(){this.send("notFound")},pushedData:function(){this.send("pushedData")},deleteRecord:function(){this.send("deleteRecord")},destroyRecord:function(){return this.deleteRecord(),this.save()},unloadRecord:function(){this.send("unloadRecord")},clearRelationships:function(){this.eachRelationship(function(e,r){if("belongsTo"===r.kind)t(this,e,null);else if("hasMany"===r.kind){var n=this._relationships[r.name];n&&n.clear()}},this)},updateRecordArrays:function(){var t=e(this,"store");t&&t.dataWasUpdated(this.constructor,this)},changedAttributes:function(){var t,r=e(this,"_data"),n=e(this,"_attributes"),i={};for(t in n)i[t]=[r[t],n[t]];return i},adapterWillCommit:function(){this.send("willCommit")},adapterDidCommit:function(e){t(this,"isError",!1),e?this._data=e:Ember.mixin(this._data,this._inFlightAttributes),this._inFlightAttributes={},this.send("didCommit"),this.updateRecordArraysLater(),e&&this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},adapterDidDirty:function(){this.send("becomeDirty"),this.updateRecordArraysLater()},dataDidChange:Ember.observer(function(){this.reloadHasManys()},"data"),reloadHasManys:function(){var t=e(this.constructor,"relationshipsByName");this.updateRecordArraysLater(),t.forEach(function(e,t){this._data.links&&this._data.links[e]||"hasMany"===t.kind&&this.hasManyDidChange(t.key)},this)},hasManyDidChange:function(e){var r=this._relationships[e];if(r){var n=this._data[e]||[];t(r,"content",Ember.A(n)),t(r,"isLoaded",!0),r.trigger("didLoad")}},updateRecordArraysLater:function(){Ember.run.once(this,this.updateRecordArrays)},setupData:function(e,t){t?Ember.merge(this._data,e):this._data=e;var r=this._relationships;this.eachRelationship(function(t,n){e.links&&e.links[t]||n.options.async&&(r[t]=null)}),e&&this.pushedData(),this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},materializeId:function(e){t(this,"id",e)},materializeAttributes:function(e){r(this._data,e)},materializeAttribute:function(e,t){this._data[e]=t},updateHasMany:function(e,t){this._data[e]=t,this.hasManyDidChange(e)},updateBelongsTo:function(e,t){this._data[e]=t},rollback:function(){this._attributes={},e(this,"isError")&&(this._inFlightAttributes={},t(this,"isError",!1)),this.send("rolledBack"),this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},toStringExtension:function(){return e(this,"id")},suspendRelationshipObservers:function(t,r){var n=e(this.constructor,"relationshipNames").belongsTo,i=this;try{this._suspendedRelationships=!0,Ember._suspendObservers(i,n,null,"belongsToDidChange",function(){Ember._suspendBeforeObservers(i,n,null,"belongsToWillChange",function(){t.call(r||i)})})}finally{this._suspendedRelationships=!1}},save:function(){var e=Ember.RSVP.defer();return this.get("store").scheduleSave(this,e),this._inFlightAttributes=this._attributes,this._attributes={},DS.PromiseObject.create({promise:e.promise})},reload:function(){t(this,"isReloading",!0);var e=Ember.RSVP.defer(),r=this;return e.promise=e.promise.then(function(){return r.set("isReloading",!1),r.set("isError",!1),r},function(e){throw r.set("isError",!0),e}),this.send("reloadRecord",e),DS.PromiseObject.create({promise:e.promise})},adapterDidUpdateAttribute:function(e,t){void 0!==t?(this._data[e]=t,this.notifyPropertyChange(e)):this._data[e]=this._inFlightAttributes[e],this.updateRecordArraysLater()},adapterDidInvalidate:function(e){this.send("becameInvalid",e)},adapterDidError:function(){this.send("becameError"),t(this,"isError",!0)},trigger:function(e){Ember.tryInvoke(this,e,[].slice.call(arguments,1)),this._super.apply(this,arguments)},triggerLater:function(){this._deferredTriggers.push(arguments),n(this,"_triggerDeferredTriggers")},_triggerDeferredTriggers:function(){for(var e=0,t=this._deferredTriggers.length;t>e;e++)this.trigger.apply(this,this._deferredTriggers[e]);this._deferredTriggers=[]}}),DS.Model.reopenClass({_create:DS.Model.create,create:function(){throw new Ember.Error("You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.")}})}(),function(){function e(e,t){return"function"==typeof t.defaultValue?t.defaultValue():t.defaultValue}function t(e,t){return e._attributes.hasOwnProperty(t)||e._inFlightAttributes.hasOwnProperty(t)||e._data.hasOwnProperty(t)}function r(e,t){return e._attributes.hasOwnProperty(t)?e._attributes[t]:e._inFlightAttributes.hasOwnProperty(t)?e._inFlightAttributes[t]:e._data[t]}var n=Ember.get;DS.Model.reopenClass({attributes:Ember.computed(function(){var e=Ember.Map.create();return this.eachComputedProperty(function(t,r){r.isAttribute&&(r.name=t,e.set(t,r))}),e}),transformedAttributes:Ember.computed(function(){var e=Ember.Map.create();return this.eachAttribute(function(t,r){r.type&&e.set(t,r.type)}),e}),eachAttribute:function(e,t){n(this,"attributes").forEach(function(r,n){e.call(t,r,n)},t)},eachTransformedAttribute:function(e,t){n(this,"transformedAttributes").forEach(function(r,n){e.call(t,r,n)})}}),DS.Model.reopen({eachAttribute:function(e,t){this.constructor.eachAttribute(e,t) -}}),DS.attr=function(n,i){i=i||{};var a={type:n,isAttribute:!0,options:i};return Ember.computed(function(n,a){if(arguments.length>1){var o=this._attributes[n]||this._inFlightAttributes[n]||this._data[n];return this.send("didSetProperty",{name:n,oldValue:o,originalValue:this._data[n],value:a}),this._attributes[n]=a,a}return t(this,n)?r(this,n):e(this,i,n)}).property("data").meta(a)}}(),function(){var e=DS.AttributeChange=function(e){this.record=e.record,this.store=e.store,this.name=e.name,this.value=e.value,this.oldValue=e.oldValue};e.createChange=function(t){return new e(t)},e.prototype={sync:function(){this.value!==this.oldValue&&(this.record.send("becomeDirty"),this.record.updateRecordArraysLater()),this.destroy()},destroy:function(){delete this.record._changesToSync[this.name]}}}(),function(){function e(e){return"object"==typeof e&&(!e.then||"function"!=typeof e.then)}var t=Ember.get,r=Ember.set,n=Ember.EnumerableUtils.forEach;DS.RelationshipChange=function(e){this.parentRecord=e.parentRecord,this.childRecord=e.childRecord,this.firstRecord=e.firstRecord,this.firstRecordKind=e.firstRecordKind,this.firstRecordName=e.firstRecordName,this.secondRecord=e.secondRecord,this.secondRecordKind=e.secondRecordKind,this.secondRecordName=e.secondRecordName,this.changeType=e.changeType,this.store=e.store,this.committed={}},DS.RelationshipChangeAdd=function(e){DS.RelationshipChange.call(this,e)},DS.RelationshipChangeRemove=function(e){DS.RelationshipChange.call(this,e)},DS.RelationshipChange.create=function(e){return new DS.RelationshipChange(e)},DS.RelationshipChangeAdd.create=function(e){return new DS.RelationshipChangeAdd(e)},DS.RelationshipChangeRemove.create=function(e){return new DS.RelationshipChangeRemove(e)},DS.OneToManyChange={},DS.OneToNoneChange={},DS.ManyToNoneChange={},DS.OneToOneChange={},DS.ManyToManyChange={},DS.RelationshipChange._createChange=function(e){return"add"===e.changeType?DS.RelationshipChangeAdd.create(e):"remove"===e.changeType?DS.RelationshipChangeRemove.create(e):void 0},DS.RelationshipChange.determineRelationshipType=function(e,t){var r,n,i=t.key,a=t.kind,o=e.inverseFor(i);return o&&(r=o.name,n=o.kind),o?"belongsTo"===n?"belongsTo"===a?"oneToOne":"manyToOne":"belongsTo"===a?"oneToMany":"manyToMany":"belongsTo"===a?"oneToNone":"manyToNone"},DS.RelationshipChange.createChange=function(e,t,r,n){var i,a=e.constructor;return i=DS.RelationshipChange.determineRelationshipType(a,n),"oneToMany"===i?DS.OneToManyChange.createChange(e,t,r,n):"manyToOne"===i?DS.OneToManyChange.createChange(t,e,r,n):"oneToNone"===i?DS.OneToNoneChange.createChange(e,t,r,n):"manyToNone"===i?DS.ManyToNoneChange.createChange(e,t,r,n):"oneToOne"===i?DS.OneToOneChange.createChange(e,t,r,n):"manyToMany"===i?DS.ManyToManyChange.createChange(e,t,r,n):void 0},DS.OneToNoneChange.createChange=function(e,t,r,n){var i=n.key,a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,store:r,changeType:n.changeType,firstRecordName:i,firstRecordKind:"belongsTo"});return r.addRelationshipChangeFor(e,i,t,null,a),a},DS.ManyToNoneChange.createChange=function(e,t,r,n){var i=n.key,a=DS.RelationshipChange._createChange({parentRecord:e,childRecord:t,secondRecord:e,store:r,changeType:n.changeType,secondRecordName:n.key,secondRecordKind:"hasMany"});return r.addRelationshipChangeFor(e,i,t,null,a),a},DS.ManyToManyChange.createChange=function(e,t,r,n){var i=n.key,a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"hasMany",secondRecordKind:"hasMany",store:r,changeType:n.changeType,firstRecordName:i});return r.addRelationshipChangeFor(e,i,t,null,a),a},DS.OneToOneChange.createChange=function(e,t,r,n){var i;n.parentType?i=n.parentType.inverseFor(n.key).name:n.key&&(i=n.key);var a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"belongsTo",secondRecordKind:"belongsTo",store:r,changeType:n.changeType,firstRecordName:i});return r.addRelationshipChangeFor(e,i,t,null,a),a},DS.OneToOneChange.maintainInvariant=function(e,r,n,i){if("add"===e.changeType&&r.recordIsMaterialized(n)){var a=t(n,i);if(a){var o=DS.OneToOneChange.createChange(n,a,r,{parentType:e.parentType,hasManyName:e.hasManyName,changeType:"remove",key:e.key});r.addRelationshipChangeFor(n,i,e.parentRecord,null,o),o.sync()}}},DS.OneToManyChange.createChange=function(e,t,r,n){var i;n.parentType?(i=n.parentType.inverseFor(n.key).name,DS.OneToManyChange.maintainInvariant(n,r,e,i)):n.key&&(i=n.key);var a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"belongsTo",secondRecordKind:"hasMany",store:r,changeType:n.changeType,firstRecordName:i});return r.addRelationshipChangeFor(e,i,t,a.getSecondRecordName(),a),a},DS.OneToManyChange.maintainInvariant=function(e,r,n,i){if("add"===e.changeType&&n){var a=t(n,i);if(a){var o=DS.OneToManyChange.createChange(n,a,r,{parentType:e.parentType,hasManyName:e.hasManyName,changeType:"remove",key:e.key});r.addRelationshipChangeFor(n,i,e.parentRecord,o.getSecondRecordName(),o),o.sync()}}},DS.RelationshipChange.prototype={getSecondRecordName:function(){var e,t=this.secondRecordName;if(!t){if(e=this.secondRecord,!e)return;var r=this.firstRecord.constructor,n=r.inverseFor(this.firstRecordName);this.secondRecordName=n.name}return this.secondRecordName},getFirstRecordName:function(){var e=this.firstRecordName;return e},destroy:function(){var e=this.childRecord,t=this.getFirstRecordName(),r=this.getSecondRecordName(),n=this.store;n.removeRelationshipChangeFor(e,t,this.parentRecord,r,this.changeType)},getSecondRecord:function(){return this.secondRecord},getFirstRecord:function(){return this.firstRecord},coalesce:function(){var e=this.store.relationshipChangePairsFor(this.firstRecord);n(e,function(e){var t=e.add,r=e.remove;t&&r&&(t.destroy(),r.destroy())})}},DS.RelationshipChangeAdd.prototype=Ember.create(DS.RelationshipChange.create({})),DS.RelationshipChangeRemove.prototype=Ember.create(DS.RelationshipChange.create({})),DS.RelationshipChangeAdd.prototype.changeType="add",DS.RelationshipChangeAdd.prototype.sync=function(){var n=this.getSecondRecordName(),i=this.getFirstRecordName(),a=this.getFirstRecord(),o=this.getSecondRecord();o instanceof DS.Model&&a instanceof DS.Model&&("belongsTo"===this.secondRecordKind?o.suspendRelationshipObservers(function(){r(o,n,a)}):"hasMany"===this.secondRecordKind&&o.suspendRelationshipObservers(function(){var r=t(o,n);e(r)&&r.addObject(a)})),a instanceof DS.Model&&o instanceof DS.Model&&t(a,i)!==o&&("belongsTo"===this.firstRecordKind?a.suspendRelationshipObservers(function(){r(a,i,o)}):"hasMany"===this.firstRecordKind&&a.suspendRelationshipObservers(function(){var r=t(a,i);e(r)&&r.addObject(o)})),this.coalesce()},DS.RelationshipChangeRemove.prototype.changeType="remove",DS.RelationshipChangeRemove.prototype.sync=function(){var n=this.getSecondRecordName(),i=this.getFirstRecordName(),a=this.getFirstRecord(),o=this.getSecondRecord();o instanceof DS.Model&&a instanceof DS.Model&&("belongsTo"===this.secondRecordKind?o.suspendRelationshipObservers(function(){r(o,n,null)}):"hasMany"===this.secondRecordKind&&o.suspendRelationshipObservers(function(){var r=t(o,n);e(r)&&r.removeObject(a)})),a instanceof DS.Model&&t(a,i)&&("belongsTo"===this.firstRecordKind?a.suspendRelationshipObservers(function(){r(a,i,null)}):"hasMany"===this.firstRecordKind&&a.suspendRelationshipObservers(function(){var r=t(a,i);e(r)&&r.removeObject(o)})),this.coalesce()}}(),function(){function e(e,n,i){return Ember.computed(function(e,n){var a=t(this,"data"),o=t(this,"store");if(2===arguments.length)return void 0===n?null:n;var s=a.links&&a.links[e],c=a[e];if(r(c)){if(s){var u=Ember.RSVP.defer();return o.findBelongsTo(this,s,i,u),DS.PromiseObject.create({promise:u.promise})}return null}var d=o.fetchRecord(c)||Ember.RSVP.resolve(c);return DS.PromiseObject.create({promise:d})}).property("data").meta(i)}var t=Ember.get,r=(Ember.set,Ember.isNone);DS.belongsTo=function(n,i){"object"==typeof n&&(i=n,n=void 0),i=i||{};var a={type:n,isRelationship:!0,options:i,kind:"belongsTo"};return i.async?e(n,i,a):Ember.computed(function(e,i){var a,o,s=t(this,"data"),c=t(this,"store");return o="string"==typeof n?c.modelFor(n):n,2===arguments.length?void 0===i?null:i:(a=s[e],r(a)?null:(c.fetchRecord(a),a))}).property("data").meta(a)},DS.Model.reopen({belongsToWillChange:Ember.beforeObserver(function(e,r){if(t(e,"isLoaded")){var n=t(e,r);if(n){var i=t(e,"store"),a=DS.RelationshipChange.createChange(e,n,i,{key:r,kind:"belongsTo",changeType:"remove"});a.sync(),this._changesToSync[r]=a}}}),belongsToDidChange:Ember.immediateObserver(function(e,r){if(t(e,"isLoaded")){var n=t(e,r);if(n){var i=t(e,"store"),a=DS.RelationshipChange.createChange(e,n,i,{key:r,kind:"belongsTo",changeType:"add"});a.sync()}}delete this._changesToSync[r]})})}(),function(){function e(e,r,n){return Ember.computed(function(e){if(this._relationships[e])return this._relationships[e];var i=Ember.RSVP.defer(),a=t(this,e,r,function(t,r){var a=r.links&&r.links[e];return a?t.findHasMany(this,a,n,i):t.findMany(this,r[e],n.type,i)}),o=i.promise.then(function(){return a});return DS.PromiseArray.create({promise:o})}).property("data").meta(n)}function t(e,t,r,a){var o=e._relationships;if(o[t])return o[t];var s=n(e,"data"),c=n(e,"store"),u=o[t]=a.call(e,c,s);return i(u,{owner:e,name:t,isPolymorphic:r.polymorphic})}function r(r,n){n=n||{};var i={type:r,isRelationship:!0,options:n,kind:"hasMany"};return n.async?e(r,n,i):Ember.computed(function(e){return t(this,e,n,function(t,r){return r[e],t.findMany(this,r[e],i.type)})}).property("data").meta(i)}var n=Ember.get,i=(Ember.set,Ember.setProperties);DS.hasMany=function(e,t){return"object"==typeof e&&(t=e,e=void 0),r(e,t)}}(),function(){var e=Ember.get;Ember.set,DS.Model.reopen({didDefineProperty:function(e,t,r){if(r instanceof Ember.Descriptor){var n=r.meta();n.isRelationship&&"belongsTo"===n.kind&&(Ember.addObserver(e,t,null,"belongsToDidChange"),Ember.addBeforeObserver(e,t,null,"belongsToWillChange")),n.parentType=e.constructor}}}),DS.Model.reopenClass({typeForRelationship:function(t){var r=e(this,"relationshipsByName").get(t);return r&&r.type},inverseFor:function(t){function r(t,n,i){i=i||[];var a=e(n,"relationships");if(a){var o=a.get(t);return o&&i.push.apply(i,a.get(t)),t.superclass&&r(t.superclass,n,i),i}}var n=this.typeForRelationship(t);if(!n)return null;var i=this.metaForProperty(t).options;if(null===i.inverse)return null;var a,o;if(i.inverse)a=i.inverse,o=Ember.get(n,"relationshipsByName").get(a).kind;else{var s=r(this,n);if(0===s.length)return null;a=s[0].name,o=s[0].kind}return{type:n,name:a,kind:o}},relationships:Ember.computed(function(){var e=new Ember.MapWithDefault({defaultValue:function(){return[]}});return this.eachComputedProperty(function(t,r){if(r.isRelationship){"string"==typeof r.type&&(r.type=this.store.modelFor(r.type));var n=e.get(r.type);n.push({name:t,kind:r.kind})}}),e}),relationshipNames:Ember.computed(function(){var e={hasMany:[],belongsTo:[]};return this.eachComputedProperty(function(t,r){r.isRelationship&&e[r.kind].push(t)}),e}),relatedTypes:Ember.computed(function(){var t,r=Ember.A();return this.eachComputedProperty(function(n,i){i.isRelationship&&(t=i.type,"string"==typeof t&&(t=e(this,t,!1)||this.store.modelFor(t)),r.contains(t)||r.push(t))}),r}),relationshipsByName:Ember.computed(function(){var e,t=Ember.Map.create();return this.eachComputedProperty(function(r,n){n.isRelationship&&(n.key=r,e=n.type,e||"hasMany"!==n.kind?e||(e=r):e=Ember.String.singularize(r),"string"==typeof e&&(n.type=this.store.modelFor(e)),t.set(r,n))}),t}),fields:Ember.computed(function(){var e=Ember.Map.create();return this.eachComputedProperty(function(t,r){r.isRelationship?e.set(t,r.kind):r.isAttribute&&e.set(t,"attribute")}),e}),eachRelationship:function(t,r){e(this,"relationshipsByName").forEach(function(e,n){t.call(r,e,n)})},eachRelatedType:function(t,r){e(this,"relatedTypes").forEach(function(e){t.call(r,e)})}}),DS.Model.reopen({eachRelationship:function(e,t){this.constructor.eachRelationship(e,t)}})}(),function(){var e=Ember.get;Ember.set;var t=Ember.run.once,r=Ember.EnumerableUtils.forEach;DS.RecordArrayManager=Ember.Object.extend({init:function(){this.filteredRecordArrays=Ember.MapWithDefault.create({defaultValue:function(){return[]}}),this.changedRecords=[]},recordDidChange:function(e){this.changedRecords.push(e),t(this,this.updateRecordArrays)},recordArraysForRecord:function(e){return e._recordArrays=e._recordArrays||Ember.OrderedSet.create(),e._recordArrays},updateRecordArrays:function(){r(this.changedRecords,function(t){var n,i=t.constructor,a=this.filteredRecordArrays.get(i);r(a,function(r){n=e(r,"filterFunction"),this.updateRecordArray(r,n,i,t)},this);var o=t._loadingRecordArrays;if(o){for(var s=0,c=o.length;c>s;s++)o[s].loadedRecord();t._loadingRecordArrays=[]}},this),this.changedRecords=[]},updateRecordArray:function(e,t,r,n){var i;i=t?t(n):!0;var a=this.recordArraysForRecord(n);i?(a.add(e),e.addRecord(n)):i||(a.remove(e),e.removeRecord(n))},remove:function(e){var t=e._recordArrays;t&&r(t,function(t){t.removeRecord(e)})},updateFilter:function(t,r,n){for(var i,a=this.store.typeMapFor(r),o=a.records,s=0,c=o.length;c>s;s++)i=o[s],e(i,"isDeleted")||e(i,"isEmpty")||this.updateRecordArray(t,n,r,i)},createManyArray:function(e,t){var n=DS.ManyArray.create({type:e,content:t,store:this.store});return r(t,function(e){var t=this.recordArraysForRecord(e);t.add(n)},this),n},registerFilteredRecordArray:function(e,t,r){var n=this.filteredRecordArrays.get(t);n.push(e),this.updateFilter(e,t,r)},registerWaitingRecordArray:function(e,t){var r=e._loadingRecordArrays||[];r.push(t),e._loadingRecordArrays=r}})}(),function(){var e=Ember.get;Ember.set;var t=Ember.ArrayPolyfills.map,r=["description","fileName","lineNumber","message","name","number","stack"];DS.InvalidError=function(e){var t=Error.prototype.constructor.call(this,"The backend rejected the commit because it was invalid: "+Ember.inspect(e));this.errors=e;for(var n=0,i=r.length;i>n;n++)this[r[n]]=t[r[n]]},DS.InvalidError.prototype=Ember.create(Error.prototype),DS.Adapter=Ember.Object.extend(DS._Mappable,{find:Ember.required(Function),findAll:null,findQuery:null,generateIdForRecord:null,serialize:function(t,r){return e(t,"store").serializerFor(t.constructor.typeKey).serialize(t,r)},createRecord:Ember.required(Function),updateRecord:Ember.required(Function),deleteRecord:Ember.required(Function),findMany:function(e,r,n){var i=t.call(n,function(t){return this.find(e,r,t)},this);return Ember.RSVP.all(i)}})}(),function(){var e=Ember.get,t=Ember.String.fmt,r=Ember.EnumerableUtils.indexOf,n=0;DS.FixtureAdapter=DS.Adapter.extend({serializer:null,simulateRemoteResponse:!0,latency:50,fixturesForType:function(e){if(e.FIXTURES){var r=Ember.A(e.FIXTURES);return r.map(function(e){var r=typeof e.id;if("number"!==r&&"string"!==r)throw new Error(t("the id property must be defined as a number or string for fixture %@",[e]));return e.id=e.id+"",e})}return null},queryFixtures:function(){},updateFixtures:function(e,t){e.FIXTURES||(e.FIXTURES=[]);var r=e.FIXTURES;this.deleteLoadedFixture(e,t),r.push(t)},mockJSON:function(e,t,r){return e.serializerFor(t).serialize(r,{includeId:!0})},generateIdForRecord:function(){return"fixture-"+n++},find:function(e,t,r){var n,i=this.fixturesForType(t);return i&&(n=Ember.A(i).findProperty("id",r)),n?this.simulateRemoteCall(function(){return n},this):void 0},findMany:function(e,t,n){var i=this.fixturesForType(t);return i&&(i=i.filter(function(e){return-1!==r(n,e.id)})),i?this.simulateRemoteCall(function(){return i},this):void 0},findAll:function(e,t){var r=this.fixturesForType(t);return this.simulateRemoteCall(function(){return r},this)},findQuery:function(e,t,r){var n=this.fixturesForType(t);return n=this.queryFixtures(n,r,t),n?this.simulateRemoteCall(function(){return n},this):void 0},createRecord:function(e,t,r){var n=this.mockJSON(e,t,r);return this.updateFixtures(t,n),this.simulateRemoteCall(function(){return n},this)},updateRecord:function(e,t,r){var n=this.mockJSON(e,t,r);return this.updateFixtures(t,n),this.simulateRemoteCall(function(){return n},this)},deleteRecord:function(e,t,r){var n=this.mockJSON(e,t,r);return this.deleteLoadedFixture(t,n),this.simulateRemoteCall(function(){return null})},deleteLoadedFixture:function(e,t){var n=this.findExistingFixture(e,t);if(n){var i=r(e.FIXTURES,n);return e.FIXTURES.splice(i,1),!0}},findExistingFixture:function(t,r){var n=this.fixturesForType(t),i=e(r,"id");return this.findFixtureById(n,i)},findFixtureById:function(t,r){return Ember.A(t).find(function(t){return""+e(t,"id")==""+r?!0:!1})},simulateRemoteCall:function(t,r){var n=this;return new Ember.RSVP.Promise(function(i){e(n,"simulateRemoteResponse")?Ember.run.later(function(){i(t.call(r))},e(n,"latency")):Ember.run.once(function(){i(t.call(r))})})}})}(),function(){function e(e){return null==e?null:e+""}var t=Ember.get;Ember.set;var r=Ember.ArrayPolyfills.forEach,n=Ember.ArrayPolyfills.map;DS.RESTSerializer=DS.JSONSerializer.extend({normalize:function(e,t,r){return this.normalizeId(t),this.normalizeUsingDeclaredMapping(e,t),this.normalizeAttributes(e,t),this.normalizeRelationships(e,t),this.normalizeHash&&this.normalizeHash[r]?this.normalizeHash[r](t):this._super(e,t,r)},normalizePayload:function(e,t){return t},normalizeId:function(e){var r=t(this,"primaryKey");"id"!==r&&(e.id=e[r],delete e[r])},normalizeUsingDeclaredMapping:function(e,r){var n,i,a=t(this,"attrs");if(a)for(i in a)n=a[i],r[i]=r[n],delete r[n]},normalizeAttributes:function(e,t){var r;this.keyForAttribute&&e.eachAttribute(function(e){r=this.keyForAttribute(e),e!==r&&(t[e]=t[r],delete t[r])},this)},normalizeRelationships:function(e,t){var r;this.keyForRelationship&&e.eachRelationship(function(e,n){r=this.keyForRelationship(e,n.kind),e!==r&&(t[e]=t[r],delete t[r])},this)},extractSingle:function(t,n,i,a){i=this.normalizePayload(n,i);var o,s=n.typeKey;for(var c in i){var u=this.typeForRoot(c),d=u===s;d&&"array"!==Ember.typeOf(i[c])?o=this.normalize(n,i[c],c):(t.modelFor(u),r.call(i[c],function(r){var n=this.typeForRoot(c),i=t.modelFor(n),s=t.serializerFor(i);r=s.normalize(i,r,c);var u=d&&!a&&!o,l=d&&e(r.id)===a;u||l?o=r:t.push(n,r)},this))}return o},extractArray:function(e,t,r){r=this.normalizePayload(t,r);var i,a=t.typeKey;for(var o in r){var s=o,c=!1;"_"===o.charAt(0)&&(c=!0,s=o.substr(1));var u=this.typeForRoot(s),d=e.modelFor(u),l=e.serializerFor(d),h=!c&&u===a,f=n.call(r[o],function(e){return l.normalize(d,e,o)},this);h?i=f:e.pushMany(u,f)}return i},pushPayload:function(e,t){t=this.normalizePayload(null,t);for(var r in t){var i=this.typeForRoot(r),a=e.modelFor(i),o=n.call(t[r],function(e){return this.normalize(a,e,r)},this);e.pushMany(i,o)}},typeForRoot:function(e){return Ember.String.singularize(e)},serialize:function(){return this._super.apply(this,arguments)},serializeIntoHash:function(e,t,r,n){e[t.typeKey]=this.serialize(r,n)},serializePolymorphicType:function(e,r,n){var i=n.key,a=t(e,i);i=this.keyForAttribute?this.keyForAttribute(i):i,r[i+"Type"]=a.constructor.typeKey}})}(),function(){var e=Ember.get;Ember.set;var t=Ember.ArrayPolyfills.forEach;DS.RESTAdapter=DS.Adapter.extend({defaultSerializer:"_rest",find:function(e,t,r){return this.ajax(this.buildURL(t.typeKey,r),"GET")},findAll:function(e,t,r){var n;return r&&(n={since:r}),this.ajax(this.buildURL(t.typeKey),"GET",{data:n})},findQuery:function(e,t,r){return this.ajax(this.buildURL(t.typeKey),"GET",{data:r})},findMany:function(e,t,r){return this.ajax(this.buildURL(t.typeKey),"GET",{data:{ids:r}})},findHasMany:function(t,r,n){var i=e(this,"host"),a=e(r,"id"),o=r.constructor.typeKey;return i&&"/"===n.charAt(0)&&"/"!==n.charAt(1)&&(n=i+n),this.ajax(this.urlPrefix(n,this.buildURL(o,a)),"GET")},findBelongsTo:function(t,r,n){var i=e(r,"id"),a=r.constructor.typeKey;return this.ajax(this.urlPrefix(n,this.buildURL(a,i)),"GET")},createRecord:function(e,t,r){var n={},i=e.serializerFor(t.typeKey);return i.serializeIntoHash(n,t,r,{includeId:!0}),this.ajax(this.buildURL(t.typeKey),"POST",{data:n})},updateRecord:function(t,r,n){var i={},a=t.serializerFor(r.typeKey);a.serializeIntoHash(i,r,n);var o=e(n,"id");return this.ajax(this.buildURL(r.typeKey,o),"PUT",{data:i})},deleteRecord:function(t,r,n){var i=e(n,"id");return this.ajax(this.buildURL(r.typeKey,i),"DELETE")},buildURL:function(t,r){var n=[],i=e(this,"host"),a=this.urlPrefix();return t&&n.push(this.pathForType(t)),r&&n.push(r),a&&n.unshift(a),n=n.join("/"),!i&&n&&(n="/"+n),n},urlPrefix:function(t,r){var n=e(this,"host"),i=e(this,"namespace"),a=[];return t?"/"===t.charAt(0)?n&&(t=t.slice(1),a.push(n)):/^http(s)?:\/\//.test(t)||a.push(r):(n&&a.push(n),i&&a.push(i)),t&&a.push(t),a.join("/")},pathForType:function(e){return Ember.String.pluralize(e)},ajaxError:function(e){return e&&(e.then=null),e},ajax:function(e,t,r){var n=this;return new Ember.RSVP.Promise(function(i,a){r=n.ajaxOptions(e,t,r),r.success=function(e){Ember.run(null,i,e)},r.error=function(e){Ember.run(null,a,n.ajaxError(e))},Ember.$.ajax(r)})},ajaxOptions:function(e,r,n){if(n=n||{},n.url=e,n.type=r,n.dataType="json",n.context=this,n.data&&"GET"!==r&&(n.contentType="application/json; charset=utf-8",n.data=JSON.stringify(n.data)),void 0!==this.headers){var i=this.headers;n.beforeSend=function(e){t.call(Ember.keys(i),function(t){e.setRequestHeader(t,i[t])})}}return n}})}(),function(){DS.Model.reopen({_debugInfo:function(){var e=["id"],t={belongsTo:[],hasMany:[]},r=[];this.eachAttribute(function(t){e.push(t)},this),this.eachRelationship(function(e,n){t[n.kind].push(e),r.push(e)});var n=[{name:"Attributes",properties:e,expand:!0},{name:"Belongs To",properties:t.belongsTo,expand:!0},{name:"Has Many",properties:t.hasMany,expand:!0},{name:"Flags",properties:["isLoaded","isDirty","isSaving","isDeleted","isError","isNew","isValid"]}];return{propertyInfo:{includeOtherProperties:!0,groups:n,expensiveProperties:r}}}})}(),function(){Ember.String.pluralize=function(e){return Ember.Inflector.inflector.pluralize(e)},Ember.String.singularize=function(e){return Ember.Inflector.inflector.singularize(e)}}(),function(){function e(e,t){for(var r=0,n=t.length;n>r;r++)e.uncountable[t[r]]=!0}function t(e,t){for(var r,n=0,i=t.length;i>n;n++)r=t[n],e.irregular[r[0]]=r[1],e.irregularInverse[r[1]]=r[0]}function r(r){r=r||{},r.uncountable=r.uncountable||{},r.irregularPairs=r.irregularPairs||{};var n=this.rules={plurals:r.plurals||[],singular:r.singular||[],irregular:{},irregularInverse:{},uncountable:{}};e(n,r.uncountable),t(n,r.irregularPairs)}var n=/^\s*$/;r.prototype={plural:function(e,t){this.rules.plurals.push([e,t])},singular:function(e,t){this.rules.singular.push([e,t])},uncountable:function(t){e(this.rules,[t])},irregular:function(e,r){t(this.rules,[[e,r]])},pluralize:function(e){return this.inflect(e,this.rules.plurals,this.rules.irregular)},singularize:function(e){return this.inflect(e,this.rules.singular,this.rules.irregularInverse)},inflect:function(e,t,r){var i,a,o,s,c,u,d,l;if(c=n.test(e))return e;if(s=e.toLowerCase(),u=this.rules.uncountable[s])return e;if(d=r&&r[s])return d;for(var h=t.length,f=0;h>f&&(i=t[h-1],l=i[0],!l.test(e));h--);return i=i||[],l=i[0],a=i[1],o=e.replace(l,a)}},Ember.Inflector=r}(),function(){Ember.Inflector.defaultRules={plurals:[[/$/,"s"],[/s$/i,"s"],[/^(ax|test)is$/i,"$1es"],[/(octop|vir)us$/i,"$1i"],[/(octop|vir)i$/i,"$1i"],[/(alias|status)$/i,"$1es"],[/(bu)s$/i,"$1ses"],[/(buffal|tomat)o$/i,"$1oes"],[/([ti])um$/i,"$1a"],[/([ti])a$/i,"$1a"],[/sis$/i,"ses"],[/(?:([^f])fe|([lr])f)$/i,"$1$2ves"],[/(hive)$/i,"$1s"],[/([^aeiouy]|qu)y$/i,"$1ies"],[/(x|ch|ss|sh)$/i,"$1es"],[/(matr|vert|ind)(?:ix|ex)$/i,"$1ices"],[/^(m|l)ouse$/i,"$1ice"],[/^(m|l)ice$/i,"$1ice"],[/^(ox)$/i,"$1en"],[/^(oxen)$/i,"$1"],[/(quiz)$/i,"$1zes"]],singular:[[/s$/i,""],[/(ss)$/i,"$1"],[/(n)ews$/i,"$1ews"],[/([ti])a$/i,"$1um"],[/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i,"$1sis"],[/(^analy)(sis|ses)$/i,"$1sis"],[/([^f])ves$/i,"$1fe"],[/(hive)s$/i,"$1"],[/(tive)s$/i,"$1"],[/([lr])ves$/i,"$1f"],[/([^aeiouy]|qu)ies$/i,"$1y"],[/(s)eries$/i,"$1eries"],[/(m)ovies$/i,"$1ovie"],[/(x|ch|ss|sh)es$/i,"$1"],[/^(m|l)ice$/i,"$1ouse"],[/(bus)(es)?$/i,"$1"],[/(o)es$/i,"$1"],[/(shoe)s$/i,"$1"],[/(cris|test)(is|es)$/i,"$1is"],[/^(a)x[ie]s$/i,"$1xis"],[/(octop|vir)(us|i)$/i,"$1us"],[/(alias|status)(es)?$/i,"$1"],[/^(ox)en/i,"$1"],[/(vert|ind)ices$/i,"$1ex"],[/(matr)ices$/i,"$1ix"],[/(quiz)zes$/i,"$1"],[/(database)s$/i,"$1"]],irregularPairs:[["person","people"],["man","men"],["child","children"],["sex","sexes"],["move","moves"],["cow","kine"],["zombie","zombies"]],uncountable:["equipment","information","rice","money","species","series","fish","sheep","jeans","police"]}}(),function(){(Ember.EXTEND_PROTOTYPES===!0||Ember.EXTEND_PROTOTYPES.String)&&(String.prototype.pluralize=function(){return Ember.String.pluralize(this)},String.prototype.singularize=function(){return Ember.String.singularize(this)})}(),function(){Ember.Inflector.inflector=new Ember.Inflector(Ember.Inflector.defaultRules)}(),function(){function e(e,n,i,a,o){var s=t(n,"attrs");s&&i.eachRelationship(function(n,i){var c,u,d,l,h=s[n],f=e.serializerFor(i.type.typeKey),p=t(f,"primaryKey");if("hasMany"===i.kind&&h&&("always"===h.embedded||"load"===h.embedded)){if(u="_"+Ember.String.pluralize(i.type.typeKey),c=this.keyForRelationship(n,i.kind),d=this.keyForAttribute(n),l=[],!a[d])return;o[u]=o[u]||[],r(a[d],function(e){l.push(e[p]),o[u].push(e)}),a[c]=l,delete a[d]}},n)}var t=Ember.get,r=Ember.EnumerableUtils.forEach;DS.ActiveModelSerializer=DS.RESTSerializer.extend({keyForAttribute:function(e){return Ember.String.decamelize(e)},keyForRelationship:function(e,t){return e=Ember.String.decamelize(e),"belongsTo"===t?e+"_id":"hasMany"===t?Ember.String.singularize(e)+"_ids":e},serializeHasMany:function(e,r,n){var i=n.key,a=t(this,"attrs"),o=a&&a[i]&&"always"===a[i].embedded;o&&(r[this.keyForAttribute(i)]=t(e,i).map(function(e){var r=e.serialize(),n=t(this,"primaryKey");return r[n]=t(e,n),r},this))},serializeIntoHash:function(e,t,r,n){var i=Ember.String.decamelize(t.typeKey);e[i]=this.serialize(r,n)},serializePolymorphicType:function(e,r,n){var i=n.key,a=t(e,i);i=this.keyForAttribute(i),r[i+"_type"]=Ember.String.capitalize(a.constructor.typeKey)},typeForRoot:function(e){var t=Ember.String.camelize(e);return Ember.String.singularize(t)},normalizeRelationships:function(e,t){var n,i;this.keyForRelationship&&e.eachRelationship(function(e,a){if(a.options.polymorphic){if(n=this.keyForAttribute(e),i=t[n],i&&i.type)i.type=this.typeForRoot(i.type);else if(i&&"hasMany"===a.kind){var o=this;r(i,function(e){e.type=o.typeForRoot(e.type)})}}else n=this.keyForRelationship(e,a.kind),i=t[n];t[e]=i,e!==n&&delete t[n]},this)},extractSingle:function(t,r,n,i,a){var o=this.keyForAttribute(r.typeKey),s=n[o];return e(t,this,r,s,n),this._super(t,r,n,i,a)},extractArray:function(t,n,i){var a=this.keyForAttribute(n.typeKey),o=i[Ember.String.pluralize(a)];return r(o,function(r){e(t,this,n,r,i)},this),this._super(t,n,i)}})}(),function(){var e=Ember.EnumerableUtils.forEach;DS.ActiveModelAdapter=DS.RESTAdapter.extend({defaultSerializer:"_ams",pathForType:function(e){var t=Ember.String.decamelize(e);return Ember.String.pluralize(t)},ajaxError:function(t){var r=this._super(t);if(t&&422===t.status){var n=Ember.$.parseJSON(t.responseText).errors,i={};return e(Ember.keys(n),function(e){i[Ember.String.camelize(e)]=n[e]}),new DS.InvalidError(i)}return r}})}(),function(){Ember.onLoad("Ember.Application",function(e){e.initializer({name:"activeModelAdapter",initialize:function(e,t){t.register("serializer:_ams",DS.ActiveModelSerializer),t.register("adapter:_ams",DS.ActiveModelAdapter)}})})}()}(),"undefined"==typeof location||"localhost"!==location.hostname&&"127.0.0.1"!==location.hostname||Ember.Logger.warn("You are running a production build of Ember on localhost and won't receive detailed error messages. If you want full error messages please use the non-minified build provided on the Ember website."); +/*! + * @overview Ember Data + * @copyright Copyright 2011-2013 Tilde Inc. and contributors. + * Portions Copyright 2011 LivingSocial Inc. + * @license Licensed under MIT license (see license.js) + */ +!function(){var e,t;!function(){var r={},i={};e=function(e,t,i){r[e]={deps:t,callback:i}},t=function(e){if(i[e])return i[e];i[e]={};var n,a,o,s,c;if(n=r[e],!n)throw new Error("Module '"+e+"' not found.");a=n.deps,o=n.callback,s=[];for(var d=0,u=a.length;u>d;d++)"exports"===a[d]?s.push(c={}):s.push(t(a[d]));var l=o.apply(this,s);return i[e]=c||l}}(),function(){var e;"undefined"==typeof e&&(e=Ember.Namespace.create({VERSION:"1.0.0-beta.5+pre.69cb8b87"}),"undefined"!=typeof window&&(window.DS=e),Ember.libraries&&Ember.libraries.registerCoreLibrary("Ember Data",e.VERSION))}(),function(){function e(e){return function(){return this[e].apply(this,arguments)}}var t=Ember.get,r=(Ember.set,Ember.isNone);DS.JSONSerializer=Ember.Object.extend({primaryKey:"id",applyTransforms:function(e,t){return e.eachTransformedAttribute(function(e,r){var i=this.transformFor(r);t[e]=i.deserialize(t[e])},this),t},normalize:function(e,t){return t?(this.applyTransforms(e,t),t):t},serialize:function(e,r){var i={};if(r&&r.includeId){var n=t(e,"id");n&&(i[t(this,"primaryKey")]=t(e,"id"))}return e.eachAttribute(function(t,r){this.serializeAttribute(e,i,t,r)},this),e.eachRelationship(function(t,r){"belongsTo"===r.kind?this.serializeBelongsTo(e,i,r):"hasMany"===r.kind&&this.serializeHasMany(e,i,r)},this),i},serializeAttribute:function(e,r,i,n){var a=t(this,"attrs"),o=t(e,i),s=n.type;if(s){var c=this.transformFor(s);o=c.serialize(o)}i=a&&a[i]||(this.keyForAttribute?this.keyForAttribute(i):i),r[i]=o},serializeBelongsTo:function(e,i,n){var a=n.key,o=t(e,a);a=this.keyForRelationship?this.keyForRelationship(a,"belongsTo"):a,i[a]=r(o)?o:t(o,"id"),n.options.polymorphic&&this.serializePolymorphicType(e,i,n)},serializeHasMany:function(e,r,i){var n=i.key,a=DS.RelationshipChange.determineRelationshipType(e.constructor,i);("manyToNone"===a||"manyToMany"===a)&&(r[n]=t(e,n).mapBy("id"))},serializePolymorphicType:Ember.K,extract:function(e,t,r,i,n){this.extractMeta(e,t,r);var a="extract"+n.charAt(0).toUpperCase()+n.substr(1);return this[a](e,t,r,i,n)},extractFindAll:e("extractArray"),extractFindQuery:e("extractArray"),extractFindMany:e("extractArray"),extractFindHasMany:e("extractArray"),extractCreateRecord:e("extractSave"),extractUpdateRecord:e("extractSave"),extractDeleteRecord:e("extractSave"),extractFind:e("extractSingle"),extractFindBelongsTo:e("extractSingle"),extractSave:e("extractSingle"),extractSingle:function(e,t,r){return this.normalize(t,r)},extractArray:function(e,t,r){return this.normalize(t,r)},extractMeta:function(e,t,r){r&&r.meta&&(e.metaForType(t,r.meta),delete r.meta)},transformFor:function(e){var t=this.container.lookup("transform:"+e);return t}})}(),function(){var e=Ember.get,t=Ember.String.capitalize,r=Ember.String.underscore,i=window.DS;i.DebugAdapter=Ember.DataAdapter.extend({getFilters:function(){return[{name:"isNew",desc:"New"},{name:"isModified",desc:"Modified"},{name:"isClean",desc:"Clean"}]},detect:function(e){return e!==i.Model&&i.Model.detect(e)},columnsForType:function(i){var n=[{name:"id",desc:"Id"}],a=0,o=this;return e(i,"attributes").forEach(function(e){if(a++>o.attributeLimit)return!1;var i=t(r(e).replace("_"," "));n.push({name:e,desc:i})}),n},getRecords:function(e){return this.get("store").all(e)},getRecordColumnValues:function(t){var r=this,i=0,n={id:e(t,"id")};return t.eachAttribute(function(a){if(i++>r.attributeLimit)return!1;var o=e(t,a);n[a]=o}),n},getRecordKeywords:function(t){var r=[],i=Ember.A(["id"]);return t.eachAttribute(function(e){i.push(e)}),i.forEach(function(i){r.push(e(t,i))}),r},getRecordFilterValues:function(e){return{isNew:e.get("isNew"),isModified:e.get("isDirty")&&!e.get("isNew"),isClean:!e.get("isDirty")}},getRecordColor:function(e){var t="black";return e.get("isNew")?t="green":e.get("isDirty")&&(t="blue"),t},observeRecord:function(e,t){var r=Ember.A(),i=this,n=Ember.A(["id","isNew","isDirty"]);e.eachAttribute(function(e){n.push(e)}),n.forEach(function(n){var a=function(){t(i.wrapRecord(e))};Ember.addObserver(e,n,a),r.push(function(){Ember.removeObserver(e,n,a)})});var a=function(){r.forEach(function(e){e()})};return a}})}(),function(){DS.Transform=Ember.Object.extend({serialize:Ember.required(),deserialize:Ember.required()})}(),function(){DS.BooleanTransform=DS.Transform.extend({deserialize:function(e){var t=typeof e;return"boolean"===t?e:"string"===t?null!==e.match(/^true$|^t$|^1$/i):"number"===t?1===e:!1},serialize:function(e){return Boolean(e)}})}(),function(){DS.DateTransform=DS.Transform.extend({deserialize:function(e){var t=typeof e;return"string"===t?new Date(Ember.Date.parse(e)):"number"===t?new Date(e):null===e||void 0===e?e:null},serialize:function(e){if(e instanceof Date){var t=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],r=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],i=function(e){return 10>e?"0"+e:""+e},n=e.getUTCFullYear(),a=e.getUTCMonth(),o=e.getUTCDate(),s=e.getUTCDay(),c=e.getUTCHours(),d=e.getUTCMinutes(),u=e.getUTCSeconds(),l=t[s],h=i(o),f=r[a];return l+", "+h+" "+f+" "+n+" "+i(c)+":"+i(d)+":"+i(u)+" GMT"}return null}})}(),function(){var e=Ember.isEmpty;DS.NumberTransform=DS.Transform.extend({deserialize:function(t){return e(t)?null:Number(t)},serialize:function(t){return e(t)?null:Number(t)}})}(),function(){var e=Ember.isNone;DS.StringTransform=DS.Transform.extend({deserialize:function(t){return e(t)?null:String(t)},serialize:function(t){return e(t)?null:String(t)}})}(),function(){Ember.set;Ember.onLoad("Ember.Application",function(e){e.initializer({name:"store",initialize:function(e,t){t.register("store:main",t.Store||DS.Store),t.register("serializer:_default",DS.JSONSerializer),t.register("serializer:_rest",DS.RESTSerializer),t.register("adapter:_rest",DS.RESTAdapter),e.lookup("store:main")}}),e.initializer({name:"transforms",before:"store",initialize:function(e,t){t.register("transform:boolean",DS.BooleanTransform),t.register("transform:date",DS.DateTransform),t.register("transform:number",DS.NumberTransform),t.register("transform:string",DS.StringTransform)}}),e.initializer({name:"dataAdapter",before:"store",initialize:function(e,t){t.register("dataAdapter:main",DS.DebugAdapter)}}),e.initializer({name:"injectStore",before:"store",initialize:function(e,t){t.inject("controller","store","store:main"),t.inject("route","store","store:main"),t.inject("serializer","store","store:main"),t.inject("dataAdapter","store","store:main")}})})}(),function(){Ember.Date=Ember.Date||{};var e=Date.parse,t=[1,4,5,6,7,10,11];Ember.Date.parse=function(r){var i,n,a=0;if(n=/^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(r)){for(var o,s=0;o=t[s];++s)n[o]=+n[o]||0;n[2]=(+n[2]||1)-1,n[3]=+n[3]||1,"Z"!==n[8]&&void 0!==n[9]&&(a=60*n[10]+n[11],"+"===n[9]&&(a=0-a)),i=Date.UTC(n[1],n[2],n[3],n[4],n[5]+a,n[6],n[7])}else i=e?e(r):0/0;return i},(Ember.EXTEND_PROTOTYPES===!0||Ember.EXTEND_PROTOTYPES.Date)&&(Date.parse=Ember.Date.parse)}(),function(){{var e=Ember.get;Ember.set}DS.RecordArray=Ember.ArrayProxy.extend(Ember.Evented,{type:null,content:null,isLoaded:!1,isUpdating:!1,store:null,objectAtContent:function(t){var r=e(this,"content");return r.objectAt(t)},update:function(){if(!e(this,"isUpdating")){var t=e(this,"store"),r=e(this,"type");t.fetchAll(r,this)}},addRecord:function(t){e(this,"content").addObject(t)},removeRecord:function(t){e(this,"content").removeObject(t)},save:function(){var t="DS: RecordArray#save "+e(this,"type"),r=Ember.RSVP.all(this.invoke("save"),t).then(function(e){return Ember.A(e)},null,"DS: RecordArray#save apply Ember.NativeArray");return DS.PromiseArray.create({promise:r})}})}(),function(){var e=Ember.get;DS.FilteredRecordArray=DS.RecordArray.extend({filterFunction:null,isLoaded:!0,replace:function(){var t=e(this,"type").toString();throw new Error("The result of a client-side filter (on "+t+") is immutable.")},updateFilter:Ember.observer(function(){var t=e(this,"manager");t.updateFilter(this,e(this,"type"),e(this,"filterFunction"))},"filterFunction")})}(),function(){{var e=Ember.get;Ember.set}DS.AdapterPopulatedRecordArray=DS.RecordArray.extend({query:null,replace:function(){var t=e(this,"type").toString();throw new Error("The result of a server query (on "+t+") is immutable.")},load:function(t){var r=e(this,"store"),i=e(this,"type"),n=r.pushMany(i,t),a=r.metadataFor(i);this.setProperties({content:Ember.A(n),isLoaded:!0,meta:a}),Ember.run.once(this,"trigger","didLoad")}})}(),function(){var e=Ember.get,t=Ember.set,r=Ember.EnumerableUtils.map;DS.ManyArray=DS.RecordArray.extend({init:function(){this._super.apply(this,arguments),this._changesToSync=Ember.OrderedSet.create()},name:null,owner:null,isPolymorphic:!1,isLoaded:!1,promise:null,loadingRecordsCount:function(e){this.loadingRecordsCount=e},loadedRecord:function(){this.loadingRecordsCount--,0===this.loadingRecordsCount&&(t(this,"isLoaded",!0),this.trigger("didLoad"))},fetch:function(){var t=e(this,"content"),r=e(this,"store"),i=e(this,"owner"),n=Ember.RSVP.defer("DS: ManyArray#fetch "+e(this,"type")),a=t.filterProperty("isEmpty",!0);r.fetchMany(a,i,n)},replaceContent:function(e,t,i){i=r(i,function(e){return e},this),this._super(e,t,i)},arrangedContentDidChange:function(){Ember.run.once(this,"fetch")},arrayContentWillChange:function(t,r){var i=e(this,"owner"),n=e(this,"name");if(!i._suspendedRelationships)for(var a=t;t+r>a;a++){var o=e(this,"content").objectAt(a),s=DS.RelationshipChange.createChange(i,o,e(this,"store"),{parentType:i.constructor,changeType:"remove",kind:"hasMany",key:n});this._changesToSync.add(s)}return this._super.apply(this,arguments)},arrayContentDidChange:function(t,r,i){this._super.apply(this,arguments);var n=e(this,"owner"),a=e(this,"name"),o=e(this,"store");if(!n._suspendedRelationships){for(var s=t;t+i>s;s++){var c=e(this,"content").objectAt(s),d=DS.RelationshipChange.createChange(n,c,o,{parentType:n.constructor,changeType:"add",kind:"hasMany",key:a});d.hasManyName=a,this._changesToSync.add(d)}this._changesToSync.forEach(function(e){e.sync()}),this._changesToSync.clear()}},createRecord:function(t){var r,i=e(this,"owner"),n=e(i,"store"),a=e(this,"type");return r=n.createRecord.call(n,a,t),this.pushObject(r),r}})}(),function(){function e(e,r,a,o){return r.eachRelationship(function(r,s){if(a.links&&a.links[r])return o&&s.options.async&&(o._relationships[r]=null),void 0;var c=s.kind,d=a[r];null!=d&&("belongsTo"===c?t(e,a,r,s,d):"hasMany"===c&&(i(e,a,r,s,d),n(o,r,d)))}),a}function t(e,t,i,n,a){if(!(R(a)||a instanceof DS.Model)){var o;"number"==typeof a||"string"==typeof a?(o=r(n,i,t),t[i]=e.recordForId(o,a)):"object"==typeof a&&(t[i]=e.recordForId(a.type,a.id))}}function r(e,t,r){return e.options.polymorphic?r[t+"Type"]:e.type}function i(e,r,i,n,a){for(var o=0,s=a.length;s>o;o++)t(e,a,o,n,a[o])}function n(e,t,r){e&&r.pushObjects(e.get(t).filterBy("isNew"))}function a(e){return DS.PromiseObject.create({promise:e})}function o(e){return DS.PromiseArray.create({promise:e})}function s(e,t,r){return e.lookup("serializer:"+t)||e.lookup("serializer:application")||e.lookup("serializer:"+r)||e.lookup("serializer:_default")}function c(e){return e.lookup("serializer:application")||e.lookup("serializer:_default")}function d(e,t){var r=e.serializer,i=e.defaultSerializer,n=e.container;return n&&void 0===r&&(r=s(n,t.typeKey,i)),(null===r||void 0===r)&&(r={extract:function(e,t,r){return r}}),r}function u(e,t,r,i){var n=e.find(t,r,i),a=d(e,r);return T(n,"DS: Handle Adapter#find of "+r+" with id: "+i).then(function(e){return e=a.extract(t,r,e,i,"find"),t.push(r,e)},function(e){var n=t.getById(r,i);throw n.notFound(),e},"DS: Extract payload of '"+r+"'")}function l(e,t,r,i,n){var a=e.findMany(t,r,i,n),o=d(e,r);return T(a,"DS: Handle Adapter#findMany of "+r).then(function(e){e=o.extract(t,r,e,null,"findMany"),t.pushMany(r,e)},null,"DS: Extract payload of "+r)}function h(e,t,r,i,n){var a=e.findHasMany(t,r,i,n),o=d(e,n.type);return T(a,"DS: Handle Adapter#findHasMany of "+r+" : "+n.type).then(function(e){e=o.extract(t,n.type,e,null,"findHasMany");var i=t.pushMany(n.type,e);r.updateHasMany(n.key,i)},null,"DS: Extract payload of "+r+" : hasMany "+n.type)}function f(e,t,r,i,n){var a=e.findBelongsTo(t,r,i,n),o=d(e,n.type);return T(a,"DS: Handle Adapter#findBelongsTo of "+r+" : "+n.type).then(function(e){e=o.extract(t,n.type,e,null,"findBelongsTo");var r=t.push(n.type,e);return r.updateBelongsTo(n.key,r),r},null,"DS: Extract payload of "+r+" : "+n.type)}function p(e,t,r,i){var n=e.findAll(t,r,i),a=d(e,r);return T(n,"DS: Handle Adapter#findAll of "+r).then(function(e){return e=a.extract(t,r,e,null,"findAll"),t.pushMany(r,e),t.didUpdateAll(r),t.all(r)},null,"DS: Extract payload of findAll "+r)}function m(e,t,r,i,n){var a=e.findQuery(t,r,i,n),o=d(e,r);return T(a,"DS: Handle Adapter#findQuery of "+r).then(function(e){return e=o.extract(t,r,e,null,"findAll"),n.load(e),n},null,"DS: Extract payload of findQuery "+r)}function y(e,t,r,i){var n=i.constructor,a=e[r](t,n,i),o=d(e,n);return a.then(function(e){return e&&(e=o.extract(t,n,e,g(i,"id"),r)),t.didSaveRecord(i,e),i},function(e){throw e instanceof DS.InvalidError?t.recordWasInvalid(i,e.errors):t.recordWasError(i,e),e},"DS: Extract and notify about "+r+" completion of "+i)}var g=Ember.get,b=Ember.set,v=Ember.run.once,R=Ember.isNone,E=Ember.EnumerableUtils.forEach,S=Ember.EnumerableUtils.indexOf,D=Ember.EnumerableUtils.map,T=Ember.RSVP.resolve,A=Ember.copy,F=function(e){return null==e?null:e+""};DS.Store=Ember.Object.extend({init:function(){this.typeMaps={},this.recordArrayManager=DS.RecordArrayManager.create({store:this}),this._relationshipChanges={},this._pendingSave=[]},adapter:"_rest",serialize:function(e,t){return this.serializerFor(e.constructor.typeKey).serialize(e,t)},defaultAdapter:Ember.computed("adapter",function(){var e=g(this,"adapter");return"string"==typeof e&&(e=this.container.lookup("adapter:"+e)||this.container.lookup("adapter:application")||this.container.lookup("adapter:_rest")),DS.Adapter.detect(e)&&(e=e.create({container:this.container})),e}),createRecord:function(e,t){e=this.modelFor(e),t=A(t)||{},R(t.id)&&(t.id=this._generateId(e)),t.id=F(t.id);var r=this.buildRecord(e,t.id);return r.loadedData(),r.setProperties(t),r},_generateId:function(e){var t=this.adapterFor(e);return t&&t.generateIdForRecord?t.generateIdForRecord(this):null},deleteRecord:function(e){e.deleteRecord()},unloadRecord:function(e){e.unloadRecord()},find:function(e,t){return void 0===t?this.findAll(e):"object"===Ember.typeOf(t)?this.findQuery(e,t):this.findById(e,F(t))},findById:function(e,t){e=this.modelFor(e);var r=this.recordForId(e,t),i=this.fetchRecord(r)||T(r,"DS: Store#findById "+e+" with id: "+t);return a(i)},findByIds:function(e,t){var r=this;return o(Ember.RSVP.all(D(t,function(t){return r.findById(e,t)})).then(Ember.A,null,"DS: Store#findByIds of "+e+" complete"))},fetchRecord:function(e){if(R(e))return null;if(e._loadingPromise)return e._loadingPromise;if(!g(e,"isEmpty"))return null;var t=e.constructor,r=g(e,"id"),i=Ember.RSVP.defer("DS: Store#fetchRecord "+e);e.loadingData(i.promise);var n=this.adapterFor(t);return i.resolve(u(n,this,t,r)),i.promise},getById:function(e,t){return this.hasRecordForId(e,t)?this.recordForId(e,t):null},reloadRecord:function(e){var t=e.constructor,r=this.adapterFor(t),i=g(e,"id");return u(r,this,t,i)},fetchMany:function(e,t,r){if(e.length){var i=Ember.MapWithDefault.create({defaultValue:function(){return Ember.A()}});E(e,function(e){i.get(e.constructor).push(e)}),E(i,function(e,i){var n=i.mapProperty("id"),a=this.adapterFor(e);r.resolve(l(a,this,e,n,t))},this)}},hasRecordForId:function(e,t){return t=F(t),e=this.modelFor(e),!!this.typeMapFor(e).idToRecord[t]},recordForId:function(e,t){e=this.modelFor(e),t=F(t);var r=this.typeMapFor(e).idToRecord[t];return r||(r=this.buildRecord(e,t)),r},findMany:function(e,t,r,i){r=this.modelFor(r),t=Ember.A(t);var n=t.filterProperty("isEmpty",!0),a=this.recordArrayManager.createManyArray(r,t);return E(n,function(e){e.loadingData()}),a.loadingRecordsCount=n.length,n.length?(E(n,function(e){this.recordArrayManager.registerWaitingRecordArray(e,a)},this),this.fetchMany(n,e,i)):(i&&i.resolve(),a.set("isLoaded",!0),Ember.run.once(a,"trigger","didLoad")),a},findHasMany:function(e,t,r,i){var n=this.adapterFor(e.constructor),a=this.recordArrayManager.createManyArray(r.type,Ember.A([]));return i.resolve(h(n,this,e,t,r)),a},findBelongsTo:function(e,t,r,i){var n=this.adapterFor(e.constructor);i.resolve(f(n,this,e,t,r))},findQuery:function(e,t){e=this.modelFor(e);var r=DS.AdapterPopulatedRecordArray.create({type:e,query:t,content:Ember.A(),store:this}),i=this.adapterFor(e),n="DS: Store#findQuery "+e,a=Ember.RSVP.defer(n);return a.resolve(m(i,this,e,t,r)),o(a.promise)},findAll:function(e){return e=this.modelFor(e),this.fetchAll(e,this.all(e))},fetchAll:function(e,t){var r=this.adapterFor(e),i=this.typeMapFor(e).metadata.since,n=Ember.RSVP.defer("DS: Store#findAll "+e);return b(t,"isUpdating",!0),n.resolve(p(r,this,e,i)),o(n.promise)},didUpdateAll:function(e){var t=this.typeMapFor(e).findAllCache;b(t,"isUpdating",!1)},all:function(e){e=this.modelFor(e);var t=this.typeMapFor(e),r=t.findAllCache;if(r)return r;var i=DS.RecordArray.create({type:e,content:Ember.A(),store:this,isLoaded:!0});return this.recordArrayManager.registerFilteredRecordArray(i,e),t.findAllCache=i,i},unloadAll:function(e){e=this.modelFor(e);for(var t,r=this.typeMapFor(e),i=r.records;t=i.pop();)t.unloadRecord();r.findAllCache=null},filter:function(e,t,r){var i;3===arguments.length?i=this.findQuery(e,t):2===arguments.length&&(r=t),e=this.modelFor(e);var n=DS.FilteredRecordArray.create({type:e,content:Ember.A(),store:this,manager:this.recordArrayManager,filterFunction:r});return this.recordArrayManager.registerFilteredRecordArray(n,e,r),i?i.then(function(){return n},null,"DS: Store#filter of "+e):n},recordIsLoaded:function(e,t){return this.hasRecordForId(e,t)?!g(this.recordForId(e,t),"isEmpty"):!1},metadataFor:function(e){return e=this.modelFor(e),this.typeMapFor(e).metadata},dataWasUpdated:function(e,t){this.recordArrayManager.recordDidChange(t)},scheduleSave:function(e,t){e.adapterWillCommit(),this._pendingSave.push([e,t]),v(this,"flushPendingSave")},flushPendingSave:function(){var e=this._pendingSave.slice();this._pendingSave=[],E(e,function(e){var t,r=e[0],i=e[1],n=this.adapterFor(r.constructor);t=g(r,"isNew")?"createRecord":g(r,"isDeleted")?"deleteRecord":"updateRecord",i.resolve(y(n,this,t,r))},this)},didSaveRecord:function(t,r){r&&(r=e(this,t.constructor,r,t),this.updateId(t,r)),t.adapterDidCommit(r)},recordWasInvalid:function(e,t){e.adapterDidInvalidate(t)},recordWasError:function(e){e.adapterDidError()},updateId:function(e,t){var r=(g(e,"id"),F(t.id));this.typeMapFor(e.constructor).idToRecord[r]=e,b(e,"id",r)},typeMapFor:function(e){var t,r=g(this,"typeMaps"),i=Ember.guidFor(e);return(t=r[i])?t:(t={idToRecord:{},records:[],metadata:{}},r[i]=t,t)},_load:function(e,t,r){var i=F(t.id),n=this.recordForId(e,i);return n.setupData(t,r),this.recordArrayManager.recordDidChange(n),n},modelFor:function(e){var t;if("string"==typeof e){if(t=this.container.lookupFactory("model:"+e),!t)throw new Ember.Error("No model was found for '"+e+"'");t.typeKey=e}else t=e;return t.store=this,t},push:function(t,r,i){return t=this.modelFor(t),r=e(this,t,r),this._load(t,r,i),this.recordForId(t,r.id)},pushPayload:function(e,t){var r;t?r=this.serializerFor(e):(t=e,r=c(this.container)),r.pushPayload(this,t)},update:function(e,t){return this.push(e,t,!0)},pushMany:function(e,t){return D(t,function(t){return this.push(e,t)},this)},metaForType:function(e,t){e=this.modelFor(e),Ember.merge(this.typeMapFor(e).metadata,t)},buildRecord:function(e,t,r){var i=this.typeMapFor(e),n=i.idToRecord,a=e._create({id:t,store:this,container:this.container});return r&&a.setupData(r),t&&(n[t]=a),i.records.push(a),a},dematerializeRecord:function(e){var t=e.constructor,r=this.typeMapFor(t),i=g(e,"id");e.updateRecordArrays(),i&&delete r.idToRecord[i];var n=S(r.records,e);r.records.splice(n,1)},addRelationshipChangeFor:function(e,t,r,i,n){var a=e.clientId,o=r?r:r,s=t+i,c=this._relationshipChanges;a in c||(c[a]={}),o in c[a]||(c[a][o]={}),s in c[a][o]||(c[a][o][s]={}),c[a][o][s][n.changeType]=n},removeRelationshipChangeFor:function(e,t,r,i,n){var a=e.clientId,o=r?r.clientId:r,s=this._relationshipChanges,c=t+i;a in s&&o in s[a]&&c in s[a][o]&&delete s[a][o][c][n]},relationshipChangePairsFor:function(e){var t=[];if(!e)return t;var r=this._relationshipChanges[e.clientId];for(var i in r)if(r.hasOwnProperty(i))for(var n in r[i])r[i].hasOwnProperty(n)&&t.push(r[i][n]);return t},adapterFor:function(e){var t,r=this.container;return r&&(t=r.lookup("adapter:"+e.typeKey)||r.lookup("adapter:application")),t||g(this,"defaultAdapter")},serializerFor:function(e){e=this.modelFor(e);var t=this.adapterFor(e);return s(this.container,e.typeKey,t&&t.defaultSerializer)}}),DS.PromiseArray=Ember.ArrayProxy.extend(Ember.PromiseProxyMixin),DS.PromiseObject=Ember.ObjectProxy.extend(Ember.PromiseProxyMixin)}(),function(){function e(t){var r,i={};for(var n in t)r=t[n],i[n]=r&&"object"==typeof r?e(r):r;return i}function t(e,t){for(var r in t)e[r]=t[r];return e}function r(r){var i=e(c);return t(i,r)}function i(e,r,n){e=t(r?Ember.create(r):{},e),e.parentState=r,e.stateName=n;for(var a in e)e.hasOwnProperty(a)&&"parentState"!==a&&"stateName"!==a&&"object"==typeof e[a]&&(e[a]=i(e[a],e,n+"."+a));return e}var n=Ember.get,a=Ember.set,o=function(e){var t,r,i,n=Ember.keys(e);for(t=0,r=n.length;r>t;t++)if(i=n[t],e.hasOwnProperty(i)&&e[i])return!0;return!1},s=function(e,t){t.value===t.originalValue?(delete e._attributes[t.name],e.send("propertyWasReset",t.name)):t.value!==t.oldValue&&e.send("becomeDirty"),e.updateRecordArraysLater()},c={initialState:"uncommitted",isDirty:!0,uncommitted:{didSetProperty:s,propertyWasReset:function(e){var t=!1;for(var r in e._attributes){t=!0;break}t||e.send("rolledBack")},pushedData:Ember.K,becomeDirty:Ember.K,willCommit:function(e){e.transitionTo("inFlight")},reloadRecord:function(e,t){t(n(e,"store").reloadRecord(e))},rolledBack:function(e){e.transitionTo("loaded.saved")},becameInvalid:function(e){e.transitionTo("invalid")},rollback:function(e){e.rollback()}},inFlight:{isSaving:!0,didSetProperty:s,becomeDirty:Ember.K,pushedData:Ember.K,willCommit:Ember.K,didCommit:function(e){var t=n(this,"dirtyType");e.transitionTo("saved"),e.send("invokeLifecycleCallbacks",t)},becameInvalid:function(e,t){a(e,"errors",t),e.transitionTo("invalid"),e.send("invokeLifecycleCallbacks")},becameError:function(e){e.transitionTo("uncommitted"),e.triggerLater("becameError",e)}},invalid:{isValid:!1,deleteRecord:function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()},didSetProperty:function(e,t){var r=n(e,"errors"),i=t.name;a(r,i,null),o(r)||e.send("becameValid"),s(e,t)},becomeDirty:Ember.K,rollback:function(e){e.send("becameValid"),e.send("rollback")},becameValid:function(e){e.transitionTo("uncommitted")},invokeLifecycleCallbacks:function(e){e.triggerLater("becameInvalid",e)}}},d=r({dirtyType:"created",isNew:!0});d.uncommitted.rolledBack=function(e){e.transitionTo("deleted.saved")};var u=r({dirtyType:"updated"});d.uncommitted.deleteRecord=function(e){e.clearRelationships(),e.transitionTo("deleted.saved")},d.uncommitted.rollback=function(e){c.uncommitted.rollback.apply(this,arguments),e.transitionTo("deleted.saved")},u.uncommitted.deleteRecord=function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()};var l={isEmpty:!1,isLoading:!1,isLoaded:!1,isDirty:!1,isSaving:!1,isDeleted:!1,isNew:!1,isValid:!0,rolledBack:Ember.K,propertyWasReset:Ember.K,empty:{isEmpty:!0,loadingData:function(e,t){e._loadingPromise=t,e.transitionTo("loading")},loadedData:function(e){e.transitionTo("loaded.created.uncommitted"),e.suspendRelationshipObservers(function(){e.notifyPropertyChange("data")})},pushedData:function(e){e.transitionTo("loaded.saved"),e.triggerLater("didLoad")}},loading:{isLoading:!0,exit:function(e){e._loadingPromise=null},pushedData:function(e){e.transitionTo("loaded.saved"),e.triggerLater("didLoad"),a(e,"isError",!1)},becameError:function(e){e.triggerLater("becameError",e)},notFound:function(e){e.transitionTo("empty")}},loaded:{initialState:"saved",isLoaded:!0,saved:{setup:function(e){var t=e._attributes,r=!1;for(var i in t)if(t.hasOwnProperty(i)){r=!0;break}r&&e.adapterDidDirty()},didSetProperty:s,pushedData:Ember.K,becomeDirty:function(e){e.transitionTo("updated.uncommitted")},willCommit:function(e){e.transitionTo("updated.inFlight")},reloadRecord:function(e,t){t(n(e,"store").reloadRecord(e))},deleteRecord:function(e){e.transitionTo("deleted.uncommitted"),e.clearRelationships()},unloadRecord:function(e){e.clearRelationships(),e.transitionTo("deleted.saved")},didCommit:function(e){e.send("invokeLifecycleCallbacks",n(e,"lastDirtyType"))},notFound:Ember.K},created:d,updated:u},deleted:{initialState:"uncommitted",dirtyType:"deleted",isDeleted:!0,isLoaded:!0,isDirty:!0,setup:function(e){e.updateRecordArrays()},uncommitted:{willCommit:function(e){e.transitionTo("inFlight")},rollback:function(e){e.rollback()},becomeDirty:Ember.K,deleteRecord:Ember.K,rolledBack:function(e){e.transitionTo("loaded.saved")}},inFlight:{isSaving:!0,willCommit:Ember.K,didCommit:function(e){e.transitionTo("saved"),e.send("invokeLifecycleCallbacks")},becameError:function(e){e.transitionTo("uncommitted"),e.triggerLater("becameError",e)}},saved:{isDirty:!1,setup:function(e){var t=n(e,"store");t.dematerializeRecord(e)},invokeLifecycleCallbacks:function(e){e.triggerLater("didDelete",e),e.triggerLater("didCommit",e)}}},invokeLifecycleCallbacks:function(e,t){"created"===t?e.triggerLater("didCreate",e):e.triggerLater("didUpdate",e),e.triggerLater("didCommit",e)}};l=i(l,null,"root"),DS.RootState=l}(),function(){var e=Ember.get,t=Ember.set,r=Ember.merge,i=Ember.run.once,n=Ember.computed("currentState",function(t){return e(e(this,"currentState"),t)}).readOnly();DS.Model=Ember.Object.extend(Ember.Evented,{isEmpty:n,isLoading:n,isLoaded:n,isDirty:n,isSaving:n,isDeleted:n,isNew:n,isValid:n,dirtyType:n,isError:!1,isReloading:!1,clientId:null,id:null,transaction:null,currentState:null,errors:null,serialize:function(t){var r=e(this,"store");return r.serialize(this,t)},toJSON:function(e){var t=DS.JSONSerializer.create({container:this.container});return t.serialize(this,e)},didLoad:Ember.K,didUpdate:Ember.K,didCreate:Ember.K,didDelete:Ember.K,becameInvalid:Ember.K,becameError:Ember.K,data:Ember.computed(function(){return this._data=this._data||{},this._data}).property(),_data:null,init:function(){t(this,"currentState",DS.RootState.empty),this._super(),this._setup()},_setup:function(){this._changesToSync={},this._deferredTriggers=[],this._data={},this._attributes={},this._inFlightAttributes={},this._relationships={}},send:function(t,r){var i=e(this,"currentState");return i[t]||this._unhandledEvent(i,t,r),i[t](this,r)},transitionTo:function(r){var i=r.split(".",1),n=e(this,"currentState"),a=n;do a.exit&&a.exit(this),a=a.parentState;while(!a.hasOwnProperty(i));var o,s,c=r.split("."),d=[],u=[];for(o=0,s=c.length;s>o;o++)a=a[c[o]],a.enter&&u.push(a),a.setup&&d.push(a);for(o=0,s=u.length;s>o;o++)u[o].enter(this);for(t(this,"currentState",a),o=0,s=d.length;s>o;o++)d[o].setup(this);this.updateRecordArraysLater()},_unhandledEvent:function(e,t,r){var i="Attempted to handle event `"+t+"` ";throw i+="on "+String(this)+" while in state ",i+=e.stateName+". ",void 0!==r&&(i+="Called with "+Ember.inspect(r)+"."),new Ember.Error(i)},withTransaction:function(t){var r=e(this,"transaction");r&&t(r)},loadingData:function(e){this.send("loadingData",e)},loadedData:function(){this.send("loadedData")},notFound:function(){this.send("notFound")},pushedData:function(){this.send("pushedData")},deleteRecord:function(){this.send("deleteRecord")},destroyRecord:function(){return this.deleteRecord(),this.save()},unloadRecord:function(){this.send("unloadRecord")},clearRelationships:function(){this.eachRelationship(function(e,r){if("belongsTo"===r.kind)t(this,e,null);else if("hasMany"===r.kind){var i=this._relationships[r.name];i&&i.clear()}},this)},updateRecordArrays:function(){e(this,"store").dataWasUpdated(this.constructor,this)},changedAttributes:function(){var t,r=e(this,"_data"),i=e(this,"_attributes"),n={};for(t in i)n[t]=[r[t],i[t]];return n},adapterWillCommit:function(){this.send("willCommit")},adapterDidCommit:function(e){t(this,"isError",!1),e?this._data=e:Ember.mixin(this._data,this._inFlightAttributes),this._inFlightAttributes={},this.send("didCommit"),this.updateRecordArraysLater(),e&&this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},adapterDidDirty:function(){this.send("becomeDirty"),this.updateRecordArraysLater()},dataDidChange:Ember.observer(function(){this.reloadHasManys()},"data"),reloadHasManys:function(){var t=e(this.constructor,"relationshipsByName");this.updateRecordArraysLater(),t.forEach(function(e,t){this._data.links&&this._data.links[e]||"hasMany"===t.kind&&this.hasManyDidChange(t.key)},this)},hasManyDidChange:function(e){var r=this._relationships[e];if(r){var i=this._data[e]||[];t(r,"content",Ember.A(i)),t(r,"isLoaded",!0),r.trigger("didLoad")}},updateRecordArraysLater:function(){Ember.run.once(this,this.updateRecordArrays)},setupData:function(e,t){t?Ember.merge(this._data,e):this._data=e;var r=this._relationships;this.eachRelationship(function(t,i){e.links&&e.links[t]||i.options.async&&(r[t]=null)}),e&&this.pushedData(),this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},materializeId:function(e){t(this,"id",e)},materializeAttributes:function(e){r(this._data,e)},materializeAttribute:function(e,t){this._data[e]=t},updateHasMany:function(e,t){this._data[e]=t,this.hasManyDidChange(e)},updateBelongsTo:function(e,t){this._data[e]=t},rollback:function(){this._attributes={},e(this,"isError")&&(this._inFlightAttributes={},t(this,"isError",!1)),e(this,"isValid")||(this._inFlightAttributes={},this.send("becameValid")),this.send("rolledBack"),this.suspendRelationshipObservers(function(){this.notifyPropertyChange("data")})},toStringExtension:function(){return e(this,"id")},suspendRelationshipObservers:function(t,r){var i=e(this.constructor,"relationshipNames").belongsTo,n=this;try{this._suspendedRelationships=!0,Ember._suspendObservers(n,i,null,"belongsToDidChange",function(){Ember._suspendBeforeObservers(n,i,null,"belongsToWillChange",function(){t.call(r||n)})})}finally{this._suspendedRelationships=!1}},save:function(){var e="DS: Model#save "+this,t=Ember.RSVP.defer(e);return this.get("store").scheduleSave(this,t),this._inFlightAttributes=this._attributes,this._attributes={},DS.PromiseObject.create({promise:t.promise})},reload:function(){t(this,"isReloading",!0);var e=this,r="DS: Model#reload of "+this,i=new Ember.RSVP.Promise(function(t){e.send("reloadRecord",t)},r).then(function(){return e.set("isReloading",!1),e.set("isError",!1),e},function(t){throw e.set("isError",!0),t},"DS: Model#reload complete, update flags");return DS.PromiseObject.create({promise:i})},adapterDidUpdateAttribute:function(e,t){void 0!==t?(this._data[e]=t,this.notifyPropertyChange(e)):this._data[e]=this._inFlightAttributes[e],this.updateRecordArraysLater()},adapterDidInvalidate:function(e){this.send("becameInvalid",e)},adapterDidError:function(){this.send("becameError"),t(this,"isError",!0)},trigger:function(e){Ember.tryInvoke(this,e,[].slice.call(arguments,1)),this._super.apply(this,arguments)},triggerLater:function(){this._deferredTriggers.push(arguments),i(this,"_triggerDeferredTriggers")},_triggerDeferredTriggers:function(){for(var e=0,t=this._deferredTriggers.length;t>e;e++)this.trigger.apply(this,this._deferredTriggers[e]);this._deferredTriggers=[]}}),DS.Model.reopenClass({_create:DS.Model.create,create:function(){throw new Ember.Error("You should not call `create` on a model. Instead, call `store.createRecord` with the attributes you would like to set.")}})}(),function(){function e(e,t){return"function"==typeof t.defaultValue?t.defaultValue():t.defaultValue}function t(e,t){return e._attributes.hasOwnProperty(t)||e._inFlightAttributes.hasOwnProperty(t)||e._data.hasOwnProperty(t)}function r(e,t){return e._attributes.hasOwnProperty(t)?e._attributes[t]:e._inFlightAttributes.hasOwnProperty(t)?e._inFlightAttributes[t]:e._data[t]}var i=Ember.get;DS.Model.reopenClass({attributes:Ember.computed(function(){var e=Ember.Map.create();return this.eachComputedProperty(function(t,r){r.isAttribute&&(r.name=t,e.set(t,r))}),e}),transformedAttributes:Ember.computed(function(){var e=Ember.Map.create();return this.eachAttribute(function(t,r){r.type&&e.set(t,r.type)}),e}),eachAttribute:function(e,t){i(this,"attributes").forEach(function(r,i){e.call(t,r,i) +},t)},eachTransformedAttribute:function(e,t){i(this,"transformedAttributes").forEach(function(r,i){e.call(t,r,i)})}}),DS.Model.reopen({eachAttribute:function(e,t){this.constructor.eachAttribute(e,t)}}),DS.attr=function(i,n){n=n||{};var a={type:i,isAttribute:!0,options:n};return Ember.computed(function(i,a){if(arguments.length>1){var o=this._attributes[i]||this._inFlightAttributes[i]||this._data[i];return this.send("didSetProperty",{name:i,oldValue:o,originalValue:this._data[i],value:a}),this._attributes[i]=a,a}return t(this,i)?r(this,i):e(this,n,i)}).property("data").meta(a)}}(),function(){var e=DS.AttributeChange=function(e){this.record=e.record,this.store=e.store,this.name=e.name,this.value=e.value,this.oldValue=e.oldValue};e.createChange=function(t){return new e(t)},e.prototype={sync:function(){this.value!==this.oldValue&&(this.record.send("becomeDirty"),this.record.updateRecordArraysLater()),this.destroy()},destroy:function(){delete this.record._changesToSync[this.name]}}}(),function(){function e(e){return"object"==typeof e&&(!e.then||"function"!=typeof e.then)}var t=Ember.get,r=Ember.set,i=Ember.EnumerableUtils.forEach;DS.RelationshipChange=function(e){this.parentRecord=e.parentRecord,this.childRecord=e.childRecord,this.firstRecord=e.firstRecord,this.firstRecordKind=e.firstRecordKind,this.firstRecordName=e.firstRecordName,this.secondRecord=e.secondRecord,this.secondRecordKind=e.secondRecordKind,this.secondRecordName=e.secondRecordName,this.changeType=e.changeType,this.store=e.store,this.committed={}},DS.RelationshipChangeAdd=function(e){DS.RelationshipChange.call(this,e)},DS.RelationshipChangeRemove=function(e){DS.RelationshipChange.call(this,e)},DS.RelationshipChange.create=function(e){return new DS.RelationshipChange(e)},DS.RelationshipChangeAdd.create=function(e){return new DS.RelationshipChangeAdd(e)},DS.RelationshipChangeRemove.create=function(e){return new DS.RelationshipChangeRemove(e)},DS.OneToManyChange={},DS.OneToNoneChange={},DS.ManyToNoneChange={},DS.OneToOneChange={},DS.ManyToManyChange={},DS.RelationshipChange._createChange=function(e){return"add"===e.changeType?DS.RelationshipChangeAdd.create(e):"remove"===e.changeType?DS.RelationshipChangeRemove.create(e):void 0},DS.RelationshipChange.determineRelationshipType=function(e,t){var r,i,n=t.key,a=t.kind,o=e.inverseFor(n);return o&&(r=o.name,i=o.kind),o?"belongsTo"===i?"belongsTo"===a?"oneToOne":"manyToOne":"belongsTo"===a?"oneToMany":"manyToMany":"belongsTo"===a?"oneToNone":"manyToNone"},DS.RelationshipChange.createChange=function(e,t,r,i){var n,a=e.constructor;return n=DS.RelationshipChange.determineRelationshipType(a,i),"oneToMany"===n?DS.OneToManyChange.createChange(e,t,r,i):"manyToOne"===n?DS.OneToManyChange.createChange(t,e,r,i):"oneToNone"===n?DS.OneToNoneChange.createChange(e,t,r,i):"manyToNone"===n?DS.ManyToNoneChange.createChange(e,t,r,i):"oneToOne"===n?DS.OneToOneChange.createChange(e,t,r,i):"manyToMany"===n?DS.ManyToManyChange.createChange(e,t,r,i):void 0},DS.OneToNoneChange.createChange=function(e,t,r,i){var n=i.key,a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,store:r,changeType:i.changeType,firstRecordName:n,firstRecordKind:"belongsTo"});return r.addRelationshipChangeFor(e,n,t,null,a),a},DS.ManyToNoneChange.createChange=function(e,t,r,i){var n=i.key,a=DS.RelationshipChange._createChange({parentRecord:e,childRecord:t,secondRecord:e,store:r,changeType:i.changeType,secondRecordName:i.key,secondRecordKind:"hasMany"});return r.addRelationshipChangeFor(e,n,t,null,a),a},DS.ManyToManyChange.createChange=function(e,t,r,i){var n=i.key,a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"hasMany",secondRecordKind:"hasMany",store:r,changeType:i.changeType,firstRecordName:n});return r.addRelationshipChangeFor(e,n,t,null,a),a},DS.OneToOneChange.createChange=function(e,t,r,i){var n;i.parentType?n=i.parentType.inverseFor(i.key).name:i.key&&(n=i.key);var a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"belongsTo",secondRecordKind:"belongsTo",store:r,changeType:i.changeType,firstRecordName:n});return r.addRelationshipChangeFor(e,n,t,null,a),a},DS.OneToOneChange.maintainInvariant=function(e,r,i,n){if("add"===e.changeType&&r.recordIsMaterialized(i)){var a=t(i,n);if(a){var o=DS.OneToOneChange.createChange(i,a,r,{parentType:e.parentType,hasManyName:e.hasManyName,changeType:"remove",key:e.key});r.addRelationshipChangeFor(i,n,e.parentRecord,null,o),o.sync()}}},DS.OneToManyChange.createChange=function(e,t,r,i){var n;i.parentType?(n=i.parentType.inverseFor(i.key).name,DS.OneToManyChange.maintainInvariant(i,r,e,n)):i.key&&(n=i.key);var a=DS.RelationshipChange._createChange({parentRecord:t,childRecord:e,firstRecord:e,secondRecord:t,firstRecordKind:"belongsTo",secondRecordKind:"hasMany",store:r,changeType:i.changeType,firstRecordName:n});return r.addRelationshipChangeFor(e,n,t,a.getSecondRecordName(),a),a},DS.OneToManyChange.maintainInvariant=function(e,r,i,n){if("add"===e.changeType&&i){var a=t(i,n);if(a){var o=DS.OneToManyChange.createChange(i,a,r,{parentType:e.parentType,hasManyName:e.hasManyName,changeType:"remove",key:e.key});r.addRelationshipChangeFor(i,n,e.parentRecord,o.getSecondRecordName(),o),o.sync()}}},DS.RelationshipChange.prototype={getSecondRecordName:function(){var e,t=this.secondRecordName;if(!t){if(e=this.secondRecord,!e)return;var r=this.firstRecord.constructor,i=r.inverseFor(this.firstRecordName);this.secondRecordName=i.name}return this.secondRecordName},getFirstRecordName:function(){var e=this.firstRecordName;return e},destroy:function(){var e=this.childRecord,t=this.getFirstRecordName(),r=this.getSecondRecordName(),i=this.store;i.removeRelationshipChangeFor(e,t,this.parentRecord,r,this.changeType)},getSecondRecord:function(){return this.secondRecord},getFirstRecord:function(){return this.firstRecord},coalesce:function(){var e=this.store.relationshipChangePairsFor(this.firstRecord);i(e,function(e){var t=e.add,r=e.remove;t&&r&&(t.destroy(),r.destroy())})}},DS.RelationshipChangeAdd.prototype=Ember.create(DS.RelationshipChange.create({})),DS.RelationshipChangeRemove.prototype=Ember.create(DS.RelationshipChange.create({})),DS.RelationshipChangeAdd.prototype.changeType="add",DS.RelationshipChangeAdd.prototype.sync=function(){var i=this.getSecondRecordName(),n=this.getFirstRecordName(),a=this.getFirstRecord(),o=this.getSecondRecord();o instanceof DS.Model&&a instanceof DS.Model&&("belongsTo"===this.secondRecordKind?o.suspendRelationshipObservers(function(){r(o,i,a)}):"hasMany"===this.secondRecordKind&&o.suspendRelationshipObservers(function(){var r=t(o,i);e(r)&&r.addObject(a)})),a instanceof DS.Model&&o instanceof DS.Model&&t(a,n)!==o&&("belongsTo"===this.firstRecordKind?a.suspendRelationshipObservers(function(){r(a,n,o)}):"hasMany"===this.firstRecordKind&&a.suspendRelationshipObservers(function(){var r=t(a,n);e(r)&&r.addObject(o)})),this.coalesce()},DS.RelationshipChangeRemove.prototype.changeType="remove",DS.RelationshipChangeRemove.prototype.sync=function(){var i=this.getSecondRecordName(),n=this.getFirstRecordName(),a=this.getFirstRecord(),o=this.getSecondRecord();o instanceof DS.Model&&a instanceof DS.Model&&("belongsTo"===this.secondRecordKind?o.suspendRelationshipObservers(function(){r(o,i,null)}):"hasMany"===this.secondRecordKind&&o.suspendRelationshipObservers(function(){var r=t(o,i);e(r)&&r.removeObject(a)})),a instanceof DS.Model&&t(a,n)&&("belongsTo"===this.firstRecordKind?a.suspendRelationshipObservers(function(){r(a,n,null)}):"hasMany"===this.firstRecordKind&&a.suspendRelationshipObservers(function(){var r=t(a,n);e(r)&&r.removeObject(o)})),this.coalesce()}}(),function(){function e(e,i,n){return Ember.computed(function(e,i){var a=t(this,"data"),o=t(this,"store"),s="DS: Async belongsTo "+this+" : "+e;if(2===arguments.length)return void 0===i?null:DS.PromiseObject.create({promise:Ember.RSVP.resolve(i,s)});var c=a.links&&a.links[e],d=a[e];if(r(d)){if(c){var u=Ember.RSVP.defer("DS: Async belongsTo (link) "+this+" : "+e);return o.findBelongsTo(this,c,n,u),DS.PromiseObject.create({promise:u.promise})}return null}var l=o.fetchRecord(d)||Ember.RSVP.resolve(d,s);return DS.PromiseObject.create({promise:l})}).property("data").meta(n)}var t=Ember.get,r=(Ember.set,Ember.isNone);DS.belongsTo=function(i,n){"object"==typeof i&&(n=i,i=void 0),n=n||{};var a={type:i,isRelationship:!0,options:n,kind:"belongsTo"};return n.async?e(i,n,a):Ember.computed(function(e,n){var a,o,s=t(this,"data"),c=t(this,"store");return o="string"==typeof i?c.modelFor(i):i,2===arguments.length?void 0===n?null:n:(a=s[e],r(a)?null:(c.fetchRecord(a),a))}).property("data").meta(a)},DS.Model.reopen({belongsToWillChange:Ember.beforeObserver(function(e,r){if(t(e,"isLoaded")){var i=t(e,r);if(i){var n=t(e,"store"),a=DS.RelationshipChange.createChange(e,i,n,{key:r,kind:"belongsTo",changeType:"remove"});a.sync(),this._changesToSync[r]=a}}}),belongsToDidChange:Ember.immediateObserver(function(e,r){if(t(e,"isLoaded")){var i=t(e,r);if(i){var n=t(e,"store"),a=DS.RelationshipChange.createChange(e,i,n,{key:r,kind:"belongsTo",changeType:"add"});a.sync()}}delete this._changesToSync[r]})})}(),function(){function e(e,r,i){return Ember.computed(function(e){var a=this._relationships[e],o="DS: Async hasMany "+this+" : "+e;if(!a){var s=Ember.RSVP.defer(o);a=t(this,e,r,function(t,r){var a,o=r.links&&r.links[e];return a=o?t.findHasMany(this,o,i,s):t.findMany(this,r[e],i.type,s),n(a,"promise",s.promise),a})}var c=a.get("promise").then(function(){return a},null,"DS: Async hasMany records received");return DS.PromiseArray.create({promise:c})}).property("data").meta(i)}function t(e,t,r,n){var o=e._relationships;if(o[t])return o[t];var s=i(e,"data"),c=i(e,"store"),d=o[t]=n.call(e,c,s);return a(d,{owner:e,name:t,isPolymorphic:r.polymorphic})}function r(r,i){i=i||{};var n={type:r,isRelationship:!0,options:i,kind:"hasMany"};return i.async?e(r,i,n):Ember.computed(function(e){return t(this,e,i,function(t,r){r[e];return t.findMany(this,r[e],n.type)})}).property("data").meta(n)}var i=Ember.get,n=Ember.set,a=Ember.setProperties;DS.hasMany=function(e,t){return"object"==typeof e&&(t=e,e=void 0),r(e,t)}}(),function(){{var e=Ember.get;Ember.set}DS.Model.reopen({didDefineProperty:function(e,t,r){if(r instanceof Ember.Descriptor){var i=r.meta();i.isRelationship&&"belongsTo"===i.kind&&(Ember.addObserver(e,t,null,"belongsToDidChange"),Ember.addBeforeObserver(e,t,null,"belongsToWillChange")),i.parentType=e.constructor}}}),DS.Model.reopenClass({typeForRelationship:function(t){var r=e(this,"relationshipsByName").get(t);return r&&r.type},inverseFor:function(t){function r(t,i,n){n=n||[];var a=e(i,"relationships");if(a){var o=a.get(t);return o&&n.push.apply(n,a.get(t)),t.superclass&&r(t.superclass,i,n),n}}var i=this.typeForRelationship(t);if(!i)return null;var n=this.metaForProperty(t).options;if(null===n.inverse)return null;var a,o;if(n.inverse)a=n.inverse,o=Ember.get(i,"relationshipsByName").get(a).kind;else{var s=r(this,i);if(0===s.length)return null;a=s[0].name,o=s[0].kind}return{type:i,name:a,kind:o}},relationships:Ember.computed(function(){var e=new Ember.MapWithDefault({defaultValue:function(){return[]}});return this.eachComputedProperty(function(t,r){if(r.isRelationship){"string"==typeof r.type&&(r.type=this.store.modelFor(r.type));var i=e.get(r.type);i.push({name:t,kind:r.kind})}}),e}),relationshipNames:Ember.computed(function(){var e={hasMany:[],belongsTo:[]};return this.eachComputedProperty(function(t,r){r.isRelationship&&e[r.kind].push(t)}),e}),relatedTypes:Ember.computed(function(){var t,r=Ember.A();return this.eachComputedProperty(function(i,n){n.isRelationship&&(t=n.type,"string"==typeof t&&(t=e(this,t,!1)||this.store.modelFor(t)),r.contains(t)||r.push(t))}),r}),relationshipsByName:Ember.computed(function(){var e,t=Ember.Map.create();return this.eachComputedProperty(function(r,i){i.isRelationship&&(i.key=r,e=i.type,e||"hasMany"!==i.kind?e||(e=r):e=Ember.String.singularize(r),"string"==typeof e&&(i.type=this.store.modelFor(e)),t.set(r,i))}),t}),fields:Ember.computed(function(){var e=Ember.Map.create();return this.eachComputedProperty(function(t,r){r.isRelationship?e.set(t,r.kind):r.isAttribute&&e.set(t,"attribute")}),e}),eachRelationship:function(t,r){e(this,"relationshipsByName").forEach(function(e,i){t.call(r,e,i)})},eachRelatedType:function(t,r){e(this,"relatedTypes").forEach(function(e){t.call(r,e)})}}),DS.Model.reopen({eachRelationship:function(e,t){this.constructor.eachRelationship(e,t)}})}(),function(){var e=Ember.get,t=(Ember.set,Ember.run.once),r=Ember.EnumerableUtils.forEach;DS.RecordArrayManager=Ember.Object.extend({init:function(){this.filteredRecordArrays=Ember.MapWithDefault.create({defaultValue:function(){return[]}}),this.changedRecords=[]},recordDidChange:function(e){this.changedRecords.push(e),t(this,this.updateRecordArrays)},recordArraysForRecord:function(e){return e._recordArrays=e._recordArrays||Ember.OrderedSet.create(),e._recordArrays},updateRecordArrays:function(){r(this.changedRecords,function(t){e(t,"isDeleted")?this._recordWasDeleted(t):this._recordWasChanged(t)},this),this.changedRecords=[]},_recordWasDeleted:function(e){var t=e._recordArrays;t&&r(t,function(t){t.removeRecord(e)})},_recordWasChanged:function(t){var i,n=t.constructor,a=this.filteredRecordArrays.get(n);r(a,function(r){i=e(r,"filterFunction"),this.updateRecordArray(r,i,n,t)},this);var o=t._loadingRecordArrays;if(o){for(var s=0,c=o.length;c>s;s++)o[s].loadedRecord();t._loadingRecordArrays=[]}},updateRecordArray:function(e,t,r,i){var n;n=t?t(i):!0;var a=this.recordArraysForRecord(i);n?(a.add(e),e.addRecord(i)):n||(a.remove(e),e.removeRecord(i))},updateFilter:function(t,r,i){for(var n,a=this.store.typeMapFor(r),o=a.records,s=0,c=o.length;c>s;s++)n=o[s],e(n,"isDeleted")||e(n,"isEmpty")||this.updateRecordArray(t,i,r,n)},createManyArray:function(e,t){var i=DS.ManyArray.create({type:e,content:t,store:this.store});return r(t,function(e){var t=this.recordArraysForRecord(e);t.add(i)},this),i},registerFilteredRecordArray:function(e,t,r){var i=this.filteredRecordArrays.get(t);i.push(e),this.updateFilter(e,t,r)},registerWaitingRecordArray:function(e,t){var r=e._loadingRecordArrays||[];r.push(t),e._loadingRecordArrays=r}})}(),function(){var e=Ember.get,t=(Ember.set,Ember.ArrayPolyfills.map),r=["description","fileName","lineNumber","message","name","number","stack"];DS.InvalidError=function(e){var t=Error.prototype.constructor.call(this,"The backend rejected the commit because it was invalid: "+Ember.inspect(e));this.errors=e;for(var i=0,n=r.length;n>i;i++)this[r[i]]=t[r[i]]},DS.InvalidError.prototype=Ember.create(Error.prototype),DS.Adapter=Ember.Object.extend({find:Ember.required(Function),findAll:null,findQuery:null,generateIdForRecord:null,serialize:function(t,r){return e(t,"store").serializerFor(t.constructor.typeKey).serialize(t,r)},createRecord:Ember.required(Function),updateRecord:Ember.required(Function),deleteRecord:Ember.required(Function),findMany:function(e,r,i){var n=t.call(i,function(t){return this.find(e,r,t)},this);return Ember.RSVP.all(n)}})}(),function(){var e=Ember.get,t=Ember.String.fmt,r=Ember.EnumerableUtils.indexOf,i=0;DS.FixtureAdapter=DS.Adapter.extend({serializer:null,simulateRemoteResponse:!0,latency:50,fixturesForType:function(e){if(e.FIXTURES){var r=Ember.A(e.FIXTURES);return r.map(function(e){var r=typeof e.id;if("number"!==r&&"string"!==r)throw new Error(t("the id property must be defined as a number or string for fixture %@",[e]));return e.id=e.id+"",e})}return null},queryFixtures:function(){},updateFixtures:function(e,t){e.FIXTURES||(e.FIXTURES=[]);var r=e.FIXTURES;this.deleteLoadedFixture(e,t),r.push(t)},mockJSON:function(e,t,r){return e.serializerFor(t).serialize(r,{includeId:!0})},generateIdForRecord:function(){return"fixture-"+i++},find:function(e,t,r){var i,n=this.fixturesForType(t);return n&&(i=Ember.A(n).findProperty("id",r)),i?this.simulateRemoteCall(function(){return i},this):void 0},findMany:function(e,t,i){var n=this.fixturesForType(t);return n&&(n=n.filter(function(e){return-1!==r(i,e.id)})),n?this.simulateRemoteCall(function(){return n},this):void 0},findAll:function(e,t){var r=this.fixturesForType(t);return this.simulateRemoteCall(function(){return r},this)},findQuery:function(e,t,r){var i=this.fixturesForType(t);return i=this.queryFixtures(i,r,t),i?this.simulateRemoteCall(function(){return i},this):void 0},createRecord:function(e,t,r){var i=this.mockJSON(e,t,r);return this.updateFixtures(t,i),this.simulateRemoteCall(function(){return i},this)},updateRecord:function(e,t,r){var i=this.mockJSON(e,t,r);return this.updateFixtures(t,i),this.simulateRemoteCall(function(){return i},this)},deleteRecord:function(e,t,r){var i=this.mockJSON(e,t,r);return this.deleteLoadedFixture(t,i),this.simulateRemoteCall(function(){return null})},deleteLoadedFixture:function(e,t){var i=this.findExistingFixture(e,t);if(i){var n=r(e.FIXTURES,i);return e.FIXTURES.splice(n,1),!0}},findExistingFixture:function(t,r){var i=this.fixturesForType(t),n=e(r,"id");return this.findFixtureById(i,n)},findFixtureById:function(t,r){return Ember.A(t).find(function(t){return""+e(t,"id")==""+r?!0:!1})},simulateRemoteCall:function(t,r){var i=this;return new Ember.RSVP.Promise(function(n){e(i,"simulateRemoteResponse")?Ember.run.later(function(){n(t.call(r))},e(i,"latency")):Ember.run.schedule("actions",null,function(){n(t.call(r))})},"DS: FixtureAdapter#simulateRemoteCall")}})}(),function(){function e(e){return null==e?null:e+""}var t=Ember.get,r=(Ember.set,Ember.ArrayPolyfills.forEach),i=Ember.ArrayPolyfills.map;DS.RESTSerializer=DS.JSONSerializer.extend({normalize:function(e,t,r){return this.normalizeId(t),this.normalizeUsingDeclaredMapping(e,t),this.normalizeAttributes(e,t),this.normalizeRelationships(e,t),this.normalizeHash&&this.normalizeHash[r]&&this.normalizeHash[r](t),this._super(e,t,r)},normalizePayload:function(e,t){return t},normalizeId:function(e){var r=t(this,"primaryKey");"id"!==r&&(e.id=e[r],delete e[r])},normalizeUsingDeclaredMapping:function(e,r){var i,n,a=t(this,"attrs");if(a)for(n in a)i=a[n],r[n]=r[i],delete r[i]},normalizeAttributes:function(e,t){var r;this.keyForAttribute&&e.eachAttribute(function(e){r=this.keyForAttribute(e),e!==r&&(t[e]=t[r],delete t[r])},this)},normalizeRelationships:function(e,t){var r;this.keyForRelationship&&e.eachRelationship(function(e,i){r=this.keyForRelationship(e,i.kind),e!==r&&(t[e]=t[r],delete t[r])},this)},extractSingle:function(t,i,n,a){n=this.normalizePayload(i,n);var o,s=i.typeKey;for(var c in n){var d=this.typeForRoot(c),u=d===s;if(u&&"array"!==Ember.typeOf(n[c]))o=this.normalize(i,n[c],c);else{{t.modelFor(d)}r.call(n[c],function(r){var i=this.typeForRoot(c),n=t.modelFor(i),s=t.serializerFor(n);r=s.normalize(n,r,c);var d=u&&!a&&!o,l=u&&e(r.id)===a;d||l?o=r:t.push(i,r)},this)}}return o},extractArray:function(e,t,r){r=this.normalizePayload(t,r);var n,a=t.typeKey;for(var o in r){var s=o,c=!1;"_"===o.charAt(0)&&(c=!0,s=o.substr(1));var d=this.typeForRoot(s),u=e.modelFor(d),l=e.serializerFor(u),h=!c&&d===a,f=i.call(r[o],function(e){return l.normalize(u,e,o)},this);h?n=f:e.pushMany(d,f)}return n},pushPayload:function(e,t){t=this.normalizePayload(null,t);for(var r in t){var n=this.typeForRoot(r),a=e.modelFor(n),o=i.call(t[r],function(e){return this.normalize(a,e,r)},this);e.pushMany(n,o)}},typeForRoot:function(e){return Ember.String.singularize(e)},serialize:function(){return this._super.apply(this,arguments)},serializeIntoHash:function(e,t,r,i){e[t.typeKey]=this.serialize(r,i)},serializePolymorphicType:function(e,r,i){var n=i.key,a=t(e,n);n=this.keyForAttribute?this.keyForAttribute(n):n,r[n+"Type"]=a.constructor.typeKey}})}(),function(){var e=Ember.get,t=(Ember.set,Ember.ArrayPolyfills.forEach);DS.RESTAdapter=DS.Adapter.extend({defaultSerializer:"_rest",find:function(e,t,r){return this.ajax(this.buildURL(t.typeKey,r),"GET")},findAll:function(e,t,r){var i;return r&&(i={since:r}),this.ajax(this.buildURL(t.typeKey),"GET",{data:i})},findQuery:function(e,t,r){return this.ajax(this.buildURL(t.typeKey),"GET",{data:r})},findMany:function(e,t,r){return this.ajax(this.buildURL(t.typeKey),"GET",{data:{ids:r}})},findHasMany:function(t,r,i){var n=e(this,"host"),a=e(r,"id"),o=r.constructor.typeKey;return n&&"/"===i.charAt(0)&&"/"!==i.charAt(1)&&(i=n+i),this.ajax(this.urlPrefix(i,this.buildURL(o,a)),"GET")},findBelongsTo:function(t,r,i){var n=e(r,"id"),a=r.constructor.typeKey;return this.ajax(this.urlPrefix(i,this.buildURL(a,n)),"GET")},createRecord:function(e,t,r){var i={},n=e.serializerFor(t.typeKey);return n.serializeIntoHash(i,t,r,{includeId:!0}),this.ajax(this.buildURL(t.typeKey),"POST",{data:i})},updateRecord:function(t,r,i){var n={},a=t.serializerFor(r.typeKey);a.serializeIntoHash(n,r,i);var o=e(i,"id");return this.ajax(this.buildURL(r.typeKey,o),"PUT",{data:n})},deleteRecord:function(t,r,i){var n=e(i,"id");return this.ajax(this.buildURL(r.typeKey,n),"DELETE")},buildURL:function(t,r){var i=[],n=e(this,"host"),a=this.urlPrefix();return t&&i.push(this.pathForType(t)),r&&i.push(r),a&&i.unshift(a),i=i.join("/"),!n&&i&&(i="/"+i),i},urlPrefix:function(t,r){var i=e(this,"host"),n=e(this,"namespace"),a=[];return t?"/"===t.charAt(0)?i&&(t=t.slice(1),a.push(i)):/^http(s)?:\/\//.test(t)||a.push(r):(i&&a.push(i),n&&a.push(n)),t&&a.push(t),a.join("/")},pathForType:function(e){return Ember.String.pluralize(e)},ajaxError:function(e){return e&&(e.then=null),e},ajax:function(e,t,r){var i=this;return new Ember.RSVP.Promise(function(n,a){r=i.ajaxOptions(e,t,r),r.success=function(e){Ember.run(null,n,e)},r.error=function(e){Ember.run(null,a,i.ajaxError(e))},Ember.$.ajax(r)},"DS: RestAdapter#ajax "+t+" to "+e)},ajaxOptions:function(e,r,i){if(i=i||{},i.url=e,i.type=r,i.dataType="json",i.context=this,i.data&&"GET"!==r&&(i.contentType="application/json; charset=utf-8",i.data=JSON.stringify(i.data)),void 0!==this.headers){var n=this.headers;i.beforeSend=function(e){t.call(Ember.keys(n),function(t){e.setRequestHeader(t,n[t])})}}return i}})}(),function(){DS.Model.reopen({_debugInfo:function(){var e=["id"],t={belongsTo:[],hasMany:[]},r=[];this.eachAttribute(function(t){e.push(t)},this),this.eachRelationship(function(e,i){t[i.kind].push(e),r.push(e)});var i=[{name:"Attributes",properties:e,expand:!0},{name:"Belongs To",properties:t.belongsTo,expand:!0},{name:"Has Many",properties:t.hasMany,expand:!0},{name:"Flags",properties:["isLoaded","isDirty","isSaving","isDeleted","isError","isNew","isValid"]}];return{propertyInfo:{includeOtherProperties:!0,groups:i,expensiveProperties:r}}}})}(),function(){Ember.String.pluralize=function(e){return Ember.Inflector.inflector.pluralize(e)},Ember.String.singularize=function(e){return Ember.Inflector.inflector.singularize(e)}}(),function(){function e(e,t){for(var r=0,i=t.length;i>r;r++)e.uncountable[t[r].toLowerCase()]=!0}function t(e,t){for(var r,i=0,n=t.length;n>i;i++)r=t[i],e.irregular[r[0].toLowerCase()]=r[1],e.irregularInverse[r[1].toLowerCase()]=r[0]}function r(r){r=r||{},r.uncountable=r.uncountable||{},r.irregularPairs=r.irregularPairs||{};var i=this.rules={plurals:r.plurals||[],singular:r.singular||[],irregular:{},irregularInverse:{},uncountable:{}};e(i,r.uncountable),t(i,r.irregularPairs)}var i=/^\s*$/;r.prototype={plural:function(e,t){this.rules.plurals.push([e,t.toLowerCase()])},singular:function(e,t){this.rules.singular.push([e,t.toLowerCase()])},uncountable:function(t){e(this.rules,[t.toLowerCase()])},irregular:function(e,r){t(this.rules,[[e,r]])},pluralize:function(e){return this.inflect(e,this.rules.plurals,this.rules.irregular)},singularize:function(e){return this.inflect(e,this.rules.singular,this.rules.irregularInverse)},inflect:function(e,t,r){var n,a,o,s,c,d,u,l;if(c=i.test(e))return e;if(s=e.toLowerCase(),d=this.rules.uncountable[s])return e;if(u=r&&r[s])return u;for(var h=t.length,f=0;h>f&&(n=t[h-1],l=n[0],!l.test(e));h--);return n=n||[],l=n[0],a=n[1],o=e.replace(l,a)}},Ember.Inflector=r}(),function(){Ember.Inflector.defaultRules={plurals:[[/$/,"s"],[/s$/i,"s"],[/^(ax|test)is$/i,"$1es"],[/(octop|vir)us$/i,"$1i"],[/(octop|vir)i$/i,"$1i"],[/(alias|status)$/i,"$1es"],[/(bu)s$/i,"$1ses"],[/(buffal|tomat)o$/i,"$1oes"],[/([ti])um$/i,"$1a"],[/([ti])a$/i,"$1a"],[/sis$/i,"ses"],[/(?:([^f])fe|([lr])f)$/i,"$1$2ves"],[/(hive)$/i,"$1s"],[/([^aeiouy]|qu)y$/i,"$1ies"],[/(x|ch|ss|sh)$/i,"$1es"],[/(matr|vert|ind)(?:ix|ex)$/i,"$1ices"],[/^(m|l)ouse$/i,"$1ice"],[/^(m|l)ice$/i,"$1ice"],[/^(ox)$/i,"$1en"],[/^(oxen)$/i,"$1"],[/(quiz)$/i,"$1zes"]],singular:[[/s$/i,""],[/(ss)$/i,"$1"],[/(n)ews$/i,"$1ews"],[/([ti])a$/i,"$1um"],[/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i,"$1sis"],[/(^analy)(sis|ses)$/i,"$1sis"],[/([^f])ves$/i,"$1fe"],[/(hive)s$/i,"$1"],[/(tive)s$/i,"$1"],[/([lr])ves$/i,"$1f"],[/([^aeiouy]|qu)ies$/i,"$1y"],[/(s)eries$/i,"$1eries"],[/(m)ovies$/i,"$1ovie"],[/(x|ch|ss|sh)es$/i,"$1"],[/^(m|l)ice$/i,"$1ouse"],[/(bus)(es)?$/i,"$1"],[/(o)es$/i,"$1"],[/(shoe)s$/i,"$1"],[/(cris|test)(is|es)$/i,"$1is"],[/^(a)x[ie]s$/i,"$1xis"],[/(octop|vir)(us|i)$/i,"$1us"],[/(alias|status)(es)?$/i,"$1"],[/^(ox)en/i,"$1"],[/(vert|ind)ices$/i,"$1ex"],[/(matr)ices$/i,"$1ix"],[/(quiz)zes$/i,"$1"],[/(database)s$/i,"$1"]],irregularPairs:[["person","people"],["man","men"],["child","children"],["sex","sexes"],["move","moves"],["cow","kine"],["zombie","zombies"]],uncountable:["equipment","information","rice","money","species","series","fish","sheep","jeans","police"]}}(),function(){(Ember.EXTEND_PROTOTYPES===!0||Ember.EXTEND_PROTOTYPES.String)&&(String.prototype.pluralize=function(){return Ember.String.pluralize(this)},String.prototype.singularize=function(){return Ember.String.singularize(this)})}(),function(){Ember.Inflector.inflector=new Ember.Inflector(Ember.Inflector.defaultRules)}(),function(){var e=Ember.get,t=Ember.EnumerableUtils.forEach;DS.ActiveModelSerializer=DS.RESTSerializer.extend({keyForAttribute:function(e){return Ember.String.decamelize(e)},keyForRelationship:function(e,t){return e=Ember.String.decamelize(e),"belongsTo"===t?e+"_id":"hasMany"===t?Ember.String.singularize(e)+"_ids":e},serializeHasMany:Ember.K,serializeIntoHash:function(e,t,r,i){var n=Ember.String.decamelize(t.typeKey);e[n]=this.serialize(r,i)},serializePolymorphicType:function(t,r,i){var n=i.key,a=e(t,n);n=this.keyForAttribute(n),r[n+"_type"]=Ember.String.capitalize(a.constructor.typeKey)},typeForRoot:function(e){var t=Ember.String.camelize(e);return Ember.String.singularize(t)},normalize:function(e,t,r){return this.normalizeLinks(t),this._super(e,t,r)},normalizeLinks:function(e){if(e.links){var t=e.links;for(var r in t){var i=Ember.String.camelize(r);i!==r&&(t[i]=t[r],delete t[r])}}},normalizeRelationships:function(e,r){var i,n;this.keyForRelationship&&e.eachRelationship(function(e,a){if(a.options.polymorphic){if(i=this.keyForAttribute(e),n=r[i],n&&n.type)n.type=this.typeForRoot(n.type);else if(n&&"hasMany"===a.kind){var o=this;t(n,function(e){e.type=o.typeForRoot(e.type)})}}else i=this.keyForRelationship(e,a.kind),n=r[i];r[e]=n,e!==i&&delete r[i]},this)}})}(),function(){function e(i,n,a,o,s){var c=t(n,"attrs");c&&a.eachRelationship(function(n,a){var d,u,l,h,f=c[n],p=i.serializerFor(a.type.typeKey),m=t(p,"primaryKey");if("hasMany"===a.kind&&f&&("always"===f.embedded||"load"===f.embedded)){if(u="_"+Ember.String.pluralize(a.type.typeKey),d=this.keyForRelationship(n,a.kind),l=this.keyForAttribute(n),h=[],!o[l])return;s[u]=s[u]||[],r(o[l],function(t){var r=i.modelFor(a.type.typeKey);e(i,p,r,t,s),h.push(t[m]),s[u].push(t)}),o[d]=h,delete o[l]}},n)}var t=Ember.get,r=Ember.EnumerableUtils.forEach;DS.EmbeddedRecordsMixin=Ember.Mixin.create({serializeHasMany:function(e,r,i){var n=i.key,a=t(this,"attrs"),o=a&&a[n]&&"always"===a[n].embedded;o&&(r[this.keyForAttribute(n)]=t(e,n).map(function(e){var r=e.serialize(),i=t(this,"primaryKey");return r[i]=t(e,i),r},this))},extractSingle:function(t,r,i,n,a){var o=this.keyForAttribute(r.typeKey),s=i[o];return e(t,this,r,s,i),this._super(t,r,i,n,a)},extractArray:function(t,i,n){var a=this.keyForAttribute(i.typeKey),o=n[Ember.String.pluralize(a)];return r(o,function(r){e(t,this,i,r,n)},this),this._super(t,i,n)}})}(),function(){var e=Ember.EnumerableUtils.forEach;DS.ActiveModelAdapter=DS.RESTAdapter.extend({defaultSerializer:"_ams",pathForType:function(e){var t=Ember.String.decamelize(e);return Ember.String.pluralize(t)},ajaxError:function(t){var r=this._super(t);if(t&&422===t.status){var i=Ember.$.parseJSON(t.responseText).errors,n={};return e(Ember.keys(i),function(e){n[Ember.String.camelize(e)]=i[e]}),new DS.InvalidError(n)}return r}})}(),function(){Ember.onLoad("Ember.Application",function(e){e.initializer({name:"activeModelAdapter",initialize:function(e,t){t.register("serializer:_ams",DS.ActiveModelSerializer),t.register("adapter:_ams",DS.ActiveModelAdapter)}})})}()}(),"undefined"==typeof location||"localhost"!==location.hostname&&"127.0.0.1"!==location.hostname||Ember.Logger.warn("You are running a production build of Ember on localhost and won't receive detailed error messages. If you want full error messages please use the non-minified build provided on the Ember website."); diff --git a/vendor/assets/ember/production/ember.js b/vendor/assets/ember/production/ember.js index 447acfe2..85915258 100644 --- a/vendor/assets/ember/production/ember.js +++ b/vendor/assets/ember/production/ember.js @@ -1,23 +1,25 @@ +// Fetched from channel: release, with url http://builds.emberjs.com/release/ember.min.js +// Fetched on: 2014-01-04T21:05:19Z // ========================================================================== // Project: Ember - JavaScript Application Framework -// Copyright: ©2011-2013 Tilde Inc. and contributors -// Portions ©2006-2011 Strobe Inc. -// Portions ©2008-2011 Apple Inc. All rights reserved. +// Copyright: Copyright 2011-2013 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: v1.0.0-225-g56e5a22 -// Last commit: 56e5a22 (2013-10-03 13:41:25 -0700) + // Version: 1.2.1+pre.ce3a6b7c - -// Copyright: ©2011-2013 Tilde Inc. and contributors -!function(){var e,t;!function(){var r={},n={};e=function(e,t,n){r[e]={deps:t,callback:n}},t=function(e){if(n[e])return n[e];n[e]={};var i,o,a,s,u;if(i=r[e],!i)throw new Error("Module '"+e+"' not found.");o=i.deps,a=i.callback,s=[];for(var c=0,l=o.length;l>c;c++)"exports"===o[c]?s.push(u={}):s.push(t(o[c]));var h=a.apply(this,s);return n[e]=u||h}}(),function(){function e(e){var t;r.console?t=r.console:"undefined"!=typeof console&&(t=console);var n="object"==typeof t?t[e]:null;return n?n.apply?function(){n.apply(t,arguments)}:function(){var e=Array.prototype.join.call(arguments,", ");n(e)}:void 0}function t(e,t){if(!e)try{throw new Error("assertion failed: "+t)}catch(r){setTimeout(function(){throw r},0)}}"undefined"==typeof Ember&&(Ember={});var r=Ember.imports=Ember.imports||this,n=Ember.exports=Ember.exports||this;Ember.lookup=Ember.lookup||this,n.Em=n.Ember=Em=Ember,Ember.isNamespace=!0,Ember.toString=function(){return"Ember"},Ember.VERSION="1.0.0","undefined"==typeof ENV&&(n.ENV={}),"undefined"==typeof ENV.DISABLE_RANGE_API&&(ENV.DISABLE_RANGE_API=!0),Ember.ENV=Ember.ENV||ENV,Ember.config=Ember.config||{},Ember.FEATURES=Ember.ENV.FEATURES||{},Ember.FEATURES.isEnabled=function(e){return Ember.ENV.ENABLE_ALL_FEATURES||Ember.FEATURES[e]},Ember.EXTEND_PROTOTYPES=Ember.ENV.EXTEND_PROTOTYPES,"undefined"==typeof Ember.EXTEND_PROTOTYPES&&(Ember.EXTEND_PROTOTYPES=!0),Ember.LOG_STACKTRACE_ON_DEPRECATION=Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION!==!1,Ember.SHIM_ES5=Ember.ENV.SHIM_ES5===!1?!1:Ember.EXTEND_PROTOTYPES,Ember.LOG_VERSION=Ember.ENV.LOG_VERSION===!1?!1:!0,Ember.K=function(){return this},"undefined"==typeof Ember.assert&&(Ember.assert=Ember.K),"undefined"==typeof Ember.warn&&(Ember.warn=Ember.K),"undefined"==typeof Ember.debug&&(Ember.debug=Ember.K),"undefined"==typeof Ember.deprecate&&(Ember.deprecate=Ember.K),"undefined"==typeof Ember.deprecateFunc&&(Ember.deprecateFunc=function(e,t){return t}),Ember.uuid=0,Ember.Logger={log:e("log")||Ember.K,warn:e("warn")||Ember.K,error:e("error")||Ember.K,info:e("info")||Ember.K,debug:e("debug")||e("info")||Ember.K,assert:e("assert")||t},Ember.onerror=null,Ember.handleErrors=function(e,t){if("function"!=typeof Ember.onerror)return e.call(t||this);try{return e.call(t||this)}catch(r){Ember.onerror(r)}},Ember.merge=function(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r]);return e},Ember.isNone=function(e){return null===e||void 0===e},Ember.none=Ember.deprecateFunc("Ember.none is deprecated. Please use Ember.isNone instead.",Ember.isNone),Ember.isEmpty=function(e){return Ember.isNone(e)||0===e.length&&"function"!=typeof e||"object"==typeof e&&0===Ember.get(e,"length")},Ember.empty=Ember.deprecateFunc("Ember.empty is deprecated. Please use Ember.isEmpty instead.",Ember.isEmpty)}(),function(){var e=Ember.platform={};if(Ember.create=Object.create,Ember.create&&2!==Ember.create({a:1},{a:{value:2}}).a&&(Ember.create=null),!Ember.create||Ember.ENV.STUB_OBJECT_CREATE){var t=function(){};Ember.create=function(e,r){if(t.prototype=e,e=new t,r){t.prototype=e;for(var n in r)t.prototype[n]=r[n].value;e=new t}return t.prototype=null,e},Ember.create.isSimulated=!0}var r,n,i=Object.defineProperty;if(i)try{i({},"a",{get:function(){}})}catch(o){i=null}i&&(r=function(){var e={};return i(e,"a",{configurable:!0,enumerable:!0,get:function(){},set:function(){}}),i(e,"a",{configurable:!0,enumerable:!0,writable:!0,value:!0}),e.a===!0}(),n=function(){try{return i(document.createElement("div"),"definePropertyOnDOM",{}),!0}catch(e){}return!1}(),r?n||(i=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)}):i=null),e.defineProperty=i,e.hasPropertyAccessors=!0,e.defineProperty||(e.hasPropertyAccessors=!1,e.defineProperty=function(e,t,r){r.get||(e[t]=r.value)},e.defineProperty.isSimulated=!0),Ember.ENV.MANDATORY_SETTER&&!e.hasPropertyAccessors&&(Ember.ENV.MANDATORY_SETTER=!1)}(),function(){var e=function(e){return e&&Function.prototype.toString.call(e).indexOf("[native code]")>-1},t=e(Array.prototype.map)?Array.prototype.map:function(e){if(void 0===this||null===this)throw new TypeError;var t=Object(this),r=t.length>>>0;if("function"!=typeof e)throw new TypeError;for(var n=new Array(r),i=arguments[1],o=0;r>o;o++)o in t&&(n[o]=e.call(i,t[o],o,t));return n},r=e(Array.prototype.forEach)?Array.prototype.forEach:function(e){if(void 0===this||null===this)throw new TypeError;var t=Object(this),r=t.length>>>0;if("function"!=typeof e)throw new TypeError;for(var n=arguments[1],i=0;r>i;i++)i in t&&e.call(n,t[i],i,t)},n=e(Array.prototype.indexOf)?Array.prototype.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};Ember.ArrayPolyfills={map:t,forEach:r,indexOf:n},Ember.SHIM_ES5&&(Array.prototype.map||(Array.prototype.map=t),Array.prototype.forEach||(Array.prototype.forEach=r),Array.prototype.indexOf||(Array.prototype.indexOf=n))}(),function(){function e(e){this.descs={},this.watching={},this.cache={},this.source=e}function t(e,t){return!(!e||"function"!=typeof e[t])}var r=Ember.platform.defineProperty,n=Ember.create,i="__ember"+ +new Date,o=0,a=[],s={},u=Ember.ENV.MANDATORY_SETTER;Ember.GUID_KEY=i;var c={writable:!1,configurable:!1,enumerable:!1,value:null};Ember.generateGuid=function(e,t){t||(t="ember");var n=t+o++;return e&&(c.value=n,r(e,i,c)),n},Ember.guidFor=function(e){if(void 0===e)return"(undefined)";if(null===e)return"(null)";var t,n=typeof e;switch(n){case"number":return t=a[e],t||(t=a[e]="nu"+e),t;case"string":return t=s[e],t||(t=s[e]="st"+o++),t;case"boolean":return e?"(true)":"(false)";default:return e[i]?e[i]:e===Object?"(Object)":e===Array?"(Array)":(t="ember"+o++,c.value=t,r(e,i,c),t)}};var l={writable:!0,configurable:!1,enumerable:!1,value:null},h=Ember.GUID_KEY+"_meta";Ember.META_KEY=h;var m={descs:{},watching:{}};u&&(m.values={}),Ember.EMPTY_META=m,Object.freeze&&Object.freeze(m);var f=Ember.platform.defineProperty.isSimulated;f&&(e.prototype.__preventPlainObject__=!0,e.prototype.toJSON=function(){}),Ember.meta=function(t,i){var o=t[h];return i===!1?o||m:(o?o.source!==t&&(f||r(t,h,l),o=n(o),o.descs=n(o.descs),o.watching=n(o.watching),o.cache={},o.source=t,u&&(o.values=n(o.values)),t[h]=o):(f||r(t,h,l),o=new e(t),u&&(o.values={}),t[h]=o,o.descs.constructor=null),o)},Ember.getMeta=function(e,t){var r=Ember.meta(e,!1);return r[t]},Ember.setMeta=function(e,t,r){var n=Ember.meta(e,!0);return n[t]=r,r},Ember.metaPath=function(e,t,r){for(var i,o,a=Ember.meta(e,r),s=0,u=t.length;u>s;s++){if(i=t[s],o=a[i]){if(o.__ember_source__!==e){if(!r)return void 0;o=a[i]=n(o),o.__ember_source__=e}}else{if(!r)return void 0;o=a[i]={__ember_source__:e}}a=o}return o},Ember.wrap=function(e,t){function r(){}function n(){var n,i=this._super;return this._super=t||r,n=e.apply(this,arguments),this._super=i,n}return n.wrappedFunction=e,n.__ember_observes__=e.__ember_observes__,n.__ember_observesBefore__=e.__ember_observesBefore__,n.__ember_listens__=e.__ember_listens__,n},Ember.isArray=function(e){return!e||e.setInterval?!1:Array.isArray&&Array.isArray(e)?!0:Ember.Array&&Ember.Array.detect(e)?!0:void 0!==e.length&&"object"==typeof e?!0:!1},Ember.makeArray=function(e){return null===e||void 0===e?[]:Ember.isArray(e)?e:[e]},Ember.canInvoke=t,Ember.tryInvoke=function(e,r,n){return t(e,r)?e[r].apply(e,n||[]):void 0};var p=function(){var e=0;try{try{}finally{throw e++,new Error("needsFinallyFixTest")}}catch(t){}return 1!==e}();Ember.tryFinally=p?function(e,t,r){var n,i,o;r=r||this;try{n=e.call(r)}finally{try{i=t.call(r)}catch(a){o=a}}if(o)throw o;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},Ember.tryCatchFinally=p?function(e,t,r,n){var i,o,a;n=n||this;try{i=e.call(n)}catch(s){i=t.call(n,s)}finally{try{o=r.call(n)}catch(u){a=u}}if(a)throw a;return void 0===o?i:o}:function(e,t,r,n){var i,o;n=n||this;try{i=e.call(n)}catch(a){i=t.call(n,a)}finally{o=r.call(n)}return void 0===o?i:o};var d={},b="Boolean Number String Function Array Date RegExp Object".split(" ");Ember.ArrayPolyfills.forEach.call(b,function(e){d["[object "+e+"]"]=e.toLowerCase()});var E=Object.prototype.toString;Ember.typeOf=function(e){var t;return t=null===e||void 0===e?String(e):d[E.call(e)]||"object","function"===t?Ember.Object&&Ember.Object.detect(e)&&(t="class"):"object"===t&&(t=e instanceof Error?"error":Ember.Object&&e instanceof Ember.Object?"instance":"object"),t}}(),function(){Ember.Instrumentation={};var e=[],t={},r=function(r){for(var n,i=[],o=0,a=e.length;a>o;o++)n=e[o],n.regex.test(r)&&i.push(n.object);return t[r]=i,i},n=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}}();Ember.Instrumentation.instrument=function(e,i,o,a){function s(){for(p=0,d=m.length;d>p;p++)f=m[p],b[p]=f.before(e,n(),i);return o.call(a)}function u(e){i=i||{},i.exception=e}function c(){for(p=0,d=m.length;d>p;p++)f=m[p],f.after(e,n(),i,b[p]);Ember.STRUCTURED_PROFILE&&console.timeEnd(l)}var l,h,m=t[e];if(Ember.STRUCTURED_PROFILE&&(l=e+": "+i.object,console.time(l)),m||(m=r(e)),0===m.length)return h=o.call(a),Ember.STRUCTURED_PROFILE&&console.timeEnd(l),h;var f,p,d,b=[];return Ember.tryCatchFinally(s,u,c)},Ember.Instrumentation.subscribe=function(r,n){for(var i,o=r.split("."),a=[],s=0,u=o.length;u>s;s++)i=o[s],"*"===i?a.push("[^\\.]*"):a.push(i);a=a.join("\\."),a+="(\\..*)?";var c={pattern:r,regex:new RegExp("^"+a+"$"),object:n};return e.push(c),t={},c},Ember.Instrumentation.unsubscribe=function(r){for(var n,i=0,o=e.length;o>i;i++)e[i]===r&&(n=i);e.splice(n,1),t={}},Ember.Instrumentation.reset=function(){e=[],t={}},Ember.instrument=Ember.Instrumentation.instrument,Ember.subscribe=Ember.Instrumentation.subscribe}(),function(){var e,t,r,n;e=Array.prototype.map||Ember.ArrayPolyfills.map,t=Array.prototype.forEach||Ember.ArrayPolyfills.forEach,r=Array.prototype.indexOf||Ember.ArrayPolyfills.indexOf,n=Array.prototype.splice;var i=Ember.EnumerableUtils={map:function(t,r,n){return t.map?t.map.call(t,r,n):e.call(t,r,n)},forEach:function(e,r,n){return e.forEach?e.forEach.call(e,r,n):t.call(e,r,n)},indexOf:function(e,t,n){return e.indexOf?e.indexOf.call(e,t,n):r.call(e,t,n)},indexesOf:function(e,t){return void 0===t?[]:i.map(t,function(t){return i.indexOf(e,t)})},addObject:function(e,t){var r=i.indexOf(e,t);-1===r&&e.push(t)},removeObject:function(e,t){var r=i.indexOf(e,t);-1!==r&&e.splice(r,1)},_replace:function(e,t,r,i){for(var o,a,s=[].concat(i),u=[],c=6e4,l=t,h=r;s.length;)a=h>c?c:h,0>=a&&(a=0),o=s.splice(0,c),o=[l,a].concat(o),l+=c,h-=a,u=u.concat(n.apply(e,o));return u},replace:function(e,t,r,n){return e.replace?e.replace(t,r,n):i._replace(e,t,r,n)},intersection:function(e,t){var r=[];return i.forEach(e,function(e){i.indexOf(t,e)>=0&&r.push(e)}),r}}}(),function(){var e,t=Ember.META_KEY,r=Ember.ENV.MANDATORY_SETTER,n=/^([A-Z$]|([0-9][A-Z$])).*[\.\*]/,i=/^this[\.\*]/,o=/^([^\.\*]+)/;e=function(e,n){if(""===n)return e;if(n||"string"!=typeof e||(n=e,e=null),null===e||-1!==n.indexOf("."))return s(e,n);var i,o=e[t],a=o&&o.descs[n];return a?a.get(e,n):(i=r&&o&&o.watching[n]>0?o.values[n]:e[n],void 0!==i||"object"!=typeof e||n in e||"function"!=typeof e.unknownProperty?i:e.unknownProperty(n))},Ember.config.overrideAccessors&&(Ember.get=e,Ember.config.overrideAccessors(),e=Ember.get);var a=Ember.normalizeTuple=function(t,r){var a,s=i.test(r),u=!s&&n.test(r);if((!t||u)&&(t=Ember.lookup),s&&(r=r.slice(5)),t===Ember.lookup&&(a=r.match(o)[0],t=e(t,a),r=r.slice(a.length+1)),!r||0===r.length)throw new Error("Invalid Path");return[t,r]},s=Ember._getPath=function(t,r){var n,o,s,u,c;if(null===t&&-1===r.indexOf("."))return e(Ember.lookup,r);for(n=i.test(r),(!t||n)&&(s=a(t,r),t=s[0],r=s[1],s.length=0),o=r.split("."),c=o.length,u=0;null!=t&&c>u;u++)if(t=e(t,o[u],!0),t&&t.isDestroyed)return void 0;return t};Ember.getWithDefault=function(t,r,n){var i=e(t,r);return void 0===i?n:i},Ember.get=e}(),function(){function e(e,t,r){for(var n=-1,i=0,o=e.length;o>i;i+=3)if(t===e[i]&&r===e[i+1]){n=i;break}return n}function t(e,t){var r,n=f(e,!0);return n.listeners||(n.listeners={}),n.hasOwnProperty("listeners")||(n.listeners=m(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 r(t,r,n){var i=t[p],o=i&&i.listeners&&i.listeners[r];if(o)for(var a=o.length-3;a>=0;a-=3){var s=o[a],u=o[a+1],c=o[a+2],l=e(n,s,u);-1===l&&n.push(s,u,c)}}function n(t,r,n){var i=t[p],o=i&&i.listeners&&i.listeners[r],a=[];if(o){for(var s=o.length-3;s>=0;s-=3){var u=o[s],c=o[s+1],l=o[s+2],h=e(n,u,c);-1===h&&(n.push(u,c,l),a.push(u,c,l))}return a}}function i(r,n,i,o,a){o||"function"!=typeof i||(o=i,i=null);var s=t(r,n),u=e(s,i,o),c=0;a&&(c|=b),-1===u&&(s.push(i,o,c),"function"==typeof r.didAddListener&&r.didAddListener(n,i,o))}function o(r,n,i,o){function a(i,o){var a=t(r,n),s=e(a,i,o);-1!==s&&(a.splice(s,3),"function"==typeof r.didRemoveListener&&r.didRemoveListener(n,i,o))}if(o||"function"!=typeof i||(o=i,i=null),o)a(i,o);else{var s=r[p],u=s&&s.listeners&&s.listeners[n];if(!u)return;for(var c=u.length-3;c>=0;c-=3)a(u[c],u[c+1])}}function a(r,n,i,o,a){function s(){return a.call(i)}function u(){-1!==l&&(c[l+2]&=~E)}o||"function"!=typeof i||(o=i,i=null);var c=t(r,n),l=e(c,i,o);return-1!==l&&(c[l+2]|=E),Ember.tryFinally(s,u)}function s(r,n,i,o,a){function s(){return a.call(i)}function u(){for(var e=0,t=f.length;t>e;e++){var r=f[e];p[e][r+2]&=~E}}o||"function"!=typeof i||(o=i,i=null);var c,l,h,m,f=[],p=[];for(h=0,m=n.length;m>h;h++){c=n[h],l=t(r,c);var d=e(l,i,o);-1!==d&&(l[d+2]|=E,f.push(d),p.push(l))}return Ember.tryFinally(s,u)}function u(e){var t=e[p].listeners,r=[];if(t)for(var n in t)t[n]&&r.push(n);return r}function c(e,t,r,n){if(e!==Ember&&"function"==typeof e.sendEvent&&e.sendEvent(t,r),!n){var i=e[p];n=i&&i.listeners&&i.listeners[t]}if(n){for(var a=n.length-3;a>=0;a-=3){var s=n[a],u=n[a+1],c=n[a+2];u&&(c&E||(c&b&&o(e,t,s,u),s||(s=e),"string"==typeof u&&(u=s[u]),r?u.apply(s,r):u.call(s)))}return!0}}function l(e,t){var r=e[p],n=r&&r.listeners&&r.listeners[t];return!(!n||!n.length)}function h(e,t){var r=[],n=e[p],i=n&&n.listeners&&n.listeners[t];if(!i)return r;for(var o=0,a=i.length;a>o;o+=3){var s=i[o],u=i[o+1];r.push([s,u])}return r}var m=Ember.create,f=Ember.meta,p=Ember.META_KEY,d=[].slice,b=1,E=2;Ember.on=function(){var e=d.call(arguments,-1)[0],t=d.call(arguments,0,-1);return e.__ember_listens__=t,e},Ember.addListener=i,Ember.removeListener=o,Ember._suspendListener=a,Ember._suspendListeners=s,Ember.sendEvent=c,Ember.hasListeners=l,Ember.watchedEvents=u,Ember.listenersFor=h,Ember.listenersDiff=n,Ember.listenersUnion=r}(),function(){var e=Ember.guidFor,t=Ember.sendEvent,r=Ember._ObserverSet=function(){this.clear()};r.prototype.add=function(t,r,n){var i,o=this.observerSet,a=this.observers,s=e(t),u=o[s];return u||(o[s]=u={}),i=u[r],void 0===i&&(i=a.push({sender:t,keyName:r,eventName:n,listeners:[]})-1,u[r]=i),a[i].listeners},r.prototype.flush=function(){var e,r,n,i,o=this.observers;for(this.clear(),e=0,r=o.length;r>e;++e)n=o[e],i=n.sender,i.isDestroying||i.isDestroyed||t(i,n.eventName,[i,n.keyName],n.listeners)},r.prototype.clear=function(){this.observerSet={},this.observers=[]}}(),function(){function e(e,t){var n=h(e,!1),i=n.watching[t]>0||"length"===t,a=n.proto,s=n.descs[t];i&&a!==e&&(s&&s.willChange&&s.willChange(e,t),r(e,t,n),o(e,t,n),c(e,t))}function t(e,t){var r=h(e,!1),i=r.watching[t]>0||"length"===t,o=r.proto,s=r.descs[t];o!==e&&(s&&s.didChange&&s.didChange(e,t),(i||"length"===t)&&(n(e,t,r),a(e,t,r,!1),l(e,t)))}function r(t,r,n){if(!t.isDestroying){var o=w,a=!o;a&&(o=w={}),i(e,t,r,o,n),a&&(w=null)}}function n(e,r,n){if(!e.isDestroying){var o=_,a=!o;a&&(o=_={}),i(t,e,r,o,n),a&&(_=null)}}function i(e,t,r,n,i){var o=m(t);if(n[o]||(n[o]={}),!n[o][r]){n[o][r]=!0;var a=i.deps;if(a=a&&a[r])for(var s in a){var u=i.descs[s];u&&u._suspended===t||e(t,s)}}}function o(t,r,n){if(n.hasOwnProperty("chainWatchers")&&n.chainWatchers[r]){var i,o,a=n.chainWatchers[r],s=[];for(i=0,o=a.length;o>i;i++)a[i].willChange(s);for(i=0,o=s.length;o>i;i+=2)e(s[i],s[i+1])}}function a(e,r,n,i){if(n.hasOwnProperty("chainWatchers")&&n.chainWatchers[r]){var o,a,s=n.chainWatchers[r],u=i?null:[];for(o=0,a=s.length;a>o;o++)s[o].didChange(u);if(!i)for(o=0,a=u.length;a>o;o+=2)t(u[o],u[o+1])}}function s(){y++}function u(){y--,0>=y&&(v.clear(),g.flush())}function c(e,t){if(!e.isDestroying){var r,n,i=t+":before";y?(r=v.add(e,t,i),n=b(e,i,r),p(e,i,[e,t],n)):p(e,i,[e,t])}}function l(e,t){if(!e.isDestroying){var r,n=t+":change";y?(r=g.add(e,t,n),d(e,n,r)):p(e,n,[e,t])}}var h=Ember.meta,m=Ember.guidFor,f=Ember.tryFinally,p=Ember.sendEvent,d=Ember.listenersUnion,b=Ember.listenersDiff,E=Ember._ObserverSet,v=new E,g=new E,y=0;Ember.propertyWillChange=e,Ember.propertyDidChange=t;var w,_;Ember.overrideChains=function(e,t,r){a(e,t,r,!0)},Ember.beginPropertyChanges=s,Ember.endPropertyChanges=u,Ember.changeProperties=function(e,t){s(),f(e,u,t)}}(),function(){function e(e,t,r,o){var a;if(a=t.slice(t.lastIndexOf(".")+1),t=t.slice(0,t.length-(a.length+1)),"this"!==t&&(e=n(e,t)),!a||0===a.length)throw new Error("You passed an empty path");if(!e){if(o)return;throw new Error("Object in path "+t+" could not be found or was destroyed.")}return i(e,a,r)}var t=Ember.META_KEY,r=Ember.ENV.MANDATORY_SETTER,n=Ember._getPath,i=function(n,i,o,a){if("string"==typeof n&&(o=i,i=n,n=null),!n||-1!==i.indexOf("."))return e(n,i,o,a);var s,u,c=n[t],l=c&&c.descs[i];return l?l.set(n,i,o):(s="object"==typeof n&&!(i in n),s&&"function"==typeof n.setUnknownProperty?n.setUnknownProperty(i,o):c&&c.watching[i]>0?(u=r?c.values[i]:n[i],o!==u&&(Ember.propertyWillChange(n,i),r?void 0!==u||i in n?c.values[i]=o:Ember.defineProperty(n,i,null,o):n[i]=o,Ember.propertyDidChange(n,i))):n[i]=o),o};Ember.config.overrideAccessors&&(Ember.set=i,Ember.config.overrideAccessors(),i=Ember.set),Ember.set=i,Ember.trySet=function(e,t,r){return i(e,t,r,!0)}}(),function(){var e=Ember.set,t=Ember.guidFor,r=Ember.ArrayPolyfills.indexOf,n=function(e){var t={};for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);return t},i=function(e,t){var r=e.keys.copy(),i=n(e.values);return t.keys=r,t.values=i,t.length=e.length,t},o=Ember.OrderedSet=function(){this.clear()};o.create=function(){return new o},o.prototype={clear:function(){this.presenceSet={},this.list=[]},add:function(e){var r=t(e),n=this.presenceSet,i=this.list;r in n||(n[r]=!0,i.push(e))},remove:function(e){var n=t(e),i=this.presenceSet,o=this.list;delete i[n];var a=r.call(o,e);a>-1&&o.splice(a,1)},isEmpty:function(){return 0===this.list.length},has:function(e){var r=t(e),n=this.presenceSet;return r in n},forEach:function(e,t){for(var r=this.toArray(),n=0,i=r.length;i>n;n++)e.call(t,r[n])},toArray:function(){return this.list.slice()},copy:function(){var e=new o;return e.presenceSet=n(this.presenceSet),e.list=this.toArray(),e}};var a=Ember.Map=function(){this.keys=Ember.OrderedSet.create(),this.values={}};a.create=function(){return new a},a.prototype={length:0,get:function(e){var r=this.values,n=t(e);return r[n]},set:function(r,n){var i=this.keys,o=this.values,a=t(r);i.add(r),o[a]=n,e(this,"length",i.list.length)},remove:function(r){var n=this.keys,i=this.values,o=t(r);return i.hasOwnProperty(o)?(n.remove(r),delete i[o],e(this,"length",n.list.length),!0):!1},has:function(e){var r=this.values,n=t(e);return r.hasOwnProperty(n)},forEach:function(e,r){var n=this.keys,i=this.values;n.forEach(function(n){var o=t(n);e.call(r,n,i[o])})},copy:function(){return i(this,new a)}};var s=Ember.MapWithDefault=function(e){a.call(this),this.defaultValue=e.defaultValue};s.create=function(e){return e?new s(e):new a},s.prototype=Ember.create(a.prototype),s.prototype.get=function(e){var t=this.has(e);if(t)return a.prototype.get.call(this,e);var r=this.defaultValue(e);return this.set(e,r),r},s.prototype.copy=function(){return i(this,new s({defaultValue:this.defaultValue}))}}(),function(){var e=Ember.META_KEY,t=Ember.meta,r=Ember.platform.defineProperty,n=Ember.ENV.MANDATORY_SETTER;Ember.Descriptor=function(){};var i=Ember.MANDATORY_SETTER_FUNCTION=function(){},o=Ember.DEFAULT_GETTER_FUNCTION=function(t){return function(){var r=this[e];return r&&r.values[t]}};Ember.defineProperty=function(e,a,s,u,c){var l,h,m,f;return c||(c=t(e)),l=c.descs,h=c.descs[a],m=c.watching[a]>0,h instanceof Ember.Descriptor&&h.teardown(e,a),s instanceof Ember.Descriptor?(f=s,l[a]=s,n&&m?r(e,a,{configurable:!0,enumerable:!0,writable:!0,value:void 0}):e[a]=void 0):(l[a]=void 0,null==s?(f=u,n&&m?(c.values[a]=u,r(e,a,{configurable:!0,enumerable:!0,set:i,get:o(a)})):e[a]=u):(f=s,r(e,a,s))),m&&Ember.overrideChains(e,a,c),e.didDefineProperty&&e.didDefineProperty(e,a,f),this}}(),function(){var e=Ember.get;Ember.getProperties=function(t){var r={},n=arguments,i=1;2===arguments.length&&"array"===Ember.typeOf(arguments[1])&&(i=0,n=arguments[1]);for(var o=n.length;o>i;i++)r[n[i]]=e(t,n[i]);return r}}(),function(){var e=Ember.changeProperties,t=Ember.set;Ember.setProperties=function(r,n){return e(function(){for(var e in n)n.hasOwnProperty(e)&&t(r,e,n[e])}),r}}(),function(){var e=Ember.meta,t=Ember.typeOf,r=Ember.ENV.MANDATORY_SETTER,n=Ember.platform.defineProperty;Ember.watchKey=function(i,o){if("length"!==o||"array"!==t(i)){var a=e(i),s=a.watching;s[o]?s[o]=(s[o]||0)+1:(s[o]=1,"function"==typeof i.willWatchProperty&&i.willWatchProperty(o),r&&o in i&&(a.values[o]=i[o],n(i,o,{configurable:!0,enumerable:!0,set:Ember.MANDATORY_SETTER_FUNCTION,get:Ember.DEFAULT_GETTER_FUNCTION(o)})))}},Ember.unwatchKey=function(t,i){var o=e(t),a=o.watching;1===a[i]?(a[i]=0,"function"==typeof t.didUnwatchProperty&&t.didUnwatchProperty(i),r&&i in t&&(n(t,i,{configurable:!0,enumerable:!0,writable:!0,value:o.values[i]}),delete o.values[i])):a[i]>1&&a[i]--}}(),function(){function e(e){return e.match(l)[0]}function t(e,t,r){if(e&&"object"==typeof e){var i=n(e),o=i.chainWatchers;i.hasOwnProperty("chainWatchers")||(o=i.chainWatchers={}),o[t]||(o[t]=[]),o[t].push(r),u(e,t)}}function r(e,t){if(!e)return void 0;var r=n(e,!1);if(r.proto===e)return void 0;if("@each"===t)return i(e,t);var o=r.descs[t];return o&&o._cacheable?t in r.cache?r.cache[t]:void 0:i(e,t)}var n=Ember.meta,i=Ember.get,o=Ember.normalizeTuple,a=Ember.ArrayPolyfills.forEach,s=Ember.warn,u=Ember.watchKey,c=Ember.unwatchKey,l=/^([^\.\*]+)/,h=[];Ember.flushPendingChains=function(){if(0!==h.length){var e=h;h=[],a.call(e,function(e){e[0].add(e[1])}),s("Watching an undefined global, Ember expects watched globals to be setup by the time the run loop is flushed, check for typos",0===h.length)}};var m=Ember.removeChainWatcher=function(e,t,r){if(e&&"object"==typeof e){var i=n(e,!1);if(i.hasOwnProperty("chainWatchers")){var o=i.chainWatchers;if(o[t]){o=o[t];for(var a=0,s=o.length;s>a;a++)o[a]===r&&o.splice(a,1)}c(e,t)}}},f=Ember._ChainNode=function(e,r,n){this._parent=e,this._key=r,this._watching=void 0===n,this._value=n,this._paths={},this._watching&&(this._object=e.value(),this._object&&t(this._object,this._key,this)),this._parent&&"@each"===this._parent._key&&this.value()},p=f.prototype;p.value=function(){if(void 0===this._value&&this._watching){var e=this._parent.value();this._value=r(e,this._key)}return this._value},p.destroy=function(){if(this._watching){var e=this._object;e&&m(e,this._key,this),this._watching=!1}},p.copy=function(e){var t,r=new f(null,null,e),n=this._paths;for(t in n)n[t]<=0||r.add(t);return r},p.add=function(t){var r,n,i,a,s;if(s=this._paths,s[t]=(s[t]||0)+1,r=this.value(),n=o(r,t),n[0]&&n[0]===r)t=n[1],i=e(t),t=t.slice(i.length+1);else{if(!n[0])return h.push([this,t]),n.length=0,void 0;a=n[0],i=t.slice(0,0-(n[1].length+1)),t=n[1]}n.length=0,this.chain(i,t,a)},p.remove=function(t){var r,n,i,a,s;s=this._paths,s[t]>0&&s[t]--,r=this.value(),n=o(r,t),n[0]===r?(t=n[1],i=e(t),t=t.slice(i.length+1)):(a=n[0],i=t.slice(0,0-(n[1].length+1)),t=n[1]),n.length=0,this.unchain(i,t)},p.count=0,p.chain=function(t,r,n){var i,o=this._chains;o||(o=this._chains={}),i=o[t],i||(i=o[t]=new f(this,t,n)),i.count++,r&&r.length>0&&(t=e(r),r=r.slice(t.length+1),i.chain(t,r))},p.unchain=function(t,r){var n=this._chains,i=n[t];r&&r.length>1&&(t=e(r),r=r.slice(t.length+1),i.unchain(t,r)),i.count--,i.count<=0&&(delete n[i._key],i.destroy())},p.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)},p.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))},p.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))},p.didChange=function(e){if(this._watching){var r=this._parent.value();r!==this._object&&(m(this._object,this._key,this),this._object=r,t(r,this._key,this)),this._value=void 0,this._parent&&"@each"===this._parent._key&&this.value()}var n=this._chains;if(n)for(var i in n)n.hasOwnProperty(i)&&n[i].didChange(e);null!==e&&this._parent&&this._parent.chainDidChange(this,this._key,1,e)},Ember.finishChains=function(e){var t=n(e,!1),r=t.chains;r&&(r.value()!==e&&(t.chains=r=r.copy(e)),r.didChange(null))}}(),function(){function e(e){var r=t(e),i=r.chains;return i?i.value()!==e&&(i=r.chains=i.copy(e)):i=r.chains=new n(null,null,e),i}var t=Ember.meta,r=Ember.typeOf,n=Ember._ChainNode;Ember.watchPath=function(n,i){if("length"!==i||"array"!==r(n)){var o=t(n),a=o.watching;a[i]?a[i]=(a[i]||0)+1:(a[i]=1,e(n).add(i))}},Ember.unwatchPath=function(r,n){var i=t(r),o=i.watching;1===o[n]?(o[n]=0,e(r).remove(n)):o[n]>1&&o[n]--}}(),function(){function e(e){return"*"===e||!h.test(e)}var t=Ember.meta,r=Ember.GUID_KEY,n=Ember.META_KEY,i=Ember.removeChainWatcher,o=Ember.watchKey,a=Ember.unwatchKey,s=Ember.watchPath,u=Ember.unwatchPath,c=Ember.typeOf,l=Ember.generateGuid,h=/[\.\*]/;Ember.watch=function(t,r){("length"!==r||"array"!==c(t))&&(e(r)?o(t,r):s(t,r))},Ember.isWatching=function(e,t){var r=e[n];return(r&&r.watching[t])>0},Ember.watch.flushPending=Ember.flushPendingChains,Ember.unwatch=function(t,r){("length"!==r||"array"!==c(t))&&(e(r)?a(t,r):u(t,r))},Ember.rewatch=function(e){var n=t(e,!1),i=n.chains;r in e&&!e.hasOwnProperty(r)&&l(e,"ember"),i&&i.value()!==e&&(n.chains=i.copy(e))};var m=[];Ember.destroy=function(e){var t,r,o,a,s=e[n];if(s&&(e[n]=null,t=s.chains))for(m.push(t);m.length>0;){if(t=m.pop(),r=t._chains)for(o in r)r.hasOwnProperty(o)&&m.push(r[o]);t._watching&&(a=t._object,a&&i(a,t._key,t))}}}(),function(){function e(e,t){var r=e[t];return r?e.hasOwnProperty(t)||(r=e[t]=f(r)):r=e[t]={},r}function t(t){return e(t,"deps")}function r(r,n,i,o){var a,s,u,c,l,h=r._dependentKeys;if(h)for(a=t(o),s=0,u=h.length;u>s;s++)c=h[s],l=e(a,c),l[i]=(l[i]||0)+1,p(n,c)}function n(r,n,i,o){var a,s,u,c,l,h=r._dependentKeys;if(h)for(a=t(o),s=0,u=h.length;u>s;s++)c=h[s],l=e(a,c),l[i]=(l[i]||0)-1,d(n,c)}function i(e,t){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)}function o(e){for(var t=0,r=e.length;r>t;t++)e[t].didChange(null)}function a(e,t){for(var r={},n=0;nt;t++)e.push(arguments[t]);return this._dependentKeys=e,this},b.meta=function(e){return 0===arguments.length?this._meta||{}:(this._meta=e,this)},b.didChange=function(e,t){if(this._cacheable&&this._suspended!==e){var r=h(e);t in r.cache&&(delete r.cache[t],n(this,e,t,r))}},b.get=function(e,t){var n,i,a,s;if(this._cacheable){if(a=h(e),i=a.cache,t in i)return i[t];n=i[t]=this.func.call(e,t),s=a.chainWatchers&&a.chainWatchers[t],s&&o(s),r(this,e,t,a)}else n=this.func.call(e,t);return n},b.set=function(e,t,n){var i,o,a,s=this._cacheable,u=this.func,c=h(e,s),l=c.watching[t],m=this._suspended,f=!1,p=c.cache;if(this._readOnly)throw new Error("Cannot Set: "+t+" on: "+e.toString());this._suspended=e;try{if(s&&p.hasOwnProperty(t)&&(o=p[t],f=!0),i=u.wrappedFunction?u.wrappedFunction.length:u.length,3===i)a=u.call(e,t,n,o);else{if(2!==i)return Ember.defineProperty(e,t,null,o),Ember.set(e,t,n),void 0;a=u.call(e,t,n)}if(f&&o===a)return;l&&Ember.propertyWillChange(e,t),f&&delete p[t],s&&(f||r(this,e,t,c),p[t]=a),l&&Ember.propertyDidChange(e,t)}finally{this._suspended=m}return a},b.teardown=function(e,t){var r=h(e);return t in r.cache&&n(this,e,t,r),this._cacheable&&delete r.cache[t],null},Ember.computed=function(e){var t;if(arguments.length>1&&(t=m.call(arguments,0,-1),e=m.call(arguments,-1)[0]),"function"!=typeof e)throw new Error("Computed Property declared without a property function");var r=new i(e);return t&&r.property.apply(r,t),r},Ember.cacheFor=function(e,t){var r=h(e,!1).cache;return r&&t in r?r[t]:void 0},s("empty",function(e){return Ember.isEmpty(c(this,e))}),s("notEmpty",function(e){return!Ember.isEmpty(c(this,e))}),s("none",function(e){return Ember.isNone(c(this,e))}),s("not",function(e){return!c(this,e)}),s("bool",function(e){return!!c(this,e)}),s("match",function(e,t){var r=c(this,e);return"string"==typeof r?!!r.match(t):!1}),s("equal",function(e,t){return c(this,e)===t}),s("gt",function(e,t){return c(this,e)>t}),s("gte",function(e,t){return c(this,e)>=t}),s("lt",function(e,t){return c(this,e)1?(l(this,e,r),r):c(this,e)})},Ember.computed.oneWay=function(e){return Ember.computed(e,function(){return c(this,e)})},Ember.computed.defaultTo=function(e){return Ember.computed(function(t,r,n){return 1===arguments.length?null!=n?n:c(this,e):null!=r?r:c(this,e)})}}(),function(){function e(e){return e+r}function t(e){return e+n}var r=":change",n=":before";Ember.addObserver=function(t,r,n,i){return Ember.addListener(t,e(r),n,i),Ember.watch(t,r),this},Ember.observersFor=function(t,r){return Ember.listenersFor(t,e(r))},Ember.removeObserver=function(t,r,n,i){return Ember.unwatch(t,r),Ember.removeListener(t,e(r),n,i),this},Ember.addBeforeObserver=function(e,r,n,i){return Ember.addListener(e,t(r),n,i),Ember.watch(e,r),this},Ember._suspendBeforeObserver=function(e,r,n,i,o){return Ember._suspendListener(e,t(r),n,i,o)},Ember._suspendObserver=function(t,r,n,i,o){return Ember._suspendListener(t,e(r),n,i,o)};var i=Ember.ArrayPolyfills.map;Ember._suspendBeforeObservers=function(e,r,n,o,a){var s=i.call(r,t);return Ember._suspendListeners(e,s,n,o,a)},Ember._suspendObservers=function(t,r,n,o,a){var s=i.call(r,e);return Ember._suspendListeners(t,s,n,o,a)},Ember.beforeObserversFor=function(e,r){return Ember.listenersFor(e,t(r))},Ember.removeBeforeObserver=function(e,r,n,i){return Ember.unwatch(e,r),Ember.removeListener(e,t(r),n,i),this}}(),function(){e("backburner/queue",["exports"],function(e){"use strict";function t(e,t,r){this.daq=e,this.name=t,this.options=r,this._queue=[]}t.prototype={daq:null,name:null,options:null,_queue:null,push:function(e,t,r,n){var i=this._queue;return i.push(e,t,r,n),{queue:this,target:e,method:t}},pushUnique:function(e,t,r,n){var i,o,a,s,u=this._queue;for(a=0,s=u.length;s>a;a+=4)if(i=u[a],o=u[a+1],i===e&&o===t)return u[a+2]=r,u[a+3]=n,{queue:this,target:e,method:t};return this._queue.push(e,t,r,n),{queue:this,target:e,method:t}},flush:function(){var e,t,r,n,i,o=this._queue,a=this.options,s=a&&a.before,u=a&&a.after,c=o.length; -for(c&&s&&s(),i=0;c>i;i+=4)e=o[i],t=o[i+1],r=o[i+2],n=o[i+3],r&&r.length>0?t.apply(e,r):t.call(e);c&&u&&u(),o.length>c?(this._queue=o.slice(c),this.flush()):this._queue.length=0},cancel:function(e){var t,r,n,i,o=this._queue;for(n=0,i=o.length;i>n;n+=4)if(t=o[n],r=o[n+1],t===e.target&&r===e.method)return o.splice(n,4),!0;if(o=this._queueBeingFlushed)for(n=0,i=o.length;i>n;n+=4)if(t=o[n],r=o[n+1],t===e.target&&r===e.method)return o[n+1]=null,!0}},e.Queue=t}),e("backburner/deferred_action_queues",["backburner/queue","exports"],function(e,t){"use strict";function r(e,t){var r=this.queues={};this.queueNames=e=e||[];for(var n,o=0,a=e.length;a>o;o++)n=e[o],r[n]=new i(this,n,t[n])}function n(e,t){for(var r,n,i=0,o=t;o>=i;i++)if(r=e.queueNames[i],n=e.queues[r],n._queue.length)return i;return-1}var i=e.Queue;r.prototype={queueNames:null,queues:null,schedule:function(e,t,r,n,i,o){var a=this.queues,s=a[e];if(!s)throw new Error("You attempted to schedule an action in a queue ("+e+") that doesn't exist");return i?s.pushUnique(t,r,n,o):s.push(t,r,n,o)},flush:function(){for(var e,t,r,i,o=this.queues,a=this.queueNames,s=0,u=a.length;u>s;){e=a[s],t=o[e],r=t._queueBeingFlushed=t._queue.slice(),t._queue=[];var c,l,h,m,f=t.options,p=f&&f.before,d=f&&f.after,b=0,E=r.length;for(E&&p&&p();E>b;)c=r[b],l=r[b+1],h=r[b+2],m=r[b+3],"string"==typeof l&&(l=c[l]),l&&(h&&h.length>0?l.apply(c,h):l.call(c)),b+=4;t._queueBeingFlushed=null,E&&d&&d(),-1===(i=n(this,s))?s++:s=i}}},t.DeferredActionQueues=r}),e("backburner",["backburner/deferred_action_queues","exports"],function(e,t){"use strict";function r(e,t){this.queueNames=e,this.options=t||{},this.options.defaultQueue||(this.options.defaultQueue=e[0]),this.instanceStack=[]}function n(e){e.begin(),a=d.setTimeout(function(){a=null,e.end()})}function i(e){var t,r,n,o,a=+new Date;e.run(function(){for(n=0,o=p.length;o>n&&(t=p[n],!(t>a));n+=2);for(r=p.splice(0,n),n=1,o=r.length;o>n;n+=2)e.schedule(e.options.defaultQueue,null,r[n])}),p.length&&(s=d.setTimeout(function(){i(e),s=null,u=null},p[0]-a),u=p[0])}function o(e,t){for(var r,n=-1,i=0,o=f.length;o>i;i++)if(r=f[i],r[0]===e&&r[1]===t){n=i;break}return n}var a,s,u,c=e.DeferredActionQueues,l=[].slice,h=[].pop,m=[],f=[],p=[],d=this;r.prototype={queueNames:null,options:null,currentInstance:null,instanceStack:null,begin:function(){var e=this.options&&this.options.onBegin,t=this.currentInstance;t&&this.instanceStack.push(t),this.currentInstance=new c(this.queueNames,this.options),e&&e(this.currentInstance,t)},end:function(){var e=this.options&&this.options.onEnd,t=this.currentInstance,r=null;try{t.flush()}finally{this.currentInstance=null,this.instanceStack.length&&(r=this.instanceStack.pop(),this.currentInstance=r),e&&e(t,r)}},run:function(e,t){var r;this.begin(),t||(t=e,e=null),"string"==typeof t&&(t=e[t]);var n=!1;try{r=arguments.length>2?t.apply(e,l.call(arguments,2)):t.call(e)}finally{n||(n=!0,this.end())}return r},defer:function(e,t,r){r||(r=t,t=null),"string"==typeof r&&(r=t[r]);var i=this.DEBUG?(new Error).stack:void 0,o=arguments.length>3?l.call(arguments,3):void 0;return this.currentInstance||n(this),this.currentInstance.schedule(e,t,r,o,!1,i)},deferOnce:function(e,t,r){r||(r=t,t=null),"string"==typeof r&&(r=t[r]);var i=this.DEBUG?(new Error).stack:void 0,o=arguments.length>3?l.call(arguments,3):void 0;return this.currentInstance||n(this),this.currentInstance.schedule(e,t,r,o,!0,i)},setTimeout:function(){var e=this,t=h.call(arguments),r=arguments[0],n=arguments[1],o=+new Date+t;n||(n=r,r=null),"string"==typeof n&&(n=r[n]);var a,c;arguments.length>2?(c=l.call(arguments,2),a=function(){n.apply(r,c)}):a=function(){n.call(r)};var m,f;for(m=0,f=p.length;f>m&&!(ou?a:(s&&(clearTimeout(s),s=null),s=d.setTimeout(function(){i(e),s=null,u=null},t),u=o,a)},throttle:function(e,t){for(var r,n=this,i=arguments,o=h.call(i),a=0,s=m.length;s>a;a++)if(r=m[a],r[0]===e&&r[1]===t)return;var u=d.setTimeout(function(){n.run.apply(n,i);for(var o=-1,a=0,s=m.length;s>a;a++)if(r=m[a],r[0]===e&&r[1]===t){o=a;break}o>-1&&m.splice(o,1)},o);m.push([e,t,u])},debounce:function(e,t){var r,n,i,a=this,s=arguments,u=h.call(s);"number"==typeof u?(r=u,u=!1):r=h.call(s),n=o(e,t),-1!==n&&(i=f[n],f.splice(n,1),clearTimeout(i[2]));var c=d.setTimeout(function(){u||a.run.apply(a,s),n=o(e,t),n&&f.splice(n,1)},r);u&&-1===n&&a.run.apply(a,s),f.push([e,t,c])},cancelTimers:function(){var e,t;for(e=0,t=m.length;t>e;e++)clearTimeout(m[e][2]);for(m=[],e=0,t=f.length;t>e;e++)clearTimeout(f[e][2]);f=[],s&&(clearTimeout(s),s=null),p=[],a&&(clearTimeout(a),a=null)},hasTimers:function(){return!!p.length||a},cancel:function(e){if(e&&"object"==typeof e&&e.queue&&e.method)return e.queue.cancel(e);if("function"==typeof e)for(var t=0,r=p.length;r>t;t+=2)if(p[t+1]===e)return p.splice(t,2),!0}},r.prototype.schedule=r.prototype.defer,r.prototype.scheduleOnce=r.prototype.deferOnce,r.prototype.later=r.prototype.setTimeout,t.Backburner=r})}(),function(){function e(){!Ember.run.currentRunLoop}var r=function(e){Ember.run.currentRunLoop=e},n=function(e,t){Ember.run.currentRunLoop=t},i=t("backburner").Backburner,o=new i(["sync","actions","destroy"],{sync:{before:Ember.beginPropertyChanges,after:Ember.endPropertyChanges},defaultQueue:"actions",onBegin:r,onEnd:n}),a=[].slice;Ember.run=function(){var e;if(Ember.onerror)try{e=o.run.apply(o,arguments)}catch(t){Ember.onerror(t)}else e=o.run.apply(o,arguments);return e},Ember.run.join=function(){if(!Ember.run.currentRunLoop)return Ember.run.apply(Ember.run,arguments);var e=a.call(arguments);e.unshift("actions"),Ember.run.schedule.apply(Ember.run,e)},Ember.run.backburner=o,Ember.run,Ember.run.currentRunLoop=null,Ember.run.queues=o.queueNames,Ember.run.begin=function(){o.begin()},Ember.run.end=function(){o.end()},Ember.run.schedule=function(){e(),o.schedule.apply(o,arguments)},Ember.run.hasScheduledTimers=function(){return o.hasTimers()},Ember.run.cancelTimers=function(){o.cancelTimers()},Ember.run.sync=function(){o.currentInstance&&o.currentInstance.queues.sync.flush()},Ember.run.later=function(){return o.later.apply(o,arguments)},Ember.run.once=function(){e();var t=a.call(arguments);return t.unshift("actions"),o.scheduleOnce.apply(o,t)},Ember.run.scheduleOnce=function(){return e(),o.scheduleOnce.apply(o,arguments)},Ember.run.next=function(){var e=a.call(arguments);return e.push(1),o.later.apply(o,e)},Ember.run.cancel=function(e){return o.cancel(e)},Ember.run.debounce=function(){return o.debounce.apply(o,arguments)},Ember.run.throttle=function(){return o.throttle.apply(o,arguments)}}(),function(){function e(e,t){return r(o(t)?Ember.lookup:e,t)}function t(e,t){for(var r in t)t.hasOwnProperty(r)&&(e[r]=t[r])}Ember.LOG_BINDINGS=!1||!!Ember.ENV.LOG_BINDINGS;var r=Ember.get,n=(Ember.set,Ember.guidFor),i=/^([A-Z$]|([0-9][A-Z$]))/,o=Ember.isGlobalPath=function(e){return i.test(e)},a=function(e,t){this._direction="fwd",this._from=t,this._to=e,this._directionMap=Ember.Map.create()};a.prototype={copy:function(){var e=new a(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<"+n(this)+">("+this._from+" -> "+this._to+")"+e},connect:function(t){var r=this._from,n=this._to;return Ember.trySet(t,n,e(t,r)),Ember.addObserver(t,r,this,this.fromDidChange),this._oneWay||Ember.addObserver(t,n,this,this.toDidChange),this._readyToSync=!0,this},disconnect:function(e){var t=!this._oneWay;return Ember.removeObserver(e,this._from,this,this.fromDidChange),t&&Ember.removeObserver(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||(Ember.run.schedule("sync",this,this._sync,e),r.set(e,t)),"back"===n&&"fwd"===t&&r.set(e,"fwd")},_sync:function(t){var n=Ember.LOG_BINDINGS;if(!t.isDestroyed&&this._readyToSync){var i=this._directionMap,o=i.get(t),a=this._from,s=this._to;if(i.remove(t),"fwd"===o){var u=e(t,this._from);n&&Ember.Logger.log(" ",this.toString(),"->",u,t),this._oneWay?Ember.trySet(t,s,u):Ember._suspendObserver(t,s,this,this.toDidChange,function(){Ember.trySet(t,s,u)})}else if("back"===o){var c=r(t,this._to);n&&Ember.Logger.log(" ",this.toString(),"<-",c,t),Ember._suspendObserver(t,a,this,this.fromDidChange,function(){Ember.trySet(Ember.isGlobalPath(a)?Ember.lookup:t,a,c)})}}}},t(a,{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)}}),Ember.Binding=a,Ember.bind=function(e,t,r){return new Ember.Binding(t,r).connect(e)},Ember.oneWay=function(e,t,r){return new Ember.Binding(t,r).oneWay().connect(e)}}(),function(){function e(e){var t=Ember.meta(e,!0),r=t.mixins;return r?t.hasOwnProperty("mixins")||(r=t.mixins=x(r)):r=t.mixins={},r}function t(e,t){return t&&t.length>0&&(e.mixins=C.call(t,function(e){if(e instanceof y)return e;var t=new y;return t.properties=e,t})),e}function r(e){return"function"==typeof e&&e.isMethod!==!1&&e!==Boolean&&e!==Object&&e!==Number&&e!==Array&&e!==Date&&e!==String}function n(e,t){var r;return t instanceof y?(r=S(t),e[r]?T:(e[r]=t,t.properties)):t}function i(e,t,r,n){var i;return i=r[e]||n[e],t[e]&&(i=i?i.concat(t[e]):t[e]),i}function o(e,t,r,n,i){var o;return void 0===n[t]&&(o=i[t]),o=o||e.descs[t],o&&o instanceof Ember.ComputedProperty?(r=x(r),r.func=Ember.wrap(r.func,o.func),r):r}function a(e,t,r,n,i){var o;return void 0===i[t]&&(o=n[t]),o=o||e[t],"function"!=typeof o?r:Ember.wrap(r,o)}function s(e,t,r,n){var i=n[t]||e[t];return i?"function"==typeof i.concat?i.concat(r):Ember.makeArray(i).concat(r):Ember.makeArray(r).slice()}function u(e,t,n,i){var o=i[t]||e[t];if(!o)return n;var s=Ember.merge({},o);for(var u in n)if(n.hasOwnProperty(u)){var c=n[u];s[u]=r(c)?a(e,u,c,o,{}):c}return s}function c(e,t,n,i,c,l,h,m){if(n instanceof Ember.Descriptor){if(n===w&&c[t])return T;n.func&&(n=o(i,t,n,l,c)),c[t]=n,l[t]=void 0}else h&&O.call(h,t)>=0||"concatenatedProperties"===t||"mergedProperties"===t?n=s(e,t,n,l):m&&O.call(m,t)>=0?n=u(e,t,n,l):r(n)&&(n=a(e,t,n,l,c)),c[t]=void 0,l[t]=n}function l(e,t,r,o,a,s){function u(e){delete r[e],delete o[e]}for(var h,m,f,p,d,b,E=0,v=e.length;v>E;E++)if(h=e[E],m=n(t,h),m!==T)if(m){b=Ember.meta(a),a.willMergeMixin&&a.willMergeMixin(m),p=i("concatenatedProperties",m,o,a),d=i("mergedProperties",m,o,a);for(f in m)m.hasOwnProperty(f)&&(s.push(f),c(a,f,m[f],b,r,o,p,d));m.hasOwnProperty("toString")&&(a.toString=m.toString)}else h.mixins&&(l(h.mixins,t,r,o,a,s),h._without&&A.call(h._without,u))}function h(e,t,r,n){if(N.test(t)){var i=n.bindings;i?n.hasOwnProperty("bindings")||(i=n.bindings=x(n.bindings)):i=n.bindings={},i[t]=r}}function m(e,t){var r,n,i,o=t.bindings;if(o){for(r in o)n=o[r],n&&(i=r.slice(0,-7),n instanceof Ember.Binding?(n=n.copy(),n.to(i)):n=new Ember.Binding(i,n),n.connect(e),e[r]=n);t.bindings={}}}function f(e,t){return m(e,t||Ember.meta(e)),e}function p(e,t,r,n,i){var o,a=t.methodName;return n[a]||i[a]?(o=i[a],t=n[a]):r.descs[a]?(t=r.descs[a],o=void 0):(t=void 0,o=e[a]),{desc:t,value:o}}function d(e,t,r,n,i){var o=r[n];if(o)for(var a=0,s=o.length;s>a;a++)Ember[i](e,o[a],null,t)}function b(e,t,r){var n=e[t];"function"==typeof n&&(d(e,t,n,"__ember_observesBefore__","removeBeforeObserver"),d(e,t,n,"__ember_observes__","removeObserver"),d(e,t,n,"__ember_listens__","removeListener")),"function"==typeof r&&(d(e,t,r,"__ember_observesBefore__","addBeforeObserver"),d(e,t,r,"__ember_observes__","addObserver"),d(e,t,r,"__ember_listens__","addListener"))}function E(t,r,n){var i,o,a,s={},u={},c=Ember.meta(t),m=[];l(r,e(t),s,u,t,m);for(var d=0,E=m.length;E>d;d++)if(i=m[d],"constructor"!==i&&u.hasOwnProperty(i)&&(a=s[i],o=u[i],a!==w)){for(;a&&a instanceof _;){var v=p(t,a,c,s,u);a=v.desc,o=v.value}(void 0!==a||void 0!==o)&&(b(t,i,o),h(t,i,o,c),V(t,i,a,o,c))}return n||f(t,c),t}function v(e,t,r){var n=S(e);if(r[n])return!1;if(r[n]=!0,e===t)return!0;for(var i=e.mixins,o=i?i.length:0;--o>=0;)if(v(i[o],t,r))return!0;return!1}function g(e,t,r){if(!r[S(t)])if(r[S(t)]=!0,t.properties){var n=t.properties;for(var i in n)n.hasOwnProperty(i)&&(e[i]=!0)}else t.mixins&&A.call(t.mixins,function(t){g(e,t,r)})}var y,w,_,C=Ember.ArrayPolyfills.map,O=Ember.ArrayPolyfills.indexOf,A=Ember.ArrayPolyfills.forEach,P=[].slice,x=Ember.create,V=Ember.defineProperty,S=Ember.guidFor,T={},N=Ember.IS_BINDING=/^.+Binding$/;Ember.mixin=function(e){var t=P.call(arguments,1);return E(e,t,!1),e},Ember.Mixin=function(){return t(this,arguments)},y=Ember.Mixin,y.prototype={properties:null,mixins:null,ownerConstructor:null},y._apply=E,y.applyPartial=function(e){var t=P.call(arguments,1);return E(e,t,!0)},y.finishPartial=f,Ember.anyUnprocessedMixins=!1,y.create=function(){Ember.anyUnprocessedMixins=!0;var e=this;return t(new e,arguments)};var R=y.prototype;R.reopen=function(){var e,t;this.properties?(e=y.create(),e.properties=this.properties,delete this.properties,this.mixins=[e]):this.mixins||(this.mixins=[]);var r,n=arguments.length,i=this.mixins;for(r=0;n>r;r++)e=arguments[r],e instanceof y?i.push(e):(t=y.create(),t.properties=e,i.push(t));return this},R.apply=function(e){return E(e,[this],!1)},R.applyPartial=function(e){return E(e,[this],!0)},R.detect=function(e){if(!e)return!1;if(e instanceof y)return v(e,this,{});var t=Ember.meta(e,!1).mixins;return t?!!t[S(this)]:!1},R.without=function(){var e=new y(this);return e._without=P.call(arguments),e},R.keys=function(){var e={},t={},r=[];g(e,this,t);for(var n in e)e.hasOwnProperty(n)&&r.push(n);return r},y.mixins=function(e){var t=Ember.meta(e,!1).mixins,r=[];if(!t)return r;for(var n in t){var i=t[n];i.properties||r.push(i)}return r},w=new Ember.Descriptor,w.toString=function(){return"(Required Property)"},Ember.required=function(){return w},_=function(e){this.methodName=e},_.prototype=new Ember.Descriptor,Ember.alias=function(e){return new _(e)},Ember.aliasMethod=function(e){return new _(e)},Ember.observer=function(e){var t=P.call(arguments,1);return e.__ember_observes__=t,e},Ember.immediateObserver=function(){for(var e=0,t=arguments.length;t>e;e++)arguments[e];return Ember.observer.apply(this,arguments)},Ember.beforeObserver=function(e){var t=P.call(arguments,1);return e.__ember_observesBefore__=t,e}}(),function(){var e=Ember.EnumerableUtils.forEach,t=Ember.EnumerableUtils.indexOf;Ember.libraries=function(){var r=[],n=0,i=function(e){for(var t=0;tr;r++)if(e[r][0]===t)return r;return-1},n=function(e){var t=e._promiseCallbacks;return t||(t=e._promiseCallbacks={}),t},i={mixin:function(e){return e.on=this.on,e.off=this.off,e.trigger=this.trigger,e},on:function(e,t,i){var o,a,s=n(this);for(e=e.split(/\s+/),i=i||this;a=e.shift();)o=s[a],o||(o=s[a]=[]),-1===r(o,t)&&o.push([t,i])},off:function(e,t){var i,o,a,s=n(this);for(e=e.split(/\s+/);o=e.shift();)t?(i=s[o],a=r(i,t),-1!==a&&i.splice(a,1)):s[o]=[]},trigger:function(e,r){var i,o,a,s,u,c=n(this);if(i=c[e])for(var l=0;l2?e(Array.prototype.slice.call(arguments,1)):e(n)}}function i(e){return function(){var t,r,i=Array.prototype.slice.call(arguments),s=this,u=new o(function(e,n){t=e,r=n});return a(i).then(function(i){i.push(n(t,r));try{e.apply(s,i)}catch(o){r(o)}}),u}}var o=e.Promise,a=t.all;r.denodeify=i}),e("rsvp/promise",["rsvp/config","rsvp/events","exports"],function(e,t,r){"use strict";function n(e){return i(e)||"object"==typeof e&&null!==e}function i(e){return"function"==typeof e}function o(e){l.onerror&&l.onerror(e.detail)}function a(e,t){e===t?u(e,t):s(e,t)||u(e,t)}function s(e,t){var r,o=null;try{if(e===t)throw new TypeError("A promises callback cannot return that same promise.");if(n(t)&&(o=t.then,i(o)))return o.call(t,function(n){return r?!0:(r=!0,t!==n?a(e,n):u(e,n),void 0)},function(t){return r?!0:(r=!0,c(e,t),void 0)}),!0}catch(s){return c(e,s),!0}return!1}function u(e,t){l.async(function(){e.trigger("promise:resolved",{detail:t}),e.isFulfilled=!0,e.fulfillmentValue=t})}function c(e,t){l.async(function(){e.trigger("promise:failed",{detail:t}),e.isRejected=!0,e.rejectedReason=t})}var l=e.config,h=t.EventTarget,m=function(e){var t=this,r=!1;if("function"!=typeof e)throw new TypeError("You must pass a resolver function as the sole argument to the promise constructor");if(!(t instanceof m))return new m(e);var n=function(e){r||(r=!0,a(t,e))},i=function(e){r||(r=!0,c(t,e))};this.on("promise:resolved",function(e){this.trigger("success",{detail:e.detail})},this),this.on("promise:failed",function(e){this.trigger("error",{detail:e.detail})},this),this.on("error",o);try{e(n,i)}catch(s){i(s)}},f=function(e,t,r,n){var o,u,l,h,m=i(r);if(m)try{o=r(n.detail),l=!0}catch(f){h=!0,u=f}else o=n.detail,l=!0;s(t,o)||(m&&l?a(t,o):h?c(t,u):"resolve"===e?a(t,o):"reject"===e&&c(t,o))};m.prototype={constructor:m,isRejected:void 0,isFulfilled:void 0,rejectedReason:void 0,fulfillmentValue:void 0,then:function(e,t){this.off("error",o);var r=new this.constructor(function(){});return this.isFulfilled&&l.async(function(t){f("resolve",r,e,{detail:t.fulfillmentValue})},this),this.isRejected&&l.async(function(e){f("reject",r,t,{detail:e.rejectedReason})},this),this.on("promise:resolved",function(t){f("resolve",r,e,t)}),this.on("promise:failed",function(e){f("reject",r,t,e)}),r},fail:function(e){return this.then(null,e)}},h.mixin(m.prototype),r.Promise=m}),e("rsvp/reject",["rsvp/promise","exports"],function(e,t){"use strict";function r(e){return new n(function(t,r){r(e)})}var n=e.Promise;t.reject=r}),e("rsvp/resolve",["rsvp/promise","exports"],function(e,t){"use strict";function r(e){return new n(function(t){t(e)})}var n=e.Promise;t.resolve=r}),e("rsvp/rethrow",["exports"],function(e){"use strict";function t(e){throw r.setTimeout(function(){throw e}),e}var r="undefined"==typeof global?this:global;e.rethrow=t}),e("rsvp",["rsvp/events","rsvp/promise","rsvp/node","rsvp/all","rsvp/hash","rsvp/rethrow","rsvp/defer","rsvp/config","rsvp/resolve","rsvp/reject","exports"],function(e,t,r,n,i,o,a,s,u,c,l){"use strict";function h(e,t){g[e]=t}var m=e.EventTarget,f=t.Promise,p=r.denodeify,d=n.all,b=i.hash,E=o.rethrow,v=a.defer,g=s.config,y=u.resolve,w=c.reject;l.Promise=f,l.EventTarget=m,l.all=d,l.hash=b,l.rethrow=E,l.defer=v,l.denodeify=p,l.configure=h,l.resolve=y,l.reject=w})}(),function(){Ember.MODEL_FACTORY_INJECTIONS=!1||!!Ember.ENV.MODEL_FACTORY_INJECTIONS,e("container",[],function(){function e(e){this.parent=e,this.dict={}}function t(t){this.parent=t,this.children=[],this.resolver=t&&t.resolver||function(){},this.registry=new e(t&&t.registry),this.cache=new e(t&&t.cache),this.factoryCache=new e(t&&t.cache),this.typeInjections=new e(t&&t.typeInjections),this.injections={},this.factoryTypeInjections=new e(t&&t.factoryTypeInjections),this.factoryInjections={},this._options=new e(t&&t._options),this._typeOptions=new e(t&&t._typeOptions)}function r(e){throw new Error(e+" is not currently supported on child containers")}function n(e,t){var r=o(e,t,"singleton");return r!==!1}function i(e,t){var r={};if(!t)return r;for(var n,i,o=0,a=t.length;a>o;o++){if(n=t[o],i=e.lookup(n.fullName),void 0===i)throw new Error("Attempting to inject an unknown injection: `"+n.fullName+"`");r[n.property]=i}return r}function o(e,t,r){var n=e._options.get(t);if(n&&void 0!==n[r])return n[r];var i=t.split(":")[0];return n=e._typeOptions.get(i),n?n[r]:void 0}function a(e,t){var r,n=e.normalize(t),i=e.resolve(n),o=e.factoryCache,a=t.split(":")[0];if(void 0!==i){if(o.has(t))return o.get(t);if(!i||"function"!=typeof i.extend||!Ember.MODEL_FACTORY_INJECTIONS&&"model"===a)return i;var c=s(e,t),l=u(e,t);return l._toString=e.makeToString(i,t),r=i.extend(c),r.reopenClass(l),o.set(t,r),r}}function s(e,t){var r=t.split(":"),n=r[0],o=[];return o=o.concat(e.typeInjections.get(n)||[]),o=o.concat(e.injections[t]||[]),o=i(e,o),o._debugContainerKey=t,o.container=e,o}function u(e,t){var r=t.split(":"),n=r[0],o=[];return o=o.concat(e.factoryTypeInjections.get(n)||[]),o=o.concat(e.factoryInjections[t]||[]),o=i(e,o),o._debugContainerKey=t,o}function c(e,t){var r=a(e,t);return o(e,t,"instantiate")===!1?r:r?"function"==typeof r.extend?r.create():r.create(s(e,t)):void 0}function l(e,t){e.cache.eachLocal(function(r,n){o(e,r,"instantiate")!==!1&&t(n)})}function h(e){e.cache.eachLocal(function(t,r){o(e,t,"instantiate")!==!1&&r.destroy()}),e.cache.dict={}}function m(e,t,r,n){var i=e.get(t);i||(i=[],e.set(t,i)),i.push({property:r,fullName:n})}function f(e,t,r,n){var i=e[t]=e[t]||[];i.push({property:r,fullName:n})}return e.prototype={parent:null,dict:null,get:function(e){var t=this.dict;return t.hasOwnProperty(e)?t[e]:this.parent?this.parent.get(e):void 0},set:function(e,t){this.dict[e]=t},remove:function(e){delete this.dict[e]},has:function(e){var t=this.dict;return t.hasOwnProperty(e)?!0:this.parent?this.parent.has(e):!1},eachLocal:function(e,t){var r=this.dict;for(var n in r)r.hasOwnProperty(n)&&e.call(t,n,r[n])}},t.prototype={parent:null,children:null,resolver:null,registry:null,cache:null,typeInjections:null,injections:null,_options:null,_typeOptions:null,child:function(){var e=new t(this);return this.children.push(e),e},set:function(e,t,r){e[t]=r},register:function(e,t,r,n){var i;if(-1!==e.indexOf(":")?(n=r,r=t,i=e):i=e+":"+t,void 0===r)throw new TypeError("Attempting to register an unknown factory: `"+i+"`");var o=this.normalize(i);this.registry.set(o,r),this._options.set(o,n||{})},unregister:function(e){var t=this.normalize(e);this.registry.remove(t),this.cache.remove(t),this.factoryCache.remove(t),this._options.remove(t)},resolve:function(e){return this.resolver(e)||this.registry.get(e)},describe:function(e){return e},normalize:function(e){return e},makeToString:function(e){return e.toString()},lookup:function(e,t){if(e=this.normalize(e),t=t||{},this.cache.has(e)&&t.singleton!==!1)return this.cache.get(e);var r=c(this,e);return void 0!==r?(n(this,e)&&t.singleton!==!1&&this.cache.set(e,r),r):void 0},lookupFactory:function(e){return a(this,e)},has:function(e){return this.cache.has(e)?!0:!!a(this,e)},optionsForType:function(e,t){this.parent&&r("optionsForType"),this._typeOptions.set(e,t)},options:function(e,t){this.optionsForType(e,t)},typeInjection:function(e,t,n){this.parent&&r("typeInjection"),m(this.typeInjections,e,t,n)},injection:function(e,t,n){return this.parent&&r("injection"),-1===e.indexOf(":")?this.typeInjection(e,t,n):(f(this.injections,e,t,n),void 0)},factoryTypeInjection:function(e,t,n){this.parent&&r("factoryTypeInjection"),m(this.factoryTypeInjections,e,t,n)},factoryInjection:function(e,t,n){return this.parent&&r("injection"),-1===e.indexOf(":")?this.factoryTypeInjection(e,t,n):(f(this.factoryInjections,e,t,n),void 0)},destroy:function(){this.isDestroyed=!0;for(var e=0,t=this.children.length;t>e;e++)this.children[e].destroy();this.children=[],l(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++)h(this.children[e]);h(this)}},t})}(),function(){function e(r,n,i,o){var a,s,u;if("object"!=typeof r||null===r)return r;if(n&&(s=t(i,r))>=0)return o[s];if("array"===Ember.typeOf(r)){if(a=r.slice(),n)for(s=a.length;--s>=0;)a[s]=e(a[s],n,i,o)}else if(Ember.Copyable&&Ember.Copyable.detect(r))a=r.copy(n,i,o);else{a={};for(u in r)r.hasOwnProperty(u)&&"__"!==u.substring(0,2)&&(a[u]=n?e(r[u],n,i,o):r[u])}return n&&(i.push(r),o.push(a)),a}var t=Ember.EnumerableUtils.indexOf;if(Ember.compare=function o(e,t){if(e===t)return 0;var r=Ember.typeOf(e),n=Ember.typeOf(t),i=Ember.Comparable;if(i){if("instance"===r&&i.detect(e.constructor))return e.constructor.compare(e,t);if("instance"===n&&i.detect(t.constructor))return 1-t.constructor.compare(t,e)}var a=Ember.ORDER_DEFINITION_MAPPING;if(!a){var s=Ember.ORDER_DEFINITION;a=Ember.ORDER_DEFINITION_MAPPING={};var u,c;for(u=0,c=s.length;c>u;++u)a[s[u]]=u;delete Ember.ORDER_DEFINITION}var l=a[r],h=a[n];if(h>l)return-1;if(l>h)return 1;switch(r){case"boolean":case"number":return t>e?-1:e>t?1:0;case"string":var m=e.localeCompare(t);return 0>m?-1:m>0?1:0;case"array":for(var f=e.length,p=t.length,d=Math.min(f,p),b=0,E=0;0===b&&d>E;)b=o(e[E],t[E]),E++;return 0!==b?b:p>f?-1:f>p?1:0;case"instance":return Ember.Comparable&&Ember.Comparable.detect(e)?e.compare(e,t):0;case"date":var v=e.getTime(),g=t.getTime();return g>v?-1:v>g?1:0;default:return 0}},Ember.copy=function(t,r){return"object"!=typeof t||null===t?t:Ember.Copyable&&Ember.Copyable.detect(t)?t.copy(r):e(t,r,r?[]:null,r?[]:null)},Ember.inspect=function(e){var t=Ember.typeOf(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"===Ember.typeOf(r)&&(r="function() { ... }"),n.push(i+": "+r)}return"{"+n.join(", ")+"}"},Ember.isEqual=function(e,t){return e&&"function"==typeof e.isEqual?e.isEqual(t):e===t},Ember.ORDER_DEFINITION=Ember.ENV.ORDER_DEFINITION||["undefined","null","boolean","number","string","array","object","instance","function","class","date"],Ember.keys=Object.keys,!Ember.keys||Ember.create.isSimulated){var r=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","valueOf","toLocaleString","toString"],n=function(e,r,n){"__"!==n.substring(0,2)&&"_super"!==n&&(t(r,n)>=0||e.hasOwnProperty(n)&&r.push(n))};Ember.keys=function(e){var t,i=[];for(t in e)n(e,i,t);for(var o=0,a=r.length;a>o;o++)t=r[o],n(e,i,t);return i}}var i=["description","fileName","lineNumber","message","name","number","stack"];Ember.Error=function(){for(var e=Error.apply(this,arguments),t=0;tu;u++){var c=this.nextObject(u,a,s);r.call(i,c,u,this),a=c}return a=null,s=t(s),this},getEach:function(e){return this.mapBy(e)},setEach:function(e,t){return this.forEach(function(r){i(r,e,t)})},map:function(e,t){var r=Ember.A();return this.forEach(function(n,i,o){r[i]=e.call(t,n,i,o)}),r},mapBy:function(e){return this.map(function(t){return n(t,e)})},mapProperty:Ember.aliasMethod("mapBy"),filter:function(e,t){var r=Ember.A();return this.forEach(function(n,i,o){e.call(t,n,i,o)&&r.push(n)}),r},reject:function(e,t){return this.filter(function(){return!e.apply(t,arguments)})},filterBy:function(){return this.filter(r.apply(this,arguments))},filterProperty:Ember.aliasMethod("filterBy"),rejectBy:function(e,t){var r=function(r){return n(r,e)===t},i=function(t){return!!n(t,e)},o=2===arguments.length?r:i;return this.reject(o)},rejectProperty:Ember.aliasMethod("rejectBy"),find:function(r,i){var o=n(this,"length");void 0===i&&(i=null);for(var a,s,u=null,c=!1,l=e(),h=0;o>h&&!c;h++)a=this.nextObject(h,u,l),(c=r.call(i,a,h,this))&&(s=a),u=a;return a=u=null,l=t(l),s},findBy:function(){return this.find(r.apply(this,arguments))},findProperty:Ember.aliasMethod("findBy"),every:function(e,t){return!this.find(function(r,n,i){return!e.call(t,r,n,i)})},everyBy:function(){return this.every(r.apply(this,arguments))},everyProperty:Ember.aliasMethod("everyBy"),any:function(e,t){return!!this.find(function(r,n,i){return!!e.call(t,r,n,i)})},some:Ember.aliasMethod("any"),anyBy:function(){return this.any(r.apply(this,arguments))},someProperty:Ember.aliasMethod("anyBy"),reduce:function(e,t,r){if("function"!=typeof e)throw new TypeError;var n=t;return this.forEach(function(t,i){n=e.call(null,n,t,i,this,r)},this),n},invoke:function(e){var t,r=Ember.A();return arguments.length>1&&(t=o.call(arguments,1)),this.forEach(function(n,i){var o=n&&n[e];"function"==typeof o&&(r[i]=t?o.apply(n,t):o.call(n))},this),r},toArray:function(){var e=Ember.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=Ember.A();return this.forEach(function(r){r!==e&&(t[t.length]=r)}),t},uniq:function(){var e=Ember.A();return this.forEach(function(t){a(e,t)<0&&e.push(t)}),e},"[]":Ember.computed(function(){return this}),addEnumerableObserver:function(e,t){var r=t&&t.willChange||"enumerableWillChange",i=t&&t.didChange||"enumerableDidChange",o=n(this,"hasEnumerableObservers");return o||Ember.propertyWillChange(this,"hasEnumerableObservers"),Ember.addListener(this,"@enumerable:before",e,r),Ember.addListener(this,"@enumerable:change",e,i),o||Ember.propertyDidChange(this,"hasEnumerableObservers"),this},removeEnumerableObserver:function(e,t){var r=t&&t.willChange||"enumerableWillChange",i=t&&t.didChange||"enumerableDidChange",o=n(this,"hasEnumerableObservers");return o&&Ember.propertyWillChange(this,"hasEnumerableObservers"),Ember.removeListener(this,"@enumerable:before",e,r),Ember.removeListener(this,"@enumerable:change",e,i),o&&Ember.propertyDidChange(this,"hasEnumerableObservers"),this},hasEnumerableObservers:Ember.computed(function(){return Ember.hasListeners(this,"@enumerable:change")||Ember.hasListeners(this,"@enumerable:before") -}),enumerableContentWillChange:function(e,t){var r,i,o;return r="number"==typeof e?e:e?n(e,"length"):e=-1,i="number"==typeof t?t:t?n(t,"length"):t=-1,o=0>i||0>r||0!==i-r,-1===e&&(e=null),-1===t&&(t=null),Ember.propertyWillChange(this,"[]"),o&&Ember.propertyWillChange(this,"length"),Ember.sendEvent(this,"@enumerable:before",[this,e,t]),this},enumerableContentDidChange:function(e,t){var r,i,o;return r="number"==typeof e?e:e?n(e,"length"):e=-1,i="number"==typeof t?t:t?n(t,"length"):t=-1,o=0>i||0>r||0!==i-r,-1===e&&(e=null),-1===t&&(t=null),Ember.sendEvent(this,"@enumerable:change",[this,e,t]),o&&Ember.propertyDidChange(this,"length"),Ember.propertyDidChange(this,"[]"),this}}),Ember.FEATURES.isEnabled("ember-runtime-sortBy")&&Ember.Enumerable.reopen({sortBy:function(){var e=arguments;return this.toArray().sort(function(t,r){for(var i=0;it||t>=e(this,"length")?void 0:e(this,t)},objectsAt:function(e){var t=this;return r(e,function(e){return t.objectAt(e)})},nextObject:function(e){return this.objectAt(e)},"[]":Ember.computed(function(t,r){return void 0!==r&&this.replace(0,e(this,"length"),r),this}),firstObject:Ember.computed(function(){return this.objectAt(0)}),lastObject:Ember.computed(function(){return this.objectAt(e(this,"length")-1)}),contains:function(e){return this.indexOf(e)>=0},slice:function(r,n){var i=Ember.A(),o=e(this,"length");for(t(r)&&(r=0),(t(n)||n>o)&&(n=o),0>r&&(r=o+r),0>n&&(n=o+n);n>r;)i[i.length]=this.objectAt(r++);return i},indexOf:function(t,r){var n,i=e(this,"length");for(void 0===r&&(r=0),0>r&&(r+=i),n=r;i>n;n++)if(this.objectAt(n)===t)return n;return-1},lastIndexOf:function(t,r){var n,i=e(this,"length");for((void 0===r||r>=i)&&(r=i-1),0>r&&(r+=i),n=r;n>=0;n--)if(this.objectAt(n)===t)return n;return-1},addArrayObserver:function(t,r){var n=r&&r.willChange||"arrayWillChange",i=r&&r.didChange||"arrayDidChange",o=e(this,"hasArrayObservers");return o||Ember.propertyWillChange(this,"hasArrayObservers"),Ember.addListener(this,"@array:before",t,n),Ember.addListener(this,"@array:change",t,i),o||Ember.propertyDidChange(this,"hasArrayObservers"),this},removeArrayObserver:function(t,r){var n=r&&r.willChange||"arrayWillChange",i=r&&r.didChange||"arrayDidChange",o=e(this,"hasArrayObservers");return o&&Ember.propertyWillChange(this,"hasArrayObservers"),Ember.removeListener(this,"@array:before",t,n),Ember.removeListener(this,"@array:change",t,i),o&&Ember.propertyDidChange(this,"hasArrayObservers"),this},hasArrayObservers:Ember.computed(function(){return Ember.hasListeners(this,"@array:change")||Ember.hasListeners(this,"@array:before")}),arrayContentWillChange:function(t,r,n){void 0===t?(t=0,r=n=-1):(void 0===r&&(r=-1),void 0===n&&(n=-1)),Ember.isWatching(this,"@each")&&e(this,"@each"),Ember.sendEvent(this,"@array:before",[this,t,r,n]);var i,o;if(t>=0&&r>=0&&e(this,"hasEnumerableObservers")){i=[],o=t+r;for(var a=t;o>a;a++)i.push(this.objectAt(a))}else i=r;return this.enumerableContentWillChange(i,n),this},arrayContentDidChange:function(t,r,i){void 0===t?(t=0,r=i=-1):(void 0===r&&(r=-1),void 0===i&&(i=-1));var o,a;if(t>=0&&i>=0&&e(this,"hasEnumerableObservers")){o=[],a=t+i;for(var s=t;a>s;s++)o.push(this.objectAt(s))}else o=i;this.enumerableContentDidChange(r,o),Ember.sendEvent(this,"@array:change",[this,t,r,i]);var u=e(this,"length"),c=n(this,"firstObject"),l=n(this,"lastObject");return this.objectAt(0)!==c&&(Ember.propertyWillChange(this,"firstObject"),Ember.propertyDidChange(this,"firstObject")),this.objectAt(u-1)!==l&&(Ember.propertyWillChange(this,"lastObject"),Ember.propertyDidChange(this,"lastObject")),this},"@each":Ember.computed(function(){return this.__each||(this.__each=new Ember.EachProxy(this)),this.__each})})}(),function(){function e(e,t){return Ember.FEATURES.isEnabled("reduceComputedSelf")&&"@self"===t?e:c(e,t)}function t(e,t,r){this.callbacks=e,this.cp=t,this.instanceMeta=r,this.dependentKeysByGuid={},this.trackedArraysByGuid={},this.changedItems={}}function r(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 n(e,t,r,n,i,o){var a={arrayChanged:e,index:r,item:t,propertyName:n,property:i};return o&&(a.previousValues=o),a}function i(e,t,r,i,o){w(e,function(a,s){o.setValue(t.addedItem.call(this,o.getValue(),a,n(e,a,s,i,r),o.sugarMeta))},this)}function o(e,t){var r;e._callbacks(),e._hasInstanceMeta(this,t)?(r=e._instanceMeta(this,t),r.setValue(e.resetValue(r.getValue()))):r=e._instanceMeta(this,t),e.options.initialize&&e.options.initialize.call(this,r.getValue(),{property:e,propertyName:t},r.sugarMeta)}function a(e,t,r){this.context=e,this.propertyName=t,this.cache=h(e).cache,this.dependentArrays={},this.sugarMeta={},this.initialValue=r}function s(t){var r=this;this.options=t,this._instanceMetas={},this._dependentKeys=null,this._itemPropertyKeys={},this._previousItemPropertyKeys={},this.readOnly(),this.cacheable(),this.recomputeOnce=function(e){Ember.run.once(this,n,e)};var n=function(t){var n=(r._dependentKeys,r._instanceMeta(this,t)),a=r._callbacks();o.call(this,r,t),w(r._dependentKeys,function(t){var i=e(this,t),o=n.dependentArrays[t];i===o?r._previousItemPropertyKeys[t]&&(delete r._previousItemPropertyKeys[t],n.dependentArraysObserver.setupPropertyObservers(t,r._itemPropertyKeys[t])):(n.dependentArrays[t]=i,o&&n.dependentArraysObserver.teardownObservers(o,t),i&&n.dependentArraysObserver.setupObservers(i,t))},this),w(r._dependentKeys,function(o){var s=e(this,o);s&&i.call(this,s,a,r,t,n)},this)};this.func=function(e){return n.call(this,e),r._instanceMeta(this,e).getValue()}}function u(e){return e}var c=Ember.get,l=(Ember.set,Ember.guidFor),h=Ember.meta,m=Ember.propertyWillChange,f=Ember.propertyDidChange,p=Ember.addBeforeObserver,d=Ember.removeBeforeObserver,b=Ember.addObserver,E=Ember.removeObserver,v=Ember.ComputedProperty,g=[].slice,y=Ember.create,w=Ember.EnumerableUtils.forEach,_=/^(.*)\.@each\.(.*)/,C=/(.*\.@each){2,}/;t.prototype={setValue:function(e){this.instanceMeta.setValue(e,!0)},getValue:function(){return this.instanceMeta.getValue()},setupObservers:function(e,t){this.dependentKeysByGuid[l(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[l(e)],this.teardownPropertyObservers(t,r),e.removeArrayObserver(this,{willChange:"dependentArrayWillChange",didChange:"dependentArrayDidChange"})},setupPropertyObservers:function(t,r){var n=e(this.instanceMeta.context,t),i=e(n,"length"),o=new Array(i);this.resetTransformations(t,o),w(n,function(e,i){var a=this.createPropertyObserverContext(n,i,this.trackedArraysByGuid[t]);o[i]=a,w(r,function(t){p(e,t,this,a.beforeObserver),b(e,t,this,a.observer)},this)},this)},teardownPropertyObservers:function(e,t){var r,n,i,o=this,a=this.trackedArraysByGuid[e];a&&a.apply(function(e,a,s){s!==Ember.TrackedArray.DELETE&&w(e,function(e){e.destroyed=!0,r=e.beforeObserver,n=e.observer,i=e.item,w(t,function(e){d(i,e,o,r),E(i,e,o,n)})})})},createPropertyObserverContext:function(e,t,n){var i=new r(e,t,n);return this.createPropertyObserver(i),i},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 Ember.TrackedArray(t)},addTransformation:function(e,t,r){var n=this.trackedArraysByGuid[e];n&&n.addItems(t,r)},removeTransformation:function(e,t,r){var n=this.trackedArraysByGuid[e];return n?n.removeItems(t,r):[]},updateIndexes:function(t,r){var n=e(r,"length");t.apply(function(e,t,r){r!==Ember.TrackedArray.DELETE&&(r!==Ember.TrackedArray.RETAIN||e.length!==n||0!==t)&&w(e,function(e,r){e.index=r+t})})},dependentArrayWillChange:function(e,t,r){function i(e){c[u].destroyed=!0,d(a,e,this,c[u].beforeObserver),E(a,e,this,c[u].observer)}var o,a,s,u,c,h=this.callbacks.removedItem,m=l(e),f=this.dependentKeysByGuid[m],p=this.cp._itemPropertyKeys[f]||[];for(c=this.removeTransformation(f,t,r),u=r-1;u>=0;--u)s=t+u,a=e.objectAt(s),w(p,i,this),o=n(e,a,s,this.instanceMeta.propertyName,this.cp),this.setValue(h.call(this.instanceMeta.context,this.getValue(),a,o,this.instanceMeta.sugarMeta))},dependentArrayDidChange:function(e,t,r,i){var o,a,s=this.callbacks.addedItem,u=l(e),c=this.dependentKeysByGuid[u],h=new Array(i),m=this.cp._itemPropertyKeys[c];w(e.slice(t,t+i),function(r,i){m&&(a=h[i]=this.createPropertyObserverContext(e,t+i,this.trackedArraysByGuid[c]),w(m,function(e){p(r,e,this,a.beforeObserver),b(r,e,this,a.observer)},this)),o=n(e,r,t+i,this.instanceMeta.propertyName,this.cp),this.setValue(s.call(this.instanceMeta.context,this.getValue(),r,o,this.instanceMeta.sugarMeta))},this),this.addTransformation(c,t,h)},itemPropertyWillChange:function(t,r,n,i){var o=l(t);this.changedItems[o]||(this.changedItems[o]={array:n,observerContext:i,obj:t,previousValues:{}}),this.changedItems[o].previousValues[r]=e(t,r)},itemPropertyDidChange:function(){this.flushChanges()},flushChanges:function(){var e,t,r,i=this.changedItems;for(e in i)t=i[e],t.observerContext.destroyed||(this.updateIndexes(t.observerContext.trackedArray,t.observerContext.dependentArray),r=n(t.array,t.obj,t.observerContext.index,this.instanceMeta.propertyName,this.cp,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={}}},a.prototype={getValue:function(){return this.propertyName in this.cache?this.cache[this.propertyName]:this.initialValue},setValue:function(e,t){if(void 0!==e){var r=t&&e!==this.cache[this.propertyName];r&&m(this.context,this.propertyName),this.cache[this.propertyName]=e,r&&f(this.context,this.propertyName)}else delete this.cache[this.propertyName]}},Ember.ReduceComputedProperty=s,s.prototype=y(v.prototype),s.prototype._callbacks=function(){if(!this.callbacks){var e=this.options;this.callbacks={removedItem:e.removedItem||u,addedItem:e.addedItem||u}}return this.callbacks},s.prototype._hasInstanceMeta=function(e,t){var r=l(e),n=r+":"+t;return!!this._instanceMetas[n]},s.prototype._instanceMeta=function(e,r){var n=l(e),i=n+":"+r,o=this._instanceMetas[i];return o||(o=this._instanceMetas[i]=new a(e,r,this.initialValue()),o.dependentArraysObserver=new t(this._callbacks(),this,o,e,r,o.sugarMeta)),o},s.prototype.initialValue=function(){switch(typeof this.options.initialValue){case"undefined":throw new Error("reduce computed properties require an initial value: did you forget to pass one to Ember.reduceComputed?");case"function":return this.options.initialValue();default:return this.options.initialValue}},s.prototype.resetValue=function(){return this.initialValue()},s.prototype.itemPropertyKey=function(e,t){this._itemPropertyKeys[e]=this._itemPropertyKeys[e]||[],this._itemPropertyKeys[e].push(t)},s.prototype.clearItemPropertyKeys=function(e){this._itemPropertyKeys[e]&&(this._previousItemPropertyKeys[e]=this._itemPropertyKeys[e],this._itemPropertyKeys[e]=[])},s.prototype.property=function(){var e,t,r,n=this,i=(g.call(arguments),[]);return w(g.call(arguments),function(o){if(C.test(o))throw new Error("Nested @each properties not supported: "+o);(e=_.exec(o))?(t=e[1],r=e[2],n.itemPropertyKey(t,r),i.push(t)):i.push(o)}),v.prototype.property.apply(this,i)},Ember.reduceComputed=function(e){var t;if(arguments.length>1&&(t=g.call(arguments,0,-1),e=g.call(arguments,-1)[0]),"object"!=typeof e)throw new Error("Reduce Computed Property declared without an options hash");if(Ember.isNone(e.initialValue))throw new Error("Reduce Computed Property declared without an initial value");var r=new s(e);return t&&r.property.apply(r,t),r}}(),function(){function e(){var e=this;return t.apply(this,arguments),this.func=function(t){return function(r){return e._hasInstanceMeta(this,r)||i(e._dependentKeys,function(t){Ember.addObserver(this,t,function(){e.recomputeOnce.call(this,r)})},this),t.apply(this,arguments)}}(this.func),this}var t=Ember.ReduceComputedProperty,r=[].slice,n=Ember.create,i=Ember.EnumerableUtils.forEach;Ember.ArrayComputedProperty=e,e.prototype=n(t.prototype),e.prototype.initialValue=function(){return Ember.A()},e.prototype.resetValue=function(e){return e.clear(),e},Ember.arrayComputed=function(t){var n;if(arguments.length>1&&(n=r.call(arguments,0,-1),t=r.call(arguments,-1)[0]),"object"!=typeof t)throw new Error("Array Computed Property declared without an options hash");var i=new e(t);return n&&i.property.apply(i,n),i}}(),function(){function e(e,n,i,o){function a(e){return Ember.ObjectProxy.detectInstance(e)?r(t(e,"content")):r(e)}var s,u,c,l,h;return arguments.length<4&&(o=t(e,"length")),arguments.length<3&&(i=0),i===o?i:(s=i+Math.floor((o-i)/2),u=e.objectAt(s),l=a(u),h=a(n),l===h?s:(c=this.order(u,n),0===c&&(c=h>l?-1:1),0>c?this.binarySearch(e,n,s+1,o):c>0?this.binarySearch(e,n,i,s):s))}var t=Ember.get,r=(Ember.set,Ember.guidFor),n=Ember.merge,i=[].slice,o=Ember.EnumerableUtils.forEach,a=Ember.EnumerableUtils.map;Ember.computed.max=function(e){return Ember.reduceComputed.call(null,e,{initialValue:-1/0,addedItem:function(e,t){return Math.max(e,t)},removedItem:function(e,t){return e>t?e:void 0}})},Ember.computed.min=function(e){return Ember.reduceComputed.call(null,e,{initialValue:1/0,addedItem:function(e,t){return Math.min(e,t)},removedItem:function(e,t){return t>e?e:void 0}})},Ember.computed.map=function(e,t){var r={addedItem:function(e,r,n){var i=t.call(this,r);return e.insertAt(n.index,i),e},removedItem:function(e,t,r){return e.removeAt(r.index,1),e}};return Ember.arrayComputed(e,r)},Ember.computed.mapBy=function(e,r){var n=function(e){return t(e,r)};return Ember.computed.map(e+".@each."+r,n)},Ember.computed.mapProperty=Ember.computed.mapBy,Ember.computed.filter=function(e,t){var r={initialize:function(e,t,r){r.filteredArrayIndexes=new Ember.SubArray},addedItem:function(e,r,n,i){var o=!!t.call(this,r),a=i.filteredArrayIndexes.addItem(n.index,o);return o&&e.insertAt(a,r),e},removedItem:function(e,t,r,n){var i=n.filteredArrayIndexes.removeItem(r.index);return i>-1&&e.removeAt(i),e}};return Ember.arrayComputed(e,r)},Ember.computed.filterBy=function(e,r,n){var i;return i=2===arguments.length?function(e){return t(e,r)}:function(e){return t(e,r)===n},Ember.computed.filter(e+".@each."+r,i)},Ember.computed.filterProperty=Ember.computed.filterBy,Ember.computed.uniq=function(){var e=i.call(arguments);return e.push({initialize:function(e,t,r){r.itemCounts={}},addedItem:function(e,t,n,i){var o=r(t);return i.itemCounts[o]?++i.itemCounts[o]:i.itemCounts[o]=1,e.addObject(t),e},removedItem:function(e,t,n,i){var o=r(t),a=i.itemCounts;return 0===--a[o]&&e.removeObject(t),e}}),Ember.arrayComputed.apply(null,e)},Ember.computed.union=Ember.computed.uniq,Ember.computed.intersect=function(){var e=function(e){return a(e.property._dependentKeys,function(e){return r(e)})},t=i.call(arguments);return t.push({initialize:function(e,t,r){r.itemCounts={}},addedItem:function(t,n,i,o){var a=r(n),s=(e(i),r(i.arrayChanged)),u=i.property._dependentKeys.length,c=o.itemCounts;return c[a]||(c[a]={}),void 0===c[a][s]&&(c[a][s]=0),1===++c[a][s]&&u===Ember.keys(c[a]).length&&t.addObject(n),t},removedItem:function(t,n,i,o){var a,s=r(n),u=(e(i),r(i.arrayChanged)),c=(i.property._dependentKeys.length,o.itemCounts);return void 0===c[s][u]&&(c[s][u]=0),0===--c[s][u]&&(delete c[s][u],a=Ember.keys(c[s]).length,0===a&&delete c[s],t.removeObject(n)),t}}),Ember.arrayComputed.apply(null,t)},Ember.computed.setDiff=function(e,r){if(2!==arguments.length)throw new Error("setDiff requires exactly two dependent arrays.");return Ember.arrayComputed.call(null,e,r,{addedItem:function(n,i,o){var a=t(this,e),s=t(this,r);return o.arrayChanged===a?s.contains(i)||n.addObject(i):n.removeObject(i),n},removedItem:function(n,i,o){var a=t(this,e),s=t(this,r);return o.arrayChanged===s?a.contains(i)&&n.addObject(i):n.removeObject(i),n}})},Ember.computed.sort=function(r,i){var a,s;return"function"==typeof i?a=function(t,r,n){n.order=i,n.binarySearch=e}:(s=i,a=function(n,i,a){function u(){var e,n,u,l=t(this,s),h=a.sortProperties=[],m=a.sortPropertyAscending={};i.property.clearItemPropertyKeys(r),o(l,function(t){-1!==(n=t.indexOf(":"))?(e=t.substring(0,n),u="desc"!==t.substring(n+1).toLowerCase()):(e=t,u=!0),h.push(e),m[e]=u,i.property.itemPropertyKey(r,e)}),l.addObserver("@each",this,c)}function c(){Ember.run.once(this,l,i.propertyName)}function l(e){u.call(this),i.property.recomputeOnce.call(this,e)}Ember.addObserver(this,s,c),u.call(this),a.order=function(e,r){for(var n,i,o,a=0;an;n++){var o=Ember.String.camelize(t[n]);r.push(o.charAt(0).toUpperCase()+o.substr(1))}return r.join(".")},underscore:function(e){return e.replace(i,"$1_$2").replace(o,"_").toLowerCase()},capitalize:function(e){return e.charAt(0).toUpperCase()+e.substr(1)}},Ember.FEATURES.isEnabled("string-humanize")&&(Ember.String.humanize=function(e){return e.replace(/_id$/,"").replace(/_/g," ").replace(/^\w/g,function(e){return e.toUpperCase()})})}(),function(){var e=Ember.String.fmt,t=Ember.String.w,r=Ember.String.loc,n=Ember.String.camelize,i=Ember.String.decamelize,o=Ember.String.dasherize,a=Ember.String.underscore,s=Ember.String.capitalize,u=Ember.String.classify;if(Ember.FEATURES.isEnabled("string-humanize"))var c=Ember.String.humanize;(Ember.EXTEND_PROTOTYPES===!0||Ember.EXTEND_PROTOTYPES.String)&&(String.prototype.fmt=function(){return e(this,arguments)},String.prototype.w=function(){return t(this)},String.prototype.loc=function(){return r(this,arguments)},String.prototype.camelize=function(){return n(this)},String.prototype.decamelize=function(){return i(this)},String.prototype.dasherize=function(){return o(this)},String.prototype.underscore=function(){return a(this)},String.prototype.classify=function(){return u(this)},String.prototype.capitalize=function(){return s(this)},Ember.FEATURES.isEnabled("string-humanize")&&(String.prototype.humanize=function(){return c(this)}))}(),function(){var e=Array.prototype.slice;(Ember.EXTEND_PROTOTYPES===!0||Ember.EXTEND_PROTOTYPES.Function)&&(Function.prototype.property=function(){var e=Ember.computed(this);return e.property.apply(e,arguments)},Function.prototype.observes=function(){return this.__ember_observes__=e.call(arguments),this},Function.prototype.observesImmediately=function(){for(var e=0,t=arguments.length;t>e;e++)arguments[e];return this.observes.apply(this,arguments)},Function.prototype.observesBefore=function(){return this.__ember_observesBefore__=e.call(arguments),this},Function.prototype.on=function(){var t=e.call(arguments);return this.__ember_listens__=t,this})}(),function(){Ember.Comparable=Ember.Mixin.create({compare:Ember.required(Function)})}(),function(){var e=Ember.get;Ember.set,Ember.Copyable=Ember.Mixin.create({copy:Ember.required(Function),frozenCopy:function(){if(Ember.Freezable&&Ember.Freezable.detect(this))return e(this,"isFrozen")?this:this.copy().freeze();throw new Error(Ember.String.fmt("%@ does not support freezing",[this]))}})}(),function(){var e=Ember.get,t=Ember.set;Ember.Freezable=Ember.Mixin.create({isFrozen:!1,freeze:function(){return e(this,"isFrozen")?this:(t(this,"isFrozen",!0),this)}}),Ember.FROZEN_ERROR="Frozen object cannot be modified."}(),function(){var e=Ember.EnumerableUtils.forEach;Ember.MutableEnumerable=Ember.Mixin.create(Ember.Enumerable,{addObject:Ember.required(Function),addObjects:function(t){return Ember.beginPropertyChanges(this),e(t,function(e){this.addObject(e)},this),Ember.endPropertyChanges(this),this},removeObject:Ember.required(Function),removeObjects:function(t){return Ember.beginPropertyChanges(this),e(t,function(e){this.removeObject(e)},this),Ember.endPropertyChanges(this),this}})}(),function(){var e="Index out of range",t=[],r=Ember.get;Ember.set,Ember.MutableArray=Ember.Mixin.create(Ember.Array,Ember.MutableEnumerable,{replace:Ember.required(),clear:function(){var e=r(this,"length");return 0===e?this:(this.replace(0,e,t),this)},insertAt:function(t,n){if(t>r(this,"length"))throw new Error(e);return this.replace(t,0,[n]),this},removeAt:function(n,i){if("number"==typeof n){if(0>n||n>=r(this,"length"))throw new Error(e);void 0===i&&(i=1),this.replace(n,i,t)}return this},pushObject:function(e){return this.insertAt(r(this,"length"),e),e},pushObjects:function(e){if(!Ember.Enumerable.detect(e)&&!Ember.isArray(e))throw new TypeError("Must pass Ember.Enumerable to Ember.MutableArray#pushObjects");return this.replace(r(this,"length"),0,e),this},popObject:function(){var e=r(this,"length");if(0===e)return null;var t=this.objectAt(e-1);return this.removeAt(e-1,1),t},shiftObject:function(){if(0===r(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=r(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=r(this,"length");return this.replace(0,t,e),this},removeObject:function(e){for(var t=r(this,"length")||0;--t>=0;){var n=this.objectAt(t);n===e&&this.removeAt(t)}return this},addObject:function(e){return this.contains(e)||this.pushObject(e),this}})}(),function(){var e=Ember.get,t=Ember.set,r=Array.prototype.slice,n=Ember.getProperties;Ember.Observable=Ember.Mixin.create({get:function(t){return e(this,t)},getProperties:function(){return n.apply(null,[this].concat(r.call(arguments)))},set:function(e,r){return t(this,e,r),this},setProperties:function(e){return Ember.setProperties(this,e)},beginPropertyChanges:function(){return Ember.beginPropertyChanges(),this},endPropertyChanges:function(){return Ember.endPropertyChanges(),this},propertyWillChange:function(e){return Ember.propertyWillChange(this,e),this},propertyDidChange:function(e){return Ember.propertyDidChange(this,e),this},notifyPropertyChange:function(e){return this.propertyWillChange(e),this.propertyDidChange(e),this},addBeforeObserver:function(e,t,r){Ember.addBeforeObserver(this,e,t,r)},addObserver:function(e,t,r){Ember.addObserver(this,e,t,r)},removeObserver:function(e,t,r){Ember.removeObserver(this,e,t,r)},hasObserverFor:function(e){return Ember.hasListeners(this,e+":change")},getWithDefault:function(e,t){return Ember.getWithDefault(this,e,t)},incrementProperty:function(r,n){return Ember.isNone(n)&&(n=1),t(this,r,(e(this,r)||0)+n),e(this,r)},decrementProperty:function(r,n){return Ember.isNone(n)&&(n=1),t(this,r,(e(this,r)||0)-n),e(this,r)},toggleProperty:function(r){return t(this,r,!e(this,r)),e(this,r)},cacheFor:function(e){return Ember.cacheFor(this,e)},observersForKey:function(e){return Ember.observersFor(this,e)}})}(),function(){var e=Ember.get;Ember.set,Ember.TargetActionSupport=Ember.Mixin.create({target:null,action:null,actionContext:null,targetObject:Ember.computed(function(){var t=e(this,"target");if("string"===Ember.typeOf(t)){var r=e(this,t);return void 0===r&&(r=e(Ember.lookup,t)),r}return t}).property("target"),actionContextObject:Ember.computed(function(){var t=e(this,"actionContext");if("string"===Ember.typeOf(t)){var r=e(this,t);return void 0===r&&(r=e(Ember.lookup,t)),r}return t}).property("actionContext"),triggerAction:function(t){t=t||{};var r=t.action||e(this,"action"),n=t.target||e(this,"targetObject"),i=t.actionContext;if("undefined"==typeof i&&(i=e(this,"actionContextObject")||this),n&&r){var o;return o=n.send?n.send.apply(n,[r,i]):n[r].apply(n,[i]),o!==!1&&(o=!0),o}return!1}})}(),function(){Ember.Evented=Ember.Mixin.create({on:function(e,t,r){return Ember.addListener(this,e,t,r),this},one:function(e,t,r){return r||(r=t,t=null),Ember.addListener(this,e,t,r,!0),this},trigger:function(e){var t,r,n=[];for(t=1,r=arguments.length;r>t;t++)n.push(arguments[t]);Ember.sendEvent(this,e,n)},off:function(e,t,r){return Ember.removeListener(this,e,t,r),this},has:function(e){return Ember.hasListeners(this,e)}})}(),function(){var e=t("rsvp");e.configure("async",function(e,t){Ember.run.schedule("actions",t,e,t)});var r=Ember.get;Ember.DeferredMixin=Ember.Mixin.create({then:function(e,t){function n(t){return t===o?e(a):e(t)}var i,o,a;return a=this,i=r(this,"_deferred"),o=i.promise,o.then(e&&n,t)},resolve:function(e){var t,n;t=r(this,"_deferred"),n=t.promise,e===this?t.resolve(n):t.resolve(e)},reject:function(e){r(this,"_deferred").reject(e)},_deferred:Ember.computed(function(){return e.defer()})})}(),function(){var e=Ember.get;Ember.ActionHandler=Ember.Mixin.create({mergedProperties:["_actions"],willMergeMixin:function(e){e.actions&&!e._actions&&(e._actions=Ember.merge(e._actions||{},e.actions),delete e.actions)},send:function(t){var r,n=[].slice.call(arguments,1);if(this._actions&&this._actions[t]){if(this._actions[t].apply(this,n)!==!0)return}else if(this.deprecatedSend&&this.deprecatedSendHandles&&this.deprecatedSendHandles(t)&&this.deprecatedSend.apply(this,[].slice.call(arguments))!==!0)return;(r=e(this,"target"))&&r.send.apply(r,arguments)}})}(),function(){function e(e,r){r.then(function(r){return t(e,"isFulfilled",!0),t(e,"content",r),r},function(r){t(e,"isRejected",!0),t(e,"reason",r)}).fail(i)}var t=Ember.set,r=Ember.get,n=Ember.RSVP.resolve,i=Ember.RSVP.rethrow,o=Ember.computed.not,a=Ember.computed.or;Ember.PromiseProxyMixin=Ember.Mixin.create({reason:null,isPending:o("isSettled").readOnly(),isSettled:a("isRejected","isFulfilled").readOnly(),isRejected:!1,isFulfilled:!1,promise:Ember.computed(function(t,r){if(2===arguments.length)return r=n(r),e(this,r),r;throw new Error("PromiseProxy's promise must be set")}),then:function(e,t){return r(this,"promise").then(e,t)}})}(),function(){function e(e,t,r){this.operation=e,this.count=t,this.items=r}function t(e,t,r,n){this.operation=e,this.index=t,this.split=r,this.rangeStart=n}var r=Ember.get,n=Ember.EnumerableUtils.forEach,i="r",o="i",a="d";Ember.TrackedArray=function(t){arguments.length<1&&(t=[]);var n=r(t,"length");this._content=n?[new e(i,n,t)]:[]},Ember.TrackedArray.RETAIN=i,Ember.TrackedArray.INSERT=o,Ember.TrackedArray.DELETE=a,Ember.TrackedArray.prototype={addItems:function(t,n){var i,a,s=r(n,"length"),u=this._findArrayOperation(t),c=u.operation,l=u.index,h=u.rangeStart;a=new e(o,s,n),c?u.split?(this._split(l,t-h,a),i=l+1):(this._content.splice(l,0,a),i=l):(this._content.push(a),i=l),this._composeInsert(i)},removeItems:function(t,r){var n,i,o=this._findArrayOperation(t),s=(o.operation,o.index),u=o.rangeStart;return n=new e(a,r),o.split?(this._split(s,t-u,n),i=s+1):(this._content.splice(s,0,n),i=s),this._composeDelete(i)},apply:function(t){var r=[],o=0;n(this._content,function(e){t(e.items,o,e.operation),e.operation!==a&&(o+=e.count,r=r.concat(e.items))}),this._content=[new e(i,r.length,r)]},_findArrayOperation:function(e){var r,n,i,o,s,u=!1;for(r=o=0,n=this._content.length;n>r;++r)if(i=this._content[r],i.operation!==a){if(s=o+i.count-1,e===o)break;if(e>o&&s>=e){u=!0;break}o=s+1}return new t(i,r,u,o)},_split:function(t,r,n){var i=this._content[t],o=i.items.slice(r),a=new e(i.operation,o.length,o);i.count=r,i.items=i.items.slice(0,r),this._content.splice(t+1,0,n,a)},_composeInsert:function(e){var t=this._content[e],r=this._content[e-1],n=this._content[e+1],i=r&&r.operation,a=n&&n.operation;i===o?(r.count+=t.count,r.items=r.items.concat(t.items),a===o?(r.count+=n.count,r.items=r.items.concat(n.items),this._content.splice(e,2)):this._content.splice(e,1)):a===o&&(t.count+=n.count,t.items=t.items.concat(n.items),this._content.splice(e+1,1))},_composeDelete:function(e){var t,r,n,i=this._content[e],s=i.count,u=this._content[e-1],c=u&&u.operation,l=[];c===a&&(i=u,e-=1);for(var h=e+1;s>0;++h)t=this._content[h],r=t.operation,n=t.count,r!==a?(n>s?(l=l.concat(t.items.splice(0,s)),t.count-=s,h-=1,n=s,s=0):(l=l.concat(t.items),s-=n),r===o&&(i.count-=n)):i.count+=n;return i.count>0?this._content.splice(e+1,h-1-e):this._content.splice(e,1),l}}}(),function(){function e(e,t){this.type=e,this.count=t}var t=(Ember.get,Ember.EnumerableUtils.forEach),r="r",n="f";Ember.SubArray=function(t){arguments.length<1&&(t=0),this._operations=t>0?[new e(r,t)]:[]},Ember.SubArray.prototype={addItem:function(t,i){var o=-1,a=i?r:n,s=this;return this._findOperation(t,function(n,u,c,l,h){var m,f;a===n.type?++n.count:t===c?s._operations.splice(u,0,new e(a,1)):(m=new e(a,1),f=new e(n.type,l-t+1),n.count=t-c,s._operations.splice(u+1,0,m,f)),i&&(o=n.type===r?h+(t-c):h),s._composeAt(u)},function(t){s._operations.push(new e(a,1)),i&&(o=t),s._composeAt(s._operations.length-1)}),o},removeItem:function(e){var t=-1,n=this;return this._findOperation(e,function(i,o,a,s,u){i.type===r&&(t=u+(e-a)),i.count>1?--i.count:(n._operations.splice(o,1),n._composeAt(o))}),t},_findOperation:function(e,t,n){var i,o,a,s,u,c=0;for(i=s=0,o=this._operations.length;o>i;s=u+1,++i){if(a=this._operations[i],u=s+a.count-1,e>=s&&u>=e)return t(a,i,s,u,c),void 0;a.type===r&&(c+=a.count)}n(c)},_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)),eb;b++){var w=f[b];if("object"===Ember.typeOf(w))for(var _=Ember.keys(w),C=0,O=_.length;O>C;C++){var A=_[C];if(w.hasOwnProperty(A)){var P=w[A],x=Ember.IS_BINDING;if(x.test(A)){var V=u.bindings;V?u.hasOwnProperty("bindings")||(V=u.bindings=r(u.bindings)):V=u.bindings={},V[A]=P}var S=u.descs[A];if(p&&v(p,A)>=0){var T=this[A];P=T?"function"==typeof T.concat?T.concat(P):Ember.makeArray(T).concat(P):Ember.makeArray(P)}S?S.set(this,A,P):"function"!=typeof this.setUnknownProperty||A in this?E?Ember.defineProperty(this,A,null,P):this[A]=P:this.setUnknownProperty(A,P)}}}}d(this,u),this.init.apply(this,arguments),u.proto=h,c(this),l(this,"init")};return a.toString=f.prototype.toString,a.willReopen=function(){o&&(a.PrototypeMixin=f.create(a.PrototypeMixin)),o=!1},a._initMixins=function(t){e=t},a._initProperties=function(e){t=e},a.proto=function(){var e=a.superclass;return e&&e.proto(),o||(o=!0,a.PrototypeMixin.applyPartial(a.prototype),u(a.prototype)),this.prototype},a}function t(e){return function(){return e}}var r=(Ember.set,Ember.get,Ember.create),n=Ember.platform.defineProperty,i=Ember.GUID_KEY,o=Ember.guidFor,a=Ember.generateGuid,s=Ember.meta,u=Ember.rewatch,c=Ember.finishChains,l=Ember.sendEvent,h=Ember.destroy,m=Ember.run.schedule,f=Ember.Mixin,p=f._apply,d=f.finishPartial,b=f.prototype.reopen,E=Ember.ENV.MANDATORY_SETTER,v=Ember.EnumerableUtils.indexOf,g={configurable:!0,writable:!0,enumerable:!1,value:void 0},y=e(); -y.toString=function(){return"Ember.CoreObject"},y.PrototypeMixin=f.create({reopen:function(){return p(this,arguments,!0),this},init:function(){},concatenatedProperties:null,isDestroyed:!1,isDestroying:!1,destroy:function(){return this.isDestroying?void 0:(this.isDestroying=!0,m("actions",this,this.willDestroy),m("destroy",this,this._scheduledDestroy),this)},willDestroy:Ember.K,_scheduledDestroy:function(){this.isDestroyed||(h(this),this.isDestroyed=!0)},bind:function(e,t){return t instanceof Ember.Binding||(t=Ember.Binding.from(t)),t.to(e).connect(this),t},toString:function(){var e="function"==typeof this.toStringExtension,r=e?":"+this.toStringExtension():"",n="<"+this.constructor.toString()+":"+o(this)+r+">";return this.toString=t(n),n}}),y.PrototypeMixin.ownerConstructor=y,Ember.config.overridePrototypeMixin&&Ember.config.overridePrototypeMixin(y.PrototypeMixin),y.__super__=null;var w=f.create({ClassMixin:Ember.required(),PrototypeMixin:Ember.required(),isClass:!0,isMethod:!1,extend:function(){var t,n=e();return n.ClassMixin=f.create(this.ClassMixin),n.PrototypeMixin=f.create(this.PrototypeMixin),n.ClassMixin.ownerConstructor=n,n.PrototypeMixin.ownerConstructor=n,b.apply(n.PrototypeMixin,arguments),n.superclass=this,n.__super__=this.prototype,t=n.prototype=r(this.prototype),t.constructor=n,a(t,"ember"),s(t).proto=t,n.ClassMixin.apply(n),n},createWithMixins:function(){var e=this;return arguments.length>0&&this._initMixins(arguments),new e},create:function(){var e=this;return arguments.length>0&&this._initProperties(arguments),new e},reopen:function(){return this.willReopen(),b.apply(this.PrototypeMixin,arguments),this},reopenClass:function(){return b.apply(this.ClassMixin,arguments),p(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=s(this.proto(),!1).descs[e];return t._meta||{}},eachComputedProperty:function(e,t){var r,n=this.proto(),i=s(n).descs,o={};for(var a in i)r=i[a],r instanceof Ember.ComputedProperty&&e.call(t||this,a,r._meta||o)}});w.ownerConstructor=y,Ember.config.overrideClassMixin&&Ember.config.overrideClassMixin(w),y.ClassMixin=w,w.apply(y),Ember.CoreObject=y}(),function(){Ember.FEATURES.isEnabled("em-o")&&(Ember.O=function(e){return Ember.Object.detectInstance(e)?e:Ember.Object.create(e)}),Ember.Object=Ember.CoreObject.extend(Ember.Observable),Ember.Object.toString=function(){return"Ember.Object"}}(),function(){function e(t,r,i){var a=t.length;c[t.join(".")]=r;for(var s in r)if(l.call(r,s)){var u=r[s];if(t[a]=s,u&&u.toString===n)u.toString=o(t.join(".")),u[m]=t.join(".");else if(u&&u.isNamespace){if(i[h(u)])continue;i[h(u)]=!0,e(t,u,i)}}t.length=a}function t(){var e,t,r=Ember.Namespace,n=Ember.lookup;if(!r.PROCESSED)for(var i in n)if("parent"!==i&&"top"!==i&&"frameElement"!==i&&"webkitStorageInfo"!==i&&!("globalStorage"===i&&n.StorageList&&n.globalStorage instanceof n.StorageList||n.hasOwnProperty&&!n.hasOwnProperty(i))){try{e=Ember.lookup[i],t=e&&e.isNamespace}catch(o){continue}t&&(e[m]=i)}}function r(e){var t=e.superclass;return t?t[m]?t[m]:r(t):void 0}function n(){Ember.BOOTED||this[m]||i();var e;if(this[m])e=this[m];else if(this._toString)e=this._toString;else{var t=r(this);e=t?"(subclass of "+t+")":"(unknown mixin)",this.toString=o(e)}return e}function i(){var r=!u.PROCESSED,n=Ember.anyUnprocessedMixins;if(r&&(t(),u.PROCESSED=!0),r||n){for(var i,o=u.NAMESPACES,a=0,s=o.length;s>a;a++)i=o[a],e([i.toString()],i,{});Ember.anyUnprocessedMixins=!1}}function o(e){return function(){return e}}var a=Ember.get,s=Ember.ArrayPolyfills.indexOf,u=Ember.Namespace=Ember.Object.extend({isNamespace:!0,init:function(){Ember.Namespace.NAMESPACES.push(this),Ember.Namespace.PROCESSED=!1},toString:function(){var e=a(this,"name");return e?e:(t(),this[Ember.GUID_KEY+"_name"])},nameClasses:function(){e([this.toString()],this,{})},destroy:function(){var e=Ember.Namespace.NAMESPACES;Ember.lookup[this.toString()]=void 0,e.splice(s.call(e,this),1),this._super()}});u.reopenClass({NAMESPACES:[Ember],NAMESPACES_BY_ID:{},PROCESSED:!1,processAll:i,byName:function(e){return Ember.BOOTED||i(),c[e]}});var c=u.NAMESPACES_BY_ID,l={}.hasOwnProperty,h=Ember.guidFor,m=Ember.NAME_KEY=Ember.GUID_KEY+"_name";Ember.Mixin.prototype.toString=n}(),function(){Ember.Application=Ember.Namespace.extend()}(),function(){var e="Index out of range",t=[],r=Ember.get;Ember.set,Ember.ArrayProxy=Ember.Object.extend(Ember.MutableArray,{content:null,arrangedContent:Ember.computed.alias("content"),objectAtContent:function(e){return r(this,"arrangedContent").objectAt(e)},replaceContent:function(e,t,n){r(this,"content").replace(e,t,n)},_contentWillChange:Ember.beforeObserver(function(){this._teardownContent()},"content"),_teardownContent:function(){var e=r(this,"content");e&&e.removeArrayObserver(this,{willChange:"contentArrayWillChange",didChange:"contentArrayDidChange"})},contentArrayWillChange:Ember.K,contentArrayDidChange:Ember.K,_contentDidChange:Ember.observer(function(){r(this,"content"),this._setupContent()},"content"),_setupContent:function(){var e=r(this,"content");e&&e.addArrayObserver(this,{willChange:"contentArrayWillChange",didChange:"contentArrayDidChange"})},_arrangedContentWillChange:Ember.beforeObserver(function(){var e=r(this,"arrangedContent"),t=e?r(e,"length"):0;this.arrangedContentArrayWillChange(this,0,t,void 0),this.arrangedContentWillChange(this),this._teardownArrangedContent(e)},"arrangedContent"),_arrangedContentDidChange:Ember.observer(function(){var e=r(this,"arrangedContent"),t=e?r(e,"length"):0;this._setupArrangedContent(),this.arrangedContentDidChange(this),this.arrangedContentArrayDidChange(this,0,void 0,t)},"arrangedContent"),_setupArrangedContent:function(){var e=r(this,"arrangedContent");e&&e.addArrayObserver(this,{willChange:"arrangedContentArrayWillChange",didChange:"arrangedContentArrayDidChange"})},_teardownArrangedContent:function(){var e=r(this,"arrangedContent");e&&e.removeArrayObserver(this,{willChange:"arrangedContentArrayWillChange",didChange:"arrangedContentArrayDidChange"})},arrangedContentWillChange:Ember.K,arrangedContentDidChange:Ember.K,objectAt:function(e){return r(this,"content")&&this.objectAtContent(e)},length:Ember.computed(function(){var e=r(this,"arrangedContent");return e?r(e,"length"):0}),_replace:function(e,t,n){var i=r(this,"content");return i&&this.replaceContent(e,t,n),this},replace:function(){if(r(this,"arrangedContent")!==r(this,"content"))throw new Ember.Error("Using replace on an arranged ArrayProxy is not allowed.");this._replace.apply(this,arguments)},_insertAt:function(t,n){if(t>r(this,"content.length"))throw new Error(e);return this._replace(t,0,[n]),this},insertAt:function(e,t){if(r(this,"arrangedContent")===r(this,"content"))return this._insertAt(e,t);throw new Ember.Error("Using insertAt on an arranged ArrayProxy is not allowed.")},removeAt:function(n,i){if("number"==typeof n){var o,a=r(this,"content"),s=r(this,"arrangedContent"),u=[];if(0>n||n>=r(this,"length"))throw new Error(e);for(void 0===i&&(i=1),o=n;n+i>o;o++)u.push(a.indexOf(s.objectAt(o)));for(u.sort(function(e,t){return t-e}),Ember.beginPropertyChanges(),o=0;o=i;){var u=e.objectAt(o);u&&(Ember.addBeforeObserver(u,t,r,"contentKeyWillChange"),Ember.addObserver(u,t,r,"contentKeyDidChange"),a=n(u),s[a]||(s[a]=[]),s[a].push(o))}}function t(e,t,r,i,a){var s=r._objects;s||(s=r._objects={});for(var u,c;--a>=i;){var l=e.objectAt(a);l&&(Ember.removeBeforeObserver(l,t,r,"contentKeyWillChange"),Ember.removeObserver(l,t,r,"contentKeyDidChange"),c=n(l),u=s[c],u[o.call(u,a)]=null)}}var r=(Ember.set,Ember.get),n=Ember.guidFor,i=Ember.EnumerableUtils.forEach,o=Ember.ArrayPolyfills.indexOf,a=Ember.Object.extend(Ember.Array,{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&&r(t,this._keyName)},length:Ember.computed(function(){var e=this._content;return e?r(e,"length"):0})}),s=/^.+:(before|change)$/;Ember.EachProxy=Ember.Object.extend({init:function(e){this._super(),this._content=e,e.addArrayObserver(this),i(Ember.watchedEvents(this),function(e){this.didAddListener(e)},this)},unknownProperty:function(e){var t;return t=new a(this._content,e,this),Ember.defineProperty(this,e,null,t),this.beginObservingContentKey(e),t},arrayWillChange:function(e,r,n){var i,o,a=this._keys;o=n>0?r+n:-1,Ember.beginPropertyChanges(this);for(i in a)a.hasOwnProperty(i)&&(o>0&&t(e,i,this,r,o),Ember.propertyWillChange(this,i));Ember.propertyWillChange(this._content,"@each"),Ember.endPropertyChanges(this)},arrayDidChange:function(t,r,n,i){var o,a=this._keys;o=i>0?r+i:-1,Ember.changeProperties(function(){for(var n in a)a.hasOwnProperty(n)&&(o>0&&e(t,n,this,r,o),Ember.propertyDidChange(this,n));Ember.propertyDidChange(this._content,"@each")},this)},didAddListener:function(e){s.test(e)&&this.beginObservingContentKey(e.slice(0,-7))},didRemoveListener:function(e){s.test(e)&&this.stopObservingContentKey(e.slice(0,-7))},beginObservingContentKey:function(t){var n=this._keys;if(n||(n=this._keys={}),n[t])n[t]++;else{n[t]=1;var i=this._content,o=r(i,"length");e(i,t,this,0,o)}},stopObservingContentKey:function(e){var n=this._keys;if(n&&n[e]>0&&--n[e]<=0){var i=this._content,o=r(i,"length");t(i,e,this,0,o)}},contentKeyWillChange:function(e,t){Ember.propertyWillChange(this,t)},contentKeyDidChange:function(e,t){Ember.propertyDidChange(this,t)}})}(),function(){var e=Ember.get,t=(Ember.set,Ember.EnumerableUtils._replace),r=Ember.Mixin.create(Ember.MutableArray,Ember.Observable,Ember.Copyable,{get:function(e){return"length"===e?this.length:"number"==typeof e?this[e]:this._super(e)},objectAt:function(e){return this[e]},replace:function(r,n,i){if(this.isFrozen)throw Ember.FROZEN_ERROR;var o=i?e(i,"length"):0;return this.arrayContentWillChange(r,n,o),0===o?this.splice(r,n):t(this,r,n,i),this.arrayContentDidChange(r,n,o),this},unknownProperty:function(e,t){var r;return void 0!==t&&void 0===r&&(r=this[e]=t),r},indexOf:function(e,t){var r,n=this.length;for(t=void 0===t?0:0>t?Math.ceil(t):Math.floor(t),0>t&&(t+=n),r=t;n>r;r++)if(this[r]===e)return r;return-1},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},copy:function(e){return e?this.map(function(e){return Ember.copy(e,!0)}):this.slice()}}),n=["length"];Ember.EnumerableUtils.forEach(r.keys(),function(e){Array.prototype[e]&&n.push(e)}),n.length>0&&(r=r.without.apply(r,n)),Ember.NativeArray=r,Ember.A=function(e){return void 0===e&&(e=[]),Ember.Array.detect(e)?e:Ember.NativeArray.apply(e)},Ember.NativeArray.activate=function(){r.apply(Array.prototype),Ember.A=function(e){return e||[]}},(Ember.EXTEND_PROTOTYPES===!0||Ember.EXTEND_PROTOTYPES.Array)&&Ember.NativeArray.activate()}(),function(){var e=Ember.get,t=Ember.set,r=Ember.guidFor,n=Ember.isNone,i=Ember.String.fmt;Ember.Set=Ember.CoreObject.extend(Ember.MutableEnumerable,Ember.Copyable,Ember.Freezable,{length:0,clear:function(){if(this.isFrozen)throw new Error(Ember.FROZEN_ERROR);var n=e(this,"length");if(0===n)return this;var i;this.enumerableContentWillChange(n,0),Ember.propertyWillChange(this,"firstObject"),Ember.propertyWillChange(this,"lastObject");for(var o=0;n>o;o++)i=r(this[o]),delete this[i],delete this[o];return t(this,"length",0),Ember.propertyDidChange(this,"firstObject"),Ember.propertyDidChange(this,"lastObject"),this.enumerableContentDidChange(n,0),this},isEqual:function(t){if(!Ember.Enumerable.detect(t))return!1;var r=e(this,"length");if(e(t,"length")!==r)return!1;for(;--r>=0;)if(!t.contains(this[r]))return!1;return!0},add:Ember.aliasMethod("addObject"),remove:Ember.aliasMethod("removeObject"),pop:function(){if(e(this,"isFrozen"))throw new Error(Ember.FROZEN_ERROR);var t=this.length>0?this[this.length-1]:null;return this.remove(t),t},push:Ember.aliasMethod("addObject"),shift:Ember.aliasMethod("pop"),unshift:Ember.aliasMethod("push"),addEach:Ember.aliasMethod("addObjects"),removeEach:Ember.aliasMethod("removeObjects"),init:function(e){this._super(),e&&this.addObjects(e)},nextObject:function(e){return this[e]},firstObject:Ember.computed(function(){return this.length>0?this[0]:void 0}),lastObject:Ember.computed(function(){return this.length>0?this[this.length-1]:void 0}),addObject:function(i){if(e(this,"isFrozen"))throw new Error(Ember.FROZEN_ERROR);if(n(i))return this;var o,a=r(i),s=this[a],u=e(this,"length");return s>=0&&u>s&&this[s]===i?this:(o=[i],this.enumerableContentWillChange(null,o),Ember.propertyWillChange(this,"lastObject"),u=e(this,"length"),this[a]=u,this[u]=i,t(this,"length",u+1),Ember.propertyDidChange(this,"lastObject"),this.enumerableContentDidChange(null,o),this)},removeObject:function(i){if(e(this,"isFrozen"))throw new Error(Ember.FROZEN_ERROR);if(n(i))return this;var o,a,s=r(i),u=this[s],c=e(this,"length"),l=0===u,h=u===c-1;return u>=0&&c>u&&this[u]===i&&(a=[i],this.enumerableContentWillChange(a,null),l&&Ember.propertyWillChange(this,"firstObject"),h&&Ember.propertyWillChange(this,"lastObject"),c-1>u&&(o=this[c-1],this[u]=o,this[r(o)]=u),delete this[s],delete this[c-1],t(this,"length",c-1),l&&Ember.propertyDidChange(this,"firstObject"),h&&Ember.propertyDidChange(this,"lastObject"),this.enumerableContentDidChange(a,null)),this},contains:function(e){return this[r(e)]>=0},copy:function(){var n=this.constructor,i=new n,o=e(this,"length");for(t(i,"length",o);--o>=0;)i[o]=this[o],i[r(this[o])]=o;return i},toString:function(){var e,t=this.length,r=[];for(e=0;t>e;e++)r[e]=this[e];return i("Ember.Set<%@>",[r.join(",")])}})}(),function(){var e=Ember.DeferredMixin;Ember.get;var t=Ember.Object.extend(e);t.reopenClass({promise:function(e,r){var n=t.create();return e.call(r,n),n}}),Ember.Deferred=t}(),function(){var e=Ember.ArrayPolyfills.forEach,t=Ember.ENV.EMBER_LOAD_HOOKS||{},r={};Ember.onLoad=function(e,n){var i;t[e]=t[e]||Ember.A(),t[e].pushObject(n),(i=r[e])&&n(i)},Ember.runLoadHooks=function(n,i){r[n]=i,t[n]&&e.call(t[n],function(e){e(i)})}}(),function(){Ember.get,Ember.ControllerMixin=Ember.Mixin.create(Ember.ActionHandler,{isController:!0,target:null,container:null,parentController:null,store:null,model:Ember.computed.alias("content"),deprecatedSendHandles:function(e){return!!this[e]},deprecatedSend:function(e){var t=[].slice.call(arguments,1);this[e].apply(this,t)}}),Ember.Controller=Ember.Object.extend(Ember.ControllerMixin)}(),function(){var e=Ember.get,t=(Ember.set,Ember.EnumerableUtils.forEach);Ember.SortableMixin=Ember.Mixin.create(Ember.MutableEnumerable,{sortProperties:null,sortAscending:!0,sortFunction:Ember.compare,orderBy:function(r,n){var i=0,o=e(this,"sortProperties"),a=e(this,"sortAscending"),s=e(this,"sortFunction");return t(o,function(t){0===i&&(i=s(e(r,t),e(n,t)),0===i||a||(i=-1*i))}),i},destroy:function(){var r=e(this,"content"),n=e(this,"sortProperties");return r&&n&&t(r,function(e){t(n,function(t){Ember.removeObserver(e,t,this,"contentItemSortPropertyDidChange")},this)},this),this._super()},isSorted:Ember.computed.bool("sortProperties"),arrangedContent:Ember.computed("content","sortProperties.@each",function(){var r=e(this,"content"),n=e(this,"isSorted"),i=e(this,"sortProperties"),o=this;return r&&n?(r=r.slice(),r.sort(function(e,t){return o.orderBy(e,t)}),t(r,function(e){t(i,function(t){Ember.addObserver(e,t,this,"contentItemSortPropertyDidChange")},this)},this),Ember.A(r)):r}),_contentWillChange:Ember.beforeObserver(function(){var r=e(this,"content"),n=e(this,"sortProperties");r&&n&&t(r,function(e){t(n,function(t){Ember.removeObserver(e,t,this,"contentItemSortPropertyDidChange")},this)},this),this._super()},"content"),sortAscendingWillChange:Ember.beforeObserver(function(){this._lastSortAscending=e(this,"sortAscending")},"sortAscending"),sortAscendingDidChange:Ember.observer(function(){if(e(this,"sortAscending")!==this._lastSortAscending){var t=e(this,"arrangedContent");t.reverseObjects()}},"sortAscending"),contentArrayWillChange:function(r,n,i,o){var a=e(this,"isSorted");if(a){var s=e(this,"arrangedContent"),u=r.slice(n,n+i),c=e(this,"sortProperties");t(u,function(e){s.removeObject(e),t(c,function(t){Ember.removeObserver(e,t,this,"contentItemSortPropertyDidChange")},this)},this)}return this._super(r,n,i,o)},contentArrayDidChange:function(r,n,i,o){var a=e(this,"isSorted"),s=e(this,"sortProperties");if(a){var u=r.slice(n,n+o);t(u,function(e){this.insertItemSorted(e),t(s,function(t){Ember.addObserver(e,t,this,"contentItemSortPropertyDidChange")},this)},this)}return this._super(r,n,i,o)},insertItemSorted:function(t){var r=e(this,"arrangedContent"),n=e(r,"length"),i=this._binarySearch(t,0,n);r.insertAt(i,t)},contentItemSortPropertyDidChange:function(t){var r=e(this,"arrangedContent"),n=r.indexOf(t),i=r.objectAt(n-1),o=r.objectAt(n+1),a=i&&this.orderBy(t,i),s=o&&this.orderBy(t,o);(0>a||s>0)&&(r.removeObject(t),this.insertItemSorted(t))},_binarySearch:function(t,r,n){var i,o,a,s;return r===n?r:(s=e(this,"arrangedContent"),i=r+Math.floor((n-r)/2),o=s.objectAt(i),a=this.orderBy(o,t),0>a?this._binarySearch(t,i+1,n):a>0?this._binarySearch(t,r,i):i)}})}(),function(){var e=Ember.get,t=(Ember.set,Ember.EnumerableUtils.forEach),r=Ember.EnumerableUtils.replace;Ember.ArrayController=Ember.ArrayProxy.extend(Ember.ControllerMixin,Ember.SortableMixin,{itemController:null,lookupItemController:function(){return e(this,"itemController")},objectAtContent:function(t){var r=e(this,"length"),n=e(this,"arrangedContent"),i=n&&n.objectAt(t);if(t>=0&&r>t){var o=this.lookupItemController(i);if(o)return this.controllerAt(t,i,o)}return i},arrangedContentDidChange:function(){this._super(),this._resetSubControllers()},arrayContentDidChange:function(n,i,o){var a=e(this,"_subControllers"),s=a.slice(n,n+i);t(s,function(e){e&&e.destroy()}),r(a,n,i,new Array(o)),this._super(n,i,o)},init:function(){this._super(),this.set("_subControllers",Ember.A())},content:Ember.computed(function(){return Ember.A()}),controllerAt:function(t,r,n){var i,o=e(this,"container"),a=e(this,"_subControllers"),s=a[t];if(s)return s;if(i="controller:"+n,!o.has(i))throw new Error('Could not resolve itemController: "'+n+'"');return s=o.lookupFactory(i).create({target:this,parentController:e(this,"parentController")||this,content:r}),a[t]=s,s},_subControllers:null,_resetSubControllers:function(){var r=e(this,"_subControllers");r&&t(r,function(e){e&&e.destroy()}),this.set("_subControllers",Ember.A())}})}(),function(){Ember.ObjectController=Ember.ObjectProxy.extend(Ember.ControllerMixin)}(),function(){var e=Ember.imports.jQuery;Ember.$=e}(),function(){if(Ember.$){var e=Ember.String.w("dragstart drag dragenter dragleave dragover drop dragend");Ember.EnumerableUtils.forEach(e,function(e){Ember.$.event.fixHooks[e]={props:["dataTransfer"]}})}}(),function(){function e(e){var t=e.shiftKey||e.metaKey||e.altKey||e.ctrlKey,r=e.which>1;return!t&&!r}var t=this.document&&function(){var e=document.createElement("div");return e.innerHTML="
",e.firstChild.innerHTML="",""===e.firstChild.innerHTML}(),r=this.document&&function(){var e=document.createElement("div");return e.innerHTML="Test: Value","Test:"===e.childNodes[0].nodeValue&&" Value"===e.childNodes[2].nodeValue}(),n=function(e,t){if(e.getAttribute("id")===t)return e;var r,i,o,a=e.childNodes.length;for(r=0;a>r;r++)if(i=e.childNodes[r],o=1===i.nodeType&&n(i,t))return o},i=function(e,i){t&&(i="­"+i);var o=[];if(r&&(i=i.replace(/(\s+)(",""===e.firstChild.innerHTML}(),a=r&&function(){var e=r.createElement("div");return e.innerHTML="Test: Value","Test:"===e.childNodes[0].nodeValue&&" Value"===e.childNodes[2].nodeValue}(),s=function(r){var n;n=this instanceof s?this:new e,n.innerHTML=r;var i="metamorph-"+t++;return n.start=i+"-start",n.end=i+"-end",n};e.prototype=s.prototype;var u,c,l,h,m,f,p,d,b;if(h=function(){return this.startTag()+this.innerHTML+this.endTag()},d=function(){return""},b=function(){return""},i)u=function(e,t){var n=r.createRange(),i=r.getElementById(e.start),o=r.getElementById(e.end);return t?(n.setStartBefore(i),n.setEndAfter(o)):(n.setStartAfter(i),n.setEndBefore(o)),n},c=function(e,t){var r=u(this,t);r.deleteContents();var n=r.createContextualFragment(e);r.insertNode(n)},l=function(){var e=u(this,!0);e.deleteContents()},m=function(e){var t=r.createRange();t.setStart(e),t.collapse(!1);var n=t.createContextualFragment(this.outerHTML());e.appendChild(n)},f=function(e){var t=r.createRange(),n=r.getElementById(this.end);t.setStartAfter(n),t.setEndAfter(n);var i=t.createContextualFragment(e);t.insertNode(i)},p=function(e){var t=r.createRange(),n=r.getElementById(this.start);t.setStartAfter(n),t.setEndAfter(n);var i=t.createContextualFragment(e);t.insertNode(i)};else{var E={select:[1,""],fieldset:[1,"
","
"],table:[1,"","
"],tbody:[2,"","
"],tr:[3,"","
"],colgroup:[2,"","
"],map:[1,"",""],_default:[0,"",""]},v=function(e,t){if(e.getAttribute("id")===t)return e;var r,n,i,o=e.childNodes.length;for(r=0;o>r;r++)if(n=e.childNodes[r],i=1===n.nodeType&&v(n,t))return i},g=function(e,t){var n=[];if(a&&(t=t.replace(/(\s+)(",""===e.firstChild.innerHTML}(),r=this.document&&function(){var e=document.createElement("div");return e.innerHTML="Test: Value","Test:"===e.childNodes[0].nodeValue&&" Value"===e.childNodes[2].nodeValue}(),n=function(e,t){if(e.getAttribute("id")===t)return e;var r,i,o,a=e.childNodes.length;for(r=0;a>r;r++)if(i=e.childNodes[r],o=1===i.nodeType&&n(i,t))return o},i=function(e,i){t&&(i="­"+i);var o=[];if(r&&(i=i.replace(/(\s+)(",""===e.firstChild.innerHTML}(),a=r&&function(){var e=r.createElement("div");return e.innerHTML="Test: Value","Test:"===e.childNodes[0].nodeValue&&" Value"===e.childNodes[2].nodeValue}(),s=function(r){var n;n=this instanceof s?this:new e,n.innerHTML=r;var i="metamorph-"+t++;return n.start=i+"-start",n.end=i+"-end",n};e.prototype=s.prototype;var u,c,l,h,m,f,p,d,b;if(h=function(){return this.startTag()+this.innerHTML+this.endTag()},d=function(){return""},b=function(){return""},i)u=function(e,t){var n=r.createRange(),i=r.getElementById(e.start),o=r.getElementById(e.end);return t?(n.setStartBefore(i),n.setEndAfter(o)):(n.setStartAfter(i),n.setEndBefore(o)),n},c=function(e,t){var r=u(this,t);r.deleteContents();var n=r.createContextualFragment(e);r.insertNode(n)},l=function(){var e=u(this,!0);e.deleteContents()},m=function(e){var t=r.createRange();t.setStart(e),t.collapse(!1);var n=t.createContextualFragment(this.outerHTML());e.appendChild(n)},f=function(e){var t=r.createRange(),n=r.getElementById(this.end);t.setStartAfter(n),t.setEndAfter(n);var i=t.createContextualFragment(e);t.insertNode(i)},p=function(e){var t=r.createRange(),n=r.getElementById(this.start);t.setStartAfter(n),t.setEndAfter(n);var i=t.createContextualFragment(e);t.insertNode(i)};else{var v={select:[1,""],fieldset:[1,"
","
"],table:[1,"","
"],tbody:[2,"","
"],tr:[3,"","
"],colgroup:[2,"","
"],map:[1,"",""],_default:[0,"",""]},E=function(e,t){if(e.getAttribute("id")===t)return e;var r,n,i,o=e.childNodes.length;for(r=0;o>r;r++)if(n=e.childNodes[r],i=1===n.nodeType&&E(n,t))return i},g=function(e,t){var n=[];if(a&&(t=t.replace(/(\s+)(