return this.findAll(type);
}
// We are passed a query instead of an id.
if (Ember.typeOf(id) === 'object') {
return this.findQuery(type, id);
}
return this.findById(type, coerceId(id), preload);
},
/**
This method returns a record for a given type and id combination.
@method findById
@private
@param {String or subclass of DS.Model} type
@param {String|Integer} id
@param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models
@return {Promise} promise
*/
findById: function(typeName, id, preload) {
var type = this.modelFor(typeName);
var record = this.recordForId(type, id);
return this._findByRecord(record, preload);
},
_findByRecord: function(record, preload) {
var fetchedRecord;
if (preload) {
record._preloadData(preload);
}
if (get(record, 'isEmpty')) {
fetchedRecord = this.scheduleFetch(record);
//TODO double check about reloading
} else if (get(record, 'isLoading')){
fetchedRecord = record._loadingPromise;
}
return promiseObject(fetchedRecord || record, "DS: Store#findByRecord " + record.typeKey + " with id: " + get(record, 'id'));
},
/**
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
@return {Promise} promise
*/
findByIds: function(type, ids) {
var store = this;
return promiseArray(Ember.RSVP.all(map(ids, function(id) {
return store.findById(type, id);
})).then(Ember.A, null, "DS: Store#findByIds of " + type + " complete"));
},
/**
This method is called by `findById` if it discovers that a particular
type/id pair hasn't been loaded yet to kick off a request to the
adapter.
@method fetchRecord
@private
@param {DS.Model} record
@return {Promise} promise
*/
fetchRecord: function(record) {
var type = record.constructor;
var id = get(record, 'id');
var adapter = this.adapterFor(type);
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);
var promise = _find(adapter, this, type, id, record);
return promise;
},
scheduleFetchMany: function(records) {
return Ember.RSVP.all(map(records, this.scheduleFetch, this));
},
scheduleFetch: function(record) {
var type = record.constructor;
if (isNone(record)) { return null; }
if (record._loadingPromise) { return record._loadingPromise; }
var resolver = Ember.RSVP.defer('Fetching ' + type + 'with id: ' + record.get('id'));
var recordResolverPair = {
record: record,
resolver: resolver
};
var promise = resolver.promise;
record.loadingData(promise);
if (!this._pendingFetch.get(type)){
this._pendingFetch.set(type, [recordResolverPair]);
} else {
this._pendingFetch.get(type).push(recordResolverPair);
}
Ember.run.scheduleOnce('afterRender', this, this.flushAllPendingFetches);
return promise;
},
flushAllPendingFetches: function(){
if (this.isDestroyed || this.isDestroying) {
return;
}
this._pendingFetch.forEach(this._flushPendingFetchForType, this);
this._pendingFetch = Map.create();
},
_flushPendingFetchForType: function (recordResolverPairs, type) {
var store = this;
var adapter = store.adapterFor(type);
var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests;
var records = Ember.A(recordResolverPairs).mapBy('record');
function _fetchRecord(recordResolverPair) {
recordResolverPair.resolver.resolve(store.fetchRecord(recordResolverPair.record));
}
function resolveFoundRecords(records) {
forEach(records, function(record){
var pair = Ember.A(recordResolverPairs).findBy('record', record);
if (pair){
var resolver = pair.resolver;
resolver.resolve(record);
}
});
}
function makeMissingRecordsRejector(requestedRecords) {
return function rejectMissingRecords(resolvedRecords) {
var missingRecords = requestedRecords.without(resolvedRecords);
rejectRecords(missingRecords);
};
}
function makeRecordsRejector(records) {
return function (error) {
rejectRecords(records, error);
};
}
function rejectRecords(records, error) {
forEach(records, function(record){
var pair = Ember.A(recordResolverPairs).findBy('record', record);
if (pair){
var resolver = pair.resolver;
resolver.reject(error);
}
});
}
if (recordResolverPairs.length === 1) {
_fetchRecord(recordResolverPairs[0]);
} else if (shouldCoalesce) {
var groups = adapter.groupRecordsForFindMany(this, records);
forEach(groups, function (groupOfRecords) {
var requestedRecords = Ember.A(groupOfRecords);
var ids = requestedRecords.mapBy('id');
if (ids.length > 1) {
_findMany(adapter, store, type, ids, requestedRecords).
then(resolveFoundRecords).
then(makeMissingRecordsRejector(requestedRecords)).
then(null, makeRecordsRejector(requestedRecords));
} else if (ids.length === 1) {
var pair = Ember.A(recordResolverPairs).findBy('record', groupOfRecords[0]);
_fetchRecord(pair);
} else {
Ember.assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false);
}
});
} else {
forEach(recordResolverPairs, _fetchRecord);
}
},
/**
Get a record by a given type and ID without triggering a fetch.
This method will synchronously return the record if it is available in the store,
otherwise it will return `null`. A record is available if it has been fetched earlier, or
pushed manually into the store.
_Note: This is an synchronous method and does not return a promise._
```js
var post = store.getById('post', 1);
post.get('id'); // 1
```
@method getById
@param {String or subclass of DS.Model} type
@param {String|Integer} id
@return {DS.Model|null} record
*/
getById: function(type, id) {
if (this.hasRecordForId(type, id)) {
return this.recordForId(type, id);
} else {
return null;
}
},
/**
This method is called by the record's `reload` method.
This method calls the adapter's `find` method, which returns a promise. When
**that** promise resolves, `reloadRecord` will resolve the promise returned
by the record's `reload`.
@method reloadRecord
@private
@param {DS.Model} record
@return {Promise} promise
*/
reloadRecord: function(record) {
var type = record.constructor;
var adapter = this.adapterFor(type);
var id = get(record, 'id');
Ember.assert("You cannot reload a record without an ID", id);
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 this.scheduleFetch(record);
},
/**
Returns true if a record for a given type and ID is already loaded.
@method hasRecordForId
@param {String or subclass of DS.Model} type
@param {String|Integer} id
@return {Boolean}
*/
hasRecordForId: function(typeName, inputId) {
var type = this.modelFor(typeName);
var id = coerceId(inputId);
return !!this.typeMapFor(type).idToRecord[id];
},
/**
Returns id record for a given type and ID. If one isn't already loaded,
it builds a new record and leaves it in the `empty` state.
@method recordForId
@private
@param {String or subclass of DS.Model} type
@param {String|Integer} id
@return {DS.Model} record
*/
recordForId: function(typeName, inputId) {
var type = this.modelFor(typeName);
var id = coerceId(inputId);
var idToRecord = this.typeMapFor(type).idToRecord;
var record = idToRecord[id];
if (!record || !idToRecord[id]) {
record = this.buildRecord(type, id);
}
return record;
},
/**
@method findMany
@private
@param {DS.Model} owner
@param {Array} records
@param {String or subclass of DS.Model} type
@param {Resolver} resolver
@return {DS.ManyArray} records
*/
findMany: function(records) {
var store = this;
return Promise.all( map(records, function(record) {
return store._findByRecord(record);
}));
},
/**
If a relationship was originally populated by the adapter as a link
(as opposed to a list of IDs), this method is called when the
relationship is fetched.
The link (which is usually a URL) is passed through unchanged, so the
adapter can make whatever request it wants.
The usual use-case is for the server to register a URL as a link, and
then use that URL in the future to make a request for the relationship.
@method findHasMany
@private
@param {DS.Model} owner
@param {any} link
@param {String or subclass of DS.Model} type
@return {Promise} promise
*/
findHasMany: function(owner, link, type) {
var adapter = this.adapterFor(owner.constructor);
Ember.assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.constructor + ")", adapter);
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);
return _findHasMany(adapter, this, owner, link, type);
},
/**
@method findBelongsTo
@private
@param {DS.Model} owner
@param {any} link
@param {Relationship} relationship
@return {Promise} promise
*/
findBelongsTo: function(owner, link, relationship) {
var adapter = this.adapterFor(owner.constructor);
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);
return _findBelongsTo(adapter, this, owner, link, relationship);
},
/**
This method delegates a query to the adapter. This is the one place where
adapter-level semantics are exposed to the application.
Exposing queries this way seems preferable to creating an abstract query
language for all server-side queries, and then require all adapters to
implement them.
This method returns a promise, which is resolved with a `RecordArray`
once the server returns.
@method findQuery
@private
@param {String or subclass of DS.Model} type
@param {any} query an opaque query to be used by the adapter
@return {Promise} promise
*/
findQuery: function(typeName, query) {
var type = this.modelFor(typeName);
var array = this.recordArrayManager
.createAdapterPopulatedRecordArray(type, query);
var adapter = this.adapterFor(type);
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);
return promiseArray(_findQuery(adapter, this, type, query, array));
},
/**
This method returns an array of all records adapter can find.
It triggers the adapter's `findAll` method to give it an opportunity to populate
the array with records of that type.
@method findAll
@private
@param {String or subclass of DS.Model} type
@return {DS.AdapterPopulatedRecordArray}
*/
findAll: function(typeName) {
var type = this.modelFor(typeName);
return this.fetchAll(type, this.all(type));
},
/**
@method fetchAll
@private
@param {DS.Model} type
@param {DS.RecordArray} array
@return {Promise} promise
*/
fetchAll: function(type, array) {
var adapter = this.adapterFor(type);
var sinceToken = this.typeMapFor(type).metadata.since;
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);
return promiseArray(_findAll(adapter, this, type, sinceToken));
},
/**
@method didUpdateAll
@param {DS.Model} type
*/
didUpdateAll: function(type) {
var findAllCache = this.typeMapFor(type).findAllCache;
set(findAllCache, 'isUpdating', false);
},
/**
This method returns a filtered array that contains all of the known records
for a given type.
Note that because it's just a filter, it will have any locally
created records of the type.
Also note that multiple calls to `all` for a given type will always
return the same RecordArray.
Example
```javascript
var localPosts = store.all('post');
```
@method all
@param {String or subclass of DS.Model} type
@return {DS.RecordArray}
*/
all: function(typeName) {
var type = this.modelFor(typeName);
var typeMap = this.typeMapFor(type);
var findAllCache = typeMap.findAllCache;
if (findAllCache) { return findAllCache; }
var array = this.recordArrayManager.createRecordArray(type);
typeMap.findAllCache = array;
return array;
},
/**
This method unloads all of the known records for a given type.
```javascript
store.unloadAll('post');
```
@method unloadAll
@param {String or subclass of DS.Model} type
*/
unloadAll: function(type) {
var modelType = this.modelFor(type);
var typeMap = this.typeMapFor(modelType);
var records = typeMap.records.slice();
var record;
for (var i = 0; i < records.length; i++) {
record = records[i];
record.unloadRecord();
record.destroy(); // maybe within unloadRecord
}
typeMap.findAllCache = null;
},
/**
Takes a type and filter function, and returns a live RecordArray that
remains up to date as new records are loaded into the store or created
locally.
The callback function takes a materialized record, and returns true
if the record should be included in the filter and false if it should
not.
The filter function is called once on all records for the type when
it is created, and then once on each newly loaded or created record.
If any of a record's properties change, or if it changes state, the
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.
Example
```javascript
store.filter('post', {unread: true}, function(post) {
return post.get('unread');
}).then(function(unreadPosts) {
unreadPosts.get('length'); // 5
var unreadPost = unreadPosts.objectAt(0);
unreadPost.set('unread', false);
unreadPosts.get('length'); // 4
});
```
@method filter
@param {String or subclass of DS.Model} type
@param {Object} query optional query
@param {Function} filter
@return {DS.PromiseArray}
*/
filter: function(type, query, filter) {
var promise;
var length = arguments.length;
var array;
var hasQuery = length === 3;
// allow an optional server query
if (hasQuery) {
promise = this.findQuery(type, query);
} else if (arguments.length === 2) {
filter = query;
}
type = this.modelFor(type);
if (hasQuery) {
array = this.recordArrayManager.createFilteredRecordArray(type, filter, query);
} else {
array = this.recordArrayManager.createFilteredRecordArray(type, filter);
}
promise = promise || Promise.cast(array);
return promiseArray(promise.then(function() {
return array;
}, null, "DS: Store#filter of " + type));
},
/**
This method returns if a certain record is already loaded
in the store. Use this function to know beforehand if a find()
will result in a request or that it will be a cache hit.
Example
```javascript
store.recordIsLoaded('post', 1); // false
store.find('post', 1).then(function() {
store.recordIsLoaded('post', 1); // true
});
```
@method recordIsLoaded
@param {String or subclass of DS.Model} type
@param {string} id
@return {boolean}
*/
recordIsLoaded: function(type, id) {
if (!this.hasRecordForId(type, id)) { return false; }
return !get(this.recordForId(type, id), 'isEmpty');
},
/**
This method returns the metadata for a specific type.
@method metadataFor
@param {String or subclass of DS.Model} type
@return {object}
*/
metadataFor: function(type) {
type = this.modelFor(type);
return this.typeMapFor(type).metadata;
},
// ............
// . UPDATING .
// ............
/**
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
@private
@param {Class} type
@param {DS.Model} record
*/
dataWasUpdated: function(type, record) {
this.recordArrayManager.recordDidChange(record);
},
// ..............
// . PERSISTING .
// ..............
/**
This method is called by `record.save`, and gets passed a
resolver for the promise that `record.save` returns.
It schedules saving to happen at the end of the run loop.
@method scheduleSave
@private
@param {DS.Model} record
@param {Resolver} resolver
*/
scheduleSave: function(record, resolver) {
record.adapterWillCommit();
this._pendingSave.push([record, resolver]);
once(this, 'flushPendingSave');
},
/**
This method is called at the end of the run loop, and
flushes any records passed into `scheduleSave`
@method flushPendingSave
@private
*/
flushPendingSave: function() {
var pending = this._pendingSave.slice();
this._pendingSave = [];
forEach(pending, function(tuple) {
var record = tuple[0], resolver = tuple[1];
var adapter = this.adapterFor(record.constructor);
var operation;
if (get(record, 'currentState.stateName') === 'root.deleted.saved') {
return resolver.resolve(record);
} else if (get(record, 'isNew')) {
operation = 'createRecord';
} else if (get(record, 'isDeleted')) {
operation = 'deleteRecord';
} else {
operation = 'updateRecord';
}
resolver.resolve(_commit(adapter, this, operation, record));
}, this);
},
/**
This method is called once the promise returned by an
adapter's `createRecord`, `updateRecord` or `deleteRecord`
is resolved.
If the data provides a server-generated ID, it will
update the record and the store's indexes.
@method didSaveRecord
@private
@param {DS.Model} record the in-flight record
@param {Object} data optional data (see above)
*/
didSaveRecord: function(record, data) {
if (data) {
// normalize relationship IDs into records
data = normalizeRelationships(this, record.constructor, data, record);
setupRelationships(this, record, data);
this.updateId(record, data);
}
record.adapterDidCommit(data);
},
/**
This method is called once the promise returned by an
adapter's `createRecord`, `updateRecord` or `deleteRecord`
is rejected with a `DS.InvalidError`.
@method recordWasInvalid
@private
@param {DS.Model} record
@param {Object} errors
*/
recordWasInvalid: function(record, errors) {
record.adapterDidInvalidate(errors);
},
/**
This method is called once the promise returned by an
adapter's `createRecord`, `updateRecord` or `deleteRecord`
is rejected (with anything other than a `DS.InvalidError`).
@method recordWasError
@private
@param {DS.Model} record
*/
recordWasError: function(record) {
record.adapterDidError();
},
/**
When an adapter's `createRecord`, `updateRecord` or `deleteRecord`
resolves with data, this method extracts the ID from the supplied
data.
@method updateId
@private
@param {DS.Model} record
@param {Object} data
*/
updateId: function(record, data) {
var oldId = get(record, 'id');
var id = coerceId(data.id);
Ember.assert("An adapter cannot assign a new id to a record that already has an id. " + record + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId);
this.typeMapFor(record.constructor).idToRecord[id] = record;
set(record, 'id', id);
},
/**
Returns a map of IDs to client IDs for a given type.
@method typeMapFor
@private
@param {subclass of DS.Model} type
@return {Object} typeMap
*/
typeMapFor: function(type) {
var typeMaps = get(this, 'typeMaps');
var guid = Ember.guidFor(type);
var typeMap;
typeMap = typeMaps[guid];
if (typeMap) { return typeMap; }
typeMap = {
idToRecord: Object.create(null),
records: [],
metadata: Object.create(null),
type: type
};
typeMaps[guid] = typeMap;
return typeMap;
},
// ................
// . LOADING DATA .
// ................
/**
This internal method is used by `push`.
@method _load
@private
@param {String or subclass of DS.Model} type
@param {Object} data
@param {Boolean} partial the data should be merged into
the existing data, not replace it.
*/
_load: function(type, data, partial) {
var id = coerceId(data.id);
var record = this.recordForId(type, id);
record.setupData(data, partial);
this.recordArrayManager.recordDidChange(record);
return record;
},
/**
Returns a model class for a particular key. Used by
methods that take a type key (like `find`, `createRecord`,
etc.)
@method modelFor
@param {String or subclass of DS.Model} key
@return {subclass of DS.Model}
*/
modelFor: function(key) {
var factory;
if (typeof key === 'string') {
factory = this.modelFactoryFor(key);
if (!factory) {
throw new Ember.Error("No model was found for '" + key + "'");
}
factory.typeKey = factory.typeKey || this._normalizeTypeKey(key);
} else {
// A factory already supplied. Ensure it has a normalized key.
factory = key;
if (factory.typeKey) {
factory.typeKey = this._normalizeTypeKey(factory.typeKey);
}
}
factory.store = this;
return factory;
},
modelFactoryFor: function(key){
return this.container.lookupFactory('model:' + key);
},
/**
Push some data for a given type into the store.
This method expects normalized data:
* The ID is a key named `id` (an ID is mandatory)
* The names of attributes are the ones you used in
your model's `DS.attr`s.
* Your relationships must be:
* represented as IDs or Arrays of IDs
* represented as model instances
* represented as URLs, under the `links` key
For this model:
```js
App.Person = DS.Model.extend({
firstName: DS.attr(),
lastName: DS.attr(),
children: DS.hasMany('person')
});
```
To represent the children as IDs:
```js
{
id: 1,
firstName: "Tom",
lastName: "Dale",
children: [1, 2, 3]
}
```
To represent the children relationship as a URL:
```js
{
id: 1,
firstName: "Tom",
lastName: "Dale",
links: {
children: "/people/1/children"
}
}
```
If you're streaming data or implementing an adapter,
make sure that you have converted the incoming data
into this form.
This method can be used both to push in brand new
records, as well as to update existing records.
@method push
@param {String or subclass of DS.Model} type
@param {Object} data
@return {DS.Model} the record that was created or
updated.
*/
push: function(typeName, data, _partial) {
// _partial is an internal param used by `update`.
// If passed, it means that the data should be
// merged into the existing data, not replace it.
Ember.assert("Expected an object as `data` in a call to push for " + typeName + " , but was " + data, Ember.typeOf(data) === 'object');
Ember.assert("You must include an `id` for " + typeName + " in an object passed to `push`", data.id != null);
var type = this.modelFor(typeName);
// If the payload contains relationships that are specified as
// IDs, normalizeRelationships will convert them into DS.Model instances
// (possibly unloaded) before we push the payload into the
// store.
data = normalizeRelationships(this, type, data);
// Actually load the record into the store.
this._load(type, data, _partial);
var record = this.recordForId(type, data.id);
// Now that the pushed record as well as any related records
// are in the store, create the data structures used to track
// relationships.
setupRelationships(this, record, data);
return record;
},
/**
Push some raw data into the store.
This method can be used both to push in brand new
records, as well as to update existing records. You
can push in more than one type of object at once.
All objects should be in the format expected by the
serializer.
```js
App.ApplicationSerializer = DS.ActiveModelSerializer;
var pushData = {
posts: [
{id: 1, post_title: "Great post", comment_ids: [2]}
],
comments: [
{id: 2, comment_body: "Insightful comment"}
]
}
store.pushPayload(pushData);
```
By default, the data will be deserialized using a default
serializer (the application serializer if it exists).
Alternatively, `pushPayload` will accept a model type which
will determine which serializer will process the payload.
However, the serializer itself (processing this data via
`normalizePayload`) will not know which model it is
deserializing.
```js
App.ApplicationSerializer = DS.ActiveModelSerializer;
App.PostSerializer = DS.JSONSerializer;
store.pushPayload('comment', pushData); // Will use the ApplicationSerializer
store.pushPayload('post', pushData); // Will use the PostSerializer
```
@method pushPayload
@param {String} type Optionally, a model used to determine which serializer will be used
@param {Object} payload
*/
pushPayload: function (type, inputPayload) {
var serializer;
var payload;
if (!inputPayload) {
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 {
payload = inputPayload;
serializer = this.serializerFor(type);
}
serializer.pushPayload(this, payload);
},
/**
`normalize` converts a json payload into the normalized form that
[push](#method_push) expects.
Example
```js
socket.on('message', function(message) {
var modelName = message.model;
var data = message.data;
store.push(modelName, store.normalize(modelName, data));
});
```
@method normalize
@param {String} type The name of the model type for this payload
@param {Object} payload
@return {Object} The normalized payload
*/
normalize: function (type, payload) {
var serializer = this.serializerFor(type);
var model = this.modelFor(type);
return serializer.normalize(model, payload);
},
/**
Update existing records in the store. Unlike [push](#method_push),
update will merge the new data properties with the existing
properties. This makes it safe to use with a subset of record
attributes. This method expects normalized data.
`update` is useful if your app broadcasts partial updates to
records.
```js
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string')
});
store.get('person', 1).then(function(tom) {
tom.get('firstName'); // Tom
tom.get('lastName'); // Dale
var updateEvent = {id: 1, firstName: "TomHuda"};
store.update('person', updateEvent);
tom.get('firstName'); // TomHuda
tom.get('lastName'); // Dale
});
```
@method update
@param {String} type
@param {Object} data
@return {DS.Model} the record that was updated.
*/
update: function(type, data) {
Ember.assert("You must include an `id` for " + type + " in a hash passed to `update`", data.id != null);
return this.push(type, data, true);
},
/**
If you have an Array of normalized data to push,
you can call `pushMany` with the Array, and it will
call `push` repeatedly for you.
@method pushMany
@param {String or subclass of DS.Model} type
@param {Array} datas
@return {Array}
*/
pushMany: function(type, datas) {
var length = datas.length;
var result = new Array(length);
for (var i = 0; i < length; i++) {
result[i] = this.push(type, datas[i]);
}
return result;
},
/**
If you have some metadata to set for a type
you can call `metaForType`.
@method metaForType
@param {String or subclass of DS.Model} type
@param {Object} metadata
*/
metaForType: function(typeName, metadata) {
var type = this.modelFor(typeName);
Ember.merge(this.typeMapFor(type).metadata, metadata);
},
/**
Build a brand new record for a given type, ID, and
initial data.
@method buildRecord
@private
@param {subclass of DS.Model} type
@param {String} id
@param {Object} data
@return {DS.Model} record
*/
buildRecord: function(type, id, data) {
var typeMap = this.typeMapFor(type);
var idToRecord = typeMap.idToRecord;
Ember.assert('The id ' + id + ' has already been used with another record of type ' + type.toString() + '.', !id || !idToRecord[id]);
Ember.assert("`" + Ember.inspect(type)+ "` does not appear to be an ember-data model", (typeof type._create === 'function') );
// lookupFactory should really return an object that creates
// instances with the injections applied
var record = type._create({
id: id,
store: this,
container: this.container
});
if (data) {
record.setupData(data);
}
// if we're creating an item, this process will be done
// later, once the object has been persisted.
if (id) {
idToRecord[id] = record;
}
typeMap.records.push(record);
return record;
},
// ...............
// . DESTRUCTION .
// ...............
/**
When a record is destroyed, this un-indexes it and
removes it from any record arrays so it can be GCed.
@method dematerializeRecord
@private
@param {DS.Model} record
*/
dematerializeRecord: function(record) {
var type = record.constructor;
var typeMap = this.typeMapFor(type);
var id = get(record, 'id');
record.updateRecordArrays();
if (id) {
delete typeMap.idToRecord[id];
}
var loc = indexOf(typeMap.records, record);
typeMap.records.splice(loc, 1);
},
// ......................
// . PER-TYPE ADAPTERS
// ......................
/**
Returns the adapter for a given type.
@method adapterFor
@private
@param {subclass of DS.Model} type
@return DS.Adapter
*/
adapterFor: function(type) {
var container = this.container, adapter;
if (container) {
adapter = container.lookup('adapter:' + type.typeKey) || container.lookup('adapter:application');
}
return adapter || get(this, 'defaultAdapter');
},
// ..............................
// . RECORD CHANGE NOTIFICATION .
// ..............................
/**
Returns an instance of the serializer for a given type. For
example, `serializerFor('person')` will return an instance of
`App.PersonSerializer`.
If no `App.PersonSerializer` is found, this method will look
for an `App.ApplicationSerializer` (the default serializer for
your entire application).
If no `App.ApplicationSerializer` is found, it will fall back
to an instance of `DS.JSONSerializer`.
@method serializerFor
@private
@param {String} type the record to serialize
@return {DS.Serializer}
*/
serializerFor: function(type) {
type = this.modelFor(type);
var adapter = this.adapterFor(type);
return serializerFor(this.container, type.typeKey, adapter && adapter.defaultSerializer);
},
willDestroy: function() {
var typeMaps = this.typeMaps;
var keys = Ember.keys(typeMaps);
var types = map(keys, byType);
this.recordArrayManager.destroy();
forEach(types, this.unloadAll, this);
function byType(entry) {
return typeMaps[entry]['type'];
}
},
/**
All typeKeys are camelCase internally. Changing this function may
require changes to other normalization hooks (such as typeForRoot).
@method _normalizeTypeKey
@private
@param {String} type
@return {String} if the adapter can generate one, an ID
*/
_normalizeTypeKey: function(key) {
return camelize(singularize(key));
}
});
function normalizeRelationships(store, type, data, record) {
type.eachRelationship(function(key, relationship) {
var kind = relationship.kind;
var value = data[key];
if (kind === 'belongsTo') {
deserializeRecordId(store, data, key, relationship, value);
} else if (kind === 'hasMany') {
deserializeRecordIds(store, data, key, relationship, value);
}
});
return data;
}
function deserializeRecordId(store, data, key, relationship, id) {
if (!Model) { Model = requireModule("ember-data/system/model")["Model"]; }
if (isNone(id) || id instanceof Model) {
return;
}
var type;
if (typeof id === 'number' || typeof id === 'string') {
type = typeFor(relationship, key, data);
data[key] = store.recordForId(type, id);
} else if (typeof id === 'object') {
// polymorphic
data[key] = store.recordForId(id.type, id.id);
}
}
function typeFor(relationship, key, data) {
if (relationship.options.polymorphic) {
return data[key + "Type"];
} else {
return relationship.type;
}
}
function deserializeRecordIds(store, data, key, relationship, ids) {
if (!Ember.isArray(ids)) {
return;
}
for (var i=0, l=ids.length; i<l; i++) {
deserializeRecordId(store, ids, i, relationship, ids[i]);
}
}
// Delegation to the adapter and promise management
function serializerFor(container, type, defaultSerializer) {
return container.lookup('serializer:'+type) ||
container.lookup('serializer:application') ||
container.lookup('serializer:' + 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;
var defaultSerializer = adapter.defaultSerializer;
var container = adapter.container;
if (container && serializer === undefined) {
serializer = serializerFor(container, type.typeKey, defaultSerializer);
}
if (serializer === null || serializer === undefined) {
serializer = {
extract: function(store, type, payload) { return payload; }
};
}
return serializer;
}
function _objectIsAlive(object) {
return !(get(object, "isDestroyed") || get(object, "isDestroying"));
}
function _guard(promise, test) {
var guarded = promise['finally'](function() {
if (!test()) {
guarded._subscribers.length = 0;
}
});
return guarded;
}
function _bind(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
return fn.apply(undefined, args);
};
}
function _find(adapter, store, type, id, record) {
var promise = adapter.find(store, type, id, record);
var serializer = serializerForAdapter(adapter, type);
var label = "DS: Handle Adapter#find of " + type + " with id: " + id;
promise = Promise.cast(promise, label);
promise = _guard(promise, _bind(_objectIsAlive, store));
return promise.then(function(adapterPayload) {
Ember.assert("You made a request for a " + type.typeKey + " with id " + id + ", but the adapter's response did not have any data", adapterPayload);
var payload = serializer.extract(store, type, adapterPayload, id, 'find');
return store.push(type, payload);
}, function(error) {
var record = store.getById(type, id);
if (record) {
record.notFound();
}
throw error;
}, "DS: Extract payload of '" + type + "'");
}
function _findMany(adapter, store, type, ids, records) {
var promise = adapter.findMany(store, type, ids, records);
var serializer = serializerForAdapter(adapter, type);
var label = "DS: Handle Adapter#findMany of " + type;
if (promise === undefined) {
throw new Error('adapter.findMany returned undefined, this was very likely a mistake');
}
promise = Promise.cast(promise, label);
promise = _guard(promise, _bind(_objectIsAlive, store));
return promise.then(function(adapterPayload) {
var payload = serializer.extract(store, type, adapterPayload, null, 'findMany');
Ember.assert("The response from a findMany must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array');
return store.pushMany(type, payload);
}, null, "DS: Extract payload of " + type);
}
function _findHasMany(adapter, store, record, link, relationship) {
var promise = adapter.findHasMany(store, record, link, relationship);
var serializer = serializerForAdapter(adapter, relationship.type);
var label = "DS: Handle Adapter#findHasMany of " + record + " : " + relationship.type;
promise = Promise.cast(promise, label);
promise = _guard(promise, _bind(_objectIsAlive, store));
promise = _guard(promise, _bind(_objectIsAlive, record));
return promise.then(function(adapterPayload) {
var payload = serializer.extract(store, relationship.type, adapterPayload, 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);
return records;
}, null, "DS: Extract payload of " + record + " : hasMany " + relationship.type);
}
function _findBelongsTo(adapter, store, record, link, relationship) {
var promise = adapter.findBelongsTo(store, record, link, relationship);
var serializer = serializerForAdapter(adapter, relationship.type);
var label = "DS: Handle Adapter#findBelongsTo of " + record + " : " + relationship.type;
promise = Promise.cast(promise, label);
promise = _guard(promise, _bind(_objectIsAlive, store));
promise = _guard(promise, _bind(_objectIsAlive, record));
return promise.then(function(adapterPayload) {
var payload = serializer.extract(store, relationship.type, adapterPayload, null, 'findBelongsTo');
var record = store.push(relationship.type, payload);
return record;
}, null, "DS: Extract payload of " + record + " : " + relationship.type);
}
function _findAll(adapter, store, type, sinceToken) {
var promise = adapter.findAll(store, type, sinceToken);
var serializer = serializerForAdapter(adapter, type);
var label = "DS: Handle Adapter#findAll of " + type;
promise = Promise.cast(promise, label);
promise = _guard(promise, _bind(_objectIsAlive, store));
return promise.then(function(adapterPayload) {
var payload = serializer.extract(store, type, adapterPayload, null, 'findAll');
Ember.assert("The response from a findAll must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array');
store.pushMany(type, payload);
store.didUpdateAll(type);
return store.all(type);
}, null, "DS: Extract payload of findAll " + type);
}
function _findQuery(adapter, store, type, query, recordArray) {
var promise = adapter.findQuery(store, type, query, recordArray);
var serializer = serializerForAdapter(adapter, type);
var label = "DS: Handle Adapter#findQuery of " + type;
promise = Promise.cast(promise, label);
promise = _guard(promise, _bind(_objectIsAlive, store));
return promise.then(function(adapterPayload) {
var payload = serializer.extract(store, type, adapterPayload, null, 'findQuery');
Ember.assert("The response from a findQuery must be an Array, not " + Ember.inspect(payload), Ember.typeOf(payload) === 'array');
recordArray.load(payload);
return recordArray;
}, null, "DS: Extract payload of findQuery " + type);
}
function _commit(adapter, store, operation, record) {
var type = record.constructor;
var promise = adapter[operation](store, type, record);
var serializer = serializerForAdapter(adapter, type);
var label = "DS: Extract and notify about " + operation + " completion of " + record;
Ember.assert("Your adapter's '" + operation + "' method must return a value, but it returned `undefined", promise !==undefined);
promise = Promise.cast(promise, label);
promise = _guard(promise, _bind(_objectIsAlive, store));
promise = _guard(promise, _bind(_objectIsAlive, record));
return promise.then(function(adapterPayload) {
var payload;
if (adapterPayload) {
payload = serializer.extract(store, type, adapterPayload, get(record, 'id'), operation);
} else {
payload = adapterPayload;
}
store.didSaveRecord(record, payload);
return record;
}, function(reason) {
if (reason instanceof InvalidError) {
store.recordWasInvalid(record, reason.errors);
} else {
store.recordWasError(record, reason);
}
throw reason;
}, label);
}
function setupRelationships(store, record, data) {
var type = record.constructor;
type.eachRelationship(function(key, descriptor) {
var kind = descriptor.kind;
var value = data[key];
var relationship = record._relationships[key];
if (data.links && data.links[key]) {
relationship.updateLink(data.links[key]);
}
if (kind === 'belongsTo') {
if (value === undefined) {
return;
}
relationship.setRecord(value);
} else if (kind === 'hasMany' && value) {
relationship.updateRecordsFromAdapter(value);
}
});
}
__exports__.Store = Store;
__exports__["default"] = Store;
});
define("ember-data/transforms",
["ember-data/transforms/base","ember-data/transforms/number","ember-data/transforms/date","ember-data/transforms/string","ember-data/transforms/boolean","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) {
"use strict";
var Transform = __dependency1__["default"];
var NumberTransform = __dependency2__["default"];
var DateTransform = __dependency3__["default"];
var StringTransform = __dependency4__["default"];
var BooleanTransform = __dependency5__["default"];
__exports__.Transform = Transform;
__exports__.NumberTransform = NumberTransform;
__exports__.DateTransform = DateTransform;
__exports__.StringTransform = StringTransform;
__exports__.BooleanTransform = BooleanTransform;
});
define("ember-data/transforms/base",
["exports"],
function(__exports__) {
"use strict";
/**
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
// Converts centigrade in the JSON to fahrenheit in the app
App.TemperatureTransform = DS.Transform.extend({
deserialize: function(serialized) {
return (serialized * 1.8) + 32;
},
serialize: function(deserialized) {
return (deserialized - 32) / 1.8;
}
});
```
Usage
```javascript
var attr = DS.attr;
App.Requirement = DS.Model.extend({
name: attr('string'),
temperature: attr('temperature')
});
```
@class Transform
@namespace DS
*/
__exports__["default"] = 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 {mixed} deserialized The deserialized value
@return {mixed} 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 deserialize
@param {mixed} serialized The serialized value
@return {mixed} The deserialized value
*/
deserialize: Ember.required()
});
});
define("ember-data/transforms/boolean",
["ember-data/transforms/base","exports"],
function(__dependency1__, __exports__) {
"use strict";
var Transform = __dependency1__["default"];
/**
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
*/
__exports__["default"] = Transform.extend({
deserialize: function(serialized) {
var type = typeof serialized;
if (type === "boolean") {
return serialized;
} else if (type === "string") {
return serialized.match(/^true$|^t$|^1$/i) !== null;
} else if (type === "number") {
return serialized === 1;
} else {
return false;
}
},
serialize: function(deserialized) {
return Boolean(deserialized);
}
});
});
define("ember-data/transforms/date",
["ember-data/transforms/base","exports"],
function(__dependency1__, __exports__) {
"use strict";
/**
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
*/
var Transform = __dependency1__["default"];
// Date.prototype.toISOString shim
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
var toISOString = Date.prototype.toISOString || function() {
function pad(number) {
if ( number < 10 ) {
return '0' + number;
}
return number;
}
return this.getUTCFullYear() +
'-' + pad( this.getUTCMonth() + 1 ) +
'-' + pad( this.getUTCDate() ) +
'T' + pad( this.getUTCHours() ) +
':' + pad( this.getUTCMinutes() ) +
':' + pad( this.getUTCSeconds() ) +
'.' + (this.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) +
'Z';
};
if (Ember.SHIM_ES5) {
if (!Date.prototype.toISOString) {
Date.prototype.toISOString = toISOString;
}
}
__exports__["default"] = Transform.extend({
deserialize: function(serialized) {
var type = typeof serialized;
if (type === "string") {
return new Date(Ember.Date.parse(serialized));
} else if (type === "number") {
return new Date(serialized);
} else if (serialized === null || serialized === undefined) {
// if the value is not present in the data,
// return undefined, not null.
return serialized;
} else {
return null;
}
},
serialize: function(date) {
if (date instanceof Date) {
return toISOString.call(date);
} else {
return null;
}
}
});
});
define("ember-data/transforms/number",
["ember-data/transforms/base","exports"],
function(__dependency1__, __exports__) {
"use strict";
var Transform = __dependency1__["default"];
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
*/
__exports__["default"] = Transform.extend({
deserialize: function(serialized) {
return empty(serialized) ? null : Number(serialized);
},
serialize: function(deserialized) {
return empty(deserialized) ? null : Number(deserialized);
}
});
});
define("ember-data/transforms/string",
["ember-data/transforms/base","exports"],
function(__dependency1__, __exports__) {
"use strict";
var Transform = __dependency1__["default"];
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
*/
__exports__["default"] = Transform.extend({
deserialize: function(serialized) {
return none(serialized) ? null : String(serialized);
},
serialize: function(deserialized) {
return none(deserialized) ? null : String(deserialized);
}
});
});
define("ember-inflector",
["./system","./helpers","./ext/string","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __exports__) {
"use strict";
var Inflector = __dependency1__.Inflector;
var defaultRules = __dependency1__.defaultRules;
var pluralize = __dependency1__.pluralize;
var singularize = __dependency1__.singularize;
Inflector.defaultRules = defaultRules;
Ember.Inflector = Inflector;
Ember.String.pluralize = pluralize;
Ember.String.singularize = singularize;
__exports__["default"] = Inflector;
__exports__.pluralize = pluralize;
__exports__.singularize = singularize;
});
define("ember-inflector/ext/string",
["../system/string"],
function(__dependency1__) {
"use strict";
var pluralize = __dependency1__.pluralize;
var singularize = __dependency1__.singularize;
if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) {
/**
See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}}
@method pluralize
@for String
*/
String.prototype.pluralize = function() {
return pluralize(this);
};
/**
See {{#crossLink "Ember.String/singularize"}}{{/crossLink}}
@method singularize
@for String
*/
String.prototype.singularize = function() {
return singularize(this);
};
}
});
define("ember-inflector/helpers",
["./system/string"],
function(__dependency1__) {
"use strict";
var singularize = __dependency1__.singularize;
var pluralize = __dependency1__.pluralize;
/**
*
* If you have Ember Inflector (such as if Ember Data is present),
* singularize a word. For example, turn "oxen" into "ox".
*
* Example:
*
* {{singularize myProperty}}
* {{singularize "oxen"}}
*
* @for Ember.Handlebars.helpers
* @method singularize
* @param {String|Property} word word to singularize
*/
Ember.Handlebars.helper('singularize', singularize);
/**
*
* If you have Ember Inflector (such as if Ember Data is present),
* pluralize a word. For example, turn "ox" into "oxen".
*
* Example:
*
* {{pluralize myProperty}}
* {{pluralize "oxen"}}
*
* @for Ember.Handlebars.helpers
* @method pluralize
* @param {String|Property} word word to pluralize
*/
Ember.Handlebars.helper('pluralize', pluralize);
});
define("ember-inflector/system",
["./system/inflector","./system/string","./system/inflections","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __exports__) {
"use strict";
var Inflector = __dependency1__["default"];
var pluralize = __dependency2__.pluralize;
var singularize = __dependency2__.singularize;
var defaultRules = __dependency3__["default"];
Inflector.inflector = new Inflector(defaultRules);
__exports__.Inflector = Inflector;
__exports__.singularize = singularize;
__exports__.pluralize = pluralize;
__exports__.defaultRules = defaultRules;
});
define("ember-inflector/system/inflections",
["exports"],
function(__exports__) {
"use strict";
__exports__["default"] = {
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'
]
};
});
define("ember-inflector/system/inflector",
["exports"],
function(__exports__) {
"use strict";
var BLANK_REGEX = /^\s*$/;
var LAST_WORD_DASHED_REGEX = /(\w+[_-])([a-z\d]+$)/;
var LAST_WORD_CAMELIZED_REGEX = /(\w+)([A-Z][a-z\d]*$)/;
var CAMELIZED_REGEX = /[A-Z][a-z\d]*$/;
function loadUncountable(rules, uncountable) {
for (var i = 0, length = uncountable.length; i < length; i++) {
rules.uncountable[uncountable[i].toLowerCase()] = true;
}
}
function loadIrregular(rules, irregularPairs) {
var pair;
for (var i = 0, length = irregularPairs.length; i < length; i++) {
pair = irregularPairs[i];
//pluralizing
rules.irregular[pair[0].toLowerCase()] = pair[1];
rules.irregular[pair[1].toLowerCase()] = pair[1];
//singularizing
rules.irregularInverse[pair[1].toLowerCase()] = pair[0];
rules.irregularInverse[pair[0].toLowerCase()] = pair[0];
}
}
/**
Inflector.Ember provides a mechanism for supplying inflection rules for your
application. Ember includes a default set of inflection rules, and provides an
API for providing additional rules.
Examples:
Creating an inflector with no rules.
```js
var inflector = new Ember.Inflector();
```
Creating an inflector with the default ember ruleset.
```js
var inflector = new Ember.Inflector(Ember.Inflector.defaultRules);
inflector.pluralize('cow'); //=> 'kine'
inflector.singularize('kine'); //=> 'cow'
```
Creating an inflector and adding rules later.
```javascript
var inflector = Ember.Inflector.inflector;
inflector.pluralize('advice'); // => 'advices'
inflector.uncountable('advice');
inflector.pluralize('advice'); // => 'advice'
inflector.pluralize('formula'); // => 'formulas'
inflector.irregular('formula', 'formulae');
inflector.pluralize('formula'); // => 'formulae'
// you would not need to add these as they are the default rules
inflector.plural(/$/, 's');
inflector.singular(/s$/i, '');
```
Creating an inflector with a nondefault ruleset.
```javascript
var rules = {
plurals: [ /$/, 's' ],
singular: [ /\s$/, '' ],
irregularPairs: [
[ 'cow', 'kine' ]
],
uncountable: [ 'fish' ]
};
var inflector = new Ember.Inflector(rules);
```
@class Inflector
@namespace Ember
*/
function Inflector(ruleSet) {
ruleSet = ruleSet || {};
ruleSet.uncountable = ruleSet.uncountable || makeDictionary();
ruleSet.irregularPairs = ruleSet.irregularPairs || makeDictionary();
var rules = this.rules = {
plurals: ruleSet.plurals || [],
singular: ruleSet.singular || [],
irregular: makeDictionary(),
irregularInverse: makeDictionary(),
uncountable: makeDictionary()
};
loadUncountable(rules, ruleSet.uncountable);
loadIrregular(rules, ruleSet.irregularPairs);
this.enableCache();
}
if (!Object.create && !Object.create(null).hasOwnProperty) {
throw new Error("This browser does not support Object.create(null), please polyfil with es5-sham: http://git.io/yBU2rg");
}
function makeDictionary() {
var cache = Object.create(null);
cache['_dict'] = null;
delete cache['_dict'];
return cache;
}
Inflector.prototype = {
/**
@public
As inflections can be costly, and commonly the same subset of words are repeatedly
inflected an optional cache is provided.
@method enableCache
*/
enableCache: function() {
this.purgeCache();
this.singularize = function(word) {
this._cacheUsed = true;
return this._sCache[word] || (this._sCache[word] = this._singularize(word));
};
this.pluralize = function(word) {
this._cacheUsed = true;
return this._pCache[word] || (this._pCache[word] = this._pluralize(word));
};
},
/**
@public
@method purgedCache
*/
purgeCache: function() {
this._cacheUsed = false;
this._sCache = makeDictionary();
this._pCache = makeDictionary();
},
/**
@public
disable caching
@method disableCache;
*/
disableCache: function() {
this._sCache = null;
this._pCache = null;
this.singularize = function(word) {
return this._singularize(word);
};
this.pluralize = function(word) {
return this._pluralize(word);
};
},
/**
@method plural
@param {RegExp} regex
@param {String} string
*/
plural: function(regex, string) {
if (this._cacheUsed) { this.purgeCache(); }
this.rules.plurals.push([regex, string.toLowerCase()]);
},
/**
@method singular
@param {RegExp} regex
@param {String} string
*/
singular: function(regex, string) {
if (this._cacheUsed) { this.purgeCache(); }
this.rules.singular.push([regex, string.toLowerCase()]);
},
/**
@method uncountable
@param {String} regex
*/
uncountable: function(string) {
if (this._cacheUsed) { this.purgeCache(); }
loadUncountable(this.rules, [string.toLowerCase()]);
},
/**
@method irregular
@param {String} singular
@param {String} plural
*/
irregular: function (singular, plural) {
if (this._cacheUsed) { this.purgeCache(); }
loadIrregular(this.rules, [[singular, plural]]);
},
/**
@method pluralize
@param {String} word
*/
pluralize: function(word) {
return this._pluralize(word);
},
_pluralize: function(word) {
return this.inflect(word, this.rules.plurals, this.rules.irregular);
},
/**
@method singularize
@param {String} word
*/
singularize: function(word) {
return this._singularize(word);
},
_singularize: function(word) {
return this.inflect(word, this.rules.singular, this.rules.irregularInverse);
},
/**
@protected
@method inflect
@param {String} word
@param {Object} typeRules
@param {Object} irregular
*/
inflect: function(word, typeRules, irregular) {
var inflection, substitution, result, lowercase, wordSplit,
firstPhrase, lastWord, isBlank, isCamelized, isUncountable,
isIrregular, isIrregularInverse, rule;
isBlank = BLANK_REGEX.test(word);
isCamelized = CAMELIZED_REGEX.test(word);
firstPhrase = "";
if (isBlank) {
return word;
}
lowercase = word.toLowerCase();
wordSplit = LAST_WORD_DASHED_REGEX.exec(word) || LAST_WORD_CAMELIZED_REGEX.exec(word);
if (wordSplit){
firstPhrase = wordSplit[1];
lastWord = wordSplit[2].toLowerCase();
}
isUncountable = this.rules.uncountable[lowercase] || this.rules.uncountable[lastWord];
if (isUncountable) {
return word;
}
isIrregular = irregular && (irregular[lowercase] || irregular[lastWord]);
if (isIrregular) {
if (irregular[lowercase]){
return isIrregular;
}
else {
isIrregular = (isCamelized) ? isIrregular.capitalize() : isIrregular;
return firstPhrase + isIrregular;
}
}
for (var i = typeRules.length, min = 0; i > min; i--) {
inflection = typeRules[i-1];
rule = inflection[0];
if (rule.test(word)) {
break;
}
}
inflection = inflection || [];
rule = inflection[0];
substitution = inflection[1];
result = word.replace(rule, substitution);
return result;
}
};
__exports__["default"] = Inflector;
});
define("ember-inflector/system/string",
["./inflector","exports"],
function(__dependency1__, __exports__) {
"use strict";
var Inflector = __dependency1__["default"];
function pluralize(word) {
return Inflector.inflector.pluralize(word);
}
function singularize(word) {
return Inflector.inflector.singularize(word);
}
__exports__.pluralize = pluralize;
__exports__.singularize = singularize;
});
global.DS = requireModule('ember-data')['default'];
})(this);


THE DAILY MISSAL
Version 1.00
Copyright
© St Paul Communications/Daughters of
ISBN
9966-08-579-3
Year
of publication 2012
Year
of electronic publication 2013
Liturgical texts: Copyright
© 2002 Libreria Editrice Vaticana,
Libreria Editrice Vaticana omnia sibi
vindicat iura. Sine ejusdem licentia scripto
data
nemini liceat hunc Missalem Romanum denuo imprimere aut in aliam linguam
vertere.
New
English Translation of The Roman Missal 2010,
granted recognitio by
the
Congregation
for Divine Worship and the Discipline of the Sacraments, for the
dioceses
of the Bishops’ Conference of:
(Prot.
N. 566/07/L);
247/11/L);
The
English translation and Chants of The
Roman Missal © 2010 International
Commission on English in the Liturgy
Corporation. All rights reserved.
Revised Standard Version Bible, Catholic
Edition © 1965, 1966, Division of
Christian
Education of the National Council of the Churches of Christ in the United
States of
Revised Standard Version Bible, Ignatius
Press, © 2006, Division of Christian
Education
of the National Council of the Churches of Christ in the
of
Psalms
reprinted from The Revised Grail Psalms ©
2010 Conception Abbey/The
Grail, admin.
by GIA Publications, Inc., www.giamusic.com. All
rights reserved.
The Revised Grail Psalms were
confirmed by decree of the Congregation for Divine
Worship and the Discipline of the
Sacraments on March 19, 2010 (Prot. N. 172/09/L).
General Editor: Fr Rinaldo Ronzani, mccj
Electronic Version Editor: Fernando Aizpun
Cum originali concordat X
Rt Rev. Edward Gabriel Risi, OMI
Bishop
of Keimoes-Upington (
Imprimatur: Most Rev.
Felix Alaba Job
Archbishop
of
President,
Catholic Bishops Conference of
Paulines
Publications
Email:
<EMAIL_ADDRESS>Website:
www.paulinesafrica.org


--- layout: post permalink: priceangels.html Tags: Array NameOfCoupon: Price Angels Cash Back Summary: See our Price Angels CO., Ltd Coupon Code, Price Angels CO., Ltd Rebate, Price Angels CO., Ltd Promo Code, Price Angels CO., Ltd Discount, Price Angels CO., Ltd Coupon Cash Back Rebate here. MetaKeywords: Price Angels Coupon Code, Price Angels Rebate, Price Angels Promo Code, Price Angels Cash Back Rebate, Price Angels Discount, Price Angels Coupon Image: images/28411.png LinkURL: http://www.shareasale.com/r.cfm?b=244016&u=412002&m=28411 affiliate_url_link: http://www.icouponblog.com/jane.php?id=2654 thesis_readmore: See the Price Angels Coupon thesis_thumb: http://www.icouponblog.com/tn.php?merchantURL=priceangels.com Title: Save 4% - Price Angels Coupon Code for priceangels.com. Price Angels Rebate & Discount thesis_description: Our Price Angels Discount Coupon Code for priceangels.com. We have the best Price Angels Rebate anywhere. thesis_keywords: Price Angels, Price Angels Coupon Code, Price Angels Discount, Price Angels Rebate product_name: Price Angels hop_url: http://www.icouponblog.com/hop.php?id=2654 ---
If you want to get the best prices on over 10,000 consumer electronics, computer accessories, video games, iPod and iPhone accessories, flashlight and much more, visit priceangels.com. You will get the most unbeatable wholesale prices on all items. The items will be delivered to you free of cost, anywhere in the world, fast and furious. Why settle for less, when you can get so much quality, at such low prices on priceangels.com. Use our discount coupons to save even more!
Get the coolest gadgets at the right price. Get computer, laptop batteries, microphones, hardware parts, stereo speakers, blank CD, DVD, Blu Ray, headsets, and so much more for amazingly low prices. Check it out online at priceangels.com. You can also buy car accessories, FM transmitters, blue tooth, cell phone accessories for all brands, flashlights and lasers and many other items. Whatever you need, there is an item waiting to be shipped to you free at lightning speed at the most unbeatable price imaginable. Check it out priceangels.com.
Visit priceangels.com. Use their user friendly website to find over 10,000 electronic items accessories for your computer, iPod, iPhone, and other brands of cell phones. Buy everything you need from priceangels.com. You will not only get quality items but you will get them real cheap. Shipping is free of charge anywhere in the world.


She likes to keep things simple and she does. She doesn't overthink. A very if-else-ish person.
She's an introvert and is totally okay with it. Likes her own circle and doesn't want that circle to grow. She's totally content and happy with the number and type of friends she has. Prefers quality over quantity.
Likely to be found indoors with close friends watching TV. Rarely found in pubs partying with strangers. And if you find her in any such social gathering, You'll notice 3 things -
Currently she works in Infosys as a Systems Engineer. And she's fairly good at that. The best thing about her is that she doesn't give up if it gets tough at work. She hangs in there and finds out a solution using whatever she has. And almost every time gets things done.
As of now her plan is to switch to some other company in her hometown after she gets promoted to senior systems engineer.
She has also thought of doing MBA sometime in the future. As of now the time is not certain.
So far she's okay with her job if not extremely excited. She has always been able to complete what has been assigned to her. And she can code. So.. so far so good.
She's into Music. Loves singing. Sings well. A lot better than just well considering she's never had any official training.
She wants to have her own Youtube channel someday where she can upload her cover songs and maybe some of her own tunes. As of now she's singing on some online kareoke apps like Starmaker.
 And if that works out for her then her best friend Petu might build her a website for her to share her music over there as well.
Lets just make this one a list -
Lets keep things even and make this one also a list -


Helene's IT 162 Portal - Seattle Central College Spring 2021
Welcome
Hello, and welcome on my portal for the IT 162 class!
My name is Helene, which is pronounced Ellen (hence my domain's name, "ellencodes.com"!). The original spelling is because I am French. I have been an international student at Seattle Central College for a year now, and love learning how to code and create websites; I am planning on getting an AAS in Programming.
When I am not studying, I love to hike and to travel. Traveling has been quite challenging in the last few months, so I am focusing on exploring the gorgeous state I am currently living in; Washington State.
While I am still learning and improving my skills, especially in HTML, CSS and JavaScript, I would love to expend my network and connection, so please feel free to contact me.


Using the controls below you'll be able to experiment with the ProgressTimer API right here in your browser. For more usage info see https://github.com/adamcik/media-progress-timer.
ProgressTimer
setTimeout
setTimout
requestAnimationFrame
set


It will transform all letter in your text into Upper Case letter
It will transform all letter in your text into lower case letter
It will transform first letter of each words in your text into Upper Case letter and remaining letters of each word in your text into lower case letter.
It will transform first letter of each words in your text into Upper Case letter and remaining letters of each word in your text into lower case letter.
It will transform all odd position letter into lower case and all even position letter into Upper case in your text
It will transform all even position letter into lower case and all odd position letter into Upper case in your text
It will transform all Upper Case into Lower Case and Lower Case into Upper Case in your text.
It will transform all text into Italic Like- Hello -> Hello
It will transform all text into Bold Style.
It will Reverse all text.
It will copy text from textarea into your Clipboard
It will Clear all text from textarea
It will download Your Text in your local computer as txt file


Lorem Ipsum
Lorem ipsum is a random message text generated by advanced AI and a team of QA engineers
Lorem Ipsum
Lorem ipsum is a random message text generated by advanced AI and a team of QA engineers
Lorem Ipsum
Lorem ipsum is a random message text generated by advanced AI and a team of QA engineers
Lorem Ipsum
Lorem ipsum is a random message text generated by advanced AI and a team of QA engineers
Lorem Ipsum
Lorem ipsum is a random message text generated by advanced AI and a team of QA engineers
Lorem Ipsum
Lorem ipsum is a random message text generated by advanced AI and a team of QA engineers
Lorem Ipsum
Lorem ipsum is a random message text generated by advanced AI and a team of QA engineers
Lorem Ipsum
Lorem ipsum is a random message text generated by advanced AI and a team of QA engineers


Provides routines for finding an Optimal System of Distinct Representatives (OSDR), as defined by D.Gale (1968) <doi:10.1016/S0021-9800(68)80039-0>.
| Version: | 1.1.2 |
| Suggests: | optrees, optmatch |
| Published: | 2018-12-08 |
| Author: | Massimo Cannas [aut, cre] |
| Maintainer: | Massimo Cannas <massimo.cannas at unica.it> |
| License: | GPL-2 |
| NeedsCompilation: | no |
| CRAN checks: | OSDR results |
| Reference manual: | OSDR.pdf |
| Package source: | OSDR_1.1.2.tar.gz |
| Windows binaries: | r-devel: OSDR_1.1.2.zip, r-release: OSDR_1.1.2.zip, r-oldrel: OSDR_1.1.2.zip |
| OS X binaries: | r-release: OSDR_1.1.2.tgz, r-oldrel: OSDR_1.1.2.tgz |
| Old sources: | OSDR archive |
Please use the canonical form https://CRAN.R-project.org/package=OSDR to link to this page.


Draw anything in the white area.
Size:
1
2
3
4
5
10
20
30
40
50
Color:
#FFFFFF
#AAAAAA
#999999
#000000
#9BA16C
#CC8F2B
#63631D
#00FF00
Pen
NewPage
Line
Rectangle
Circle
Triangle
RightTriangle
Ellipse
FilledRectangle
FilledCircle
FilledTriangle
FilledRightTriangle
FilledEllipse
Trapezium
+
‹
›
calc
LOADING
this is
your phone number
call link:
https://...
...834y8uask
Click 'Allow' to go
Full Screen
Allow
Cancel
1
2
3
4
5
1


var friendRequests: HashMap<String, FriendRequest>
The friend requests of this user
friendRequests - The friend requests of this user
friendRequests


Darlene Holland
About
Portfolio
Contact
Projects
Bamazon
FriendFinder
Burger App
Burger-Sequelize App
React Clicky Game
NYT Article Search
1
2
3
Connect with Me


Tricking is a relatively new acrobatic sport or hobby that borrows moves from martial arts, gymnastics and breakdancing.
Tricking athletes put together kicks, flips, twists, and ground moves in creative combinations, sometimes just for fun and sometimes in "battles" of friendly compeition. Some trickers describe it as the ultimate form of movement and expression.
Tricking began in the 1990s, as martial artists looked for ways to add more flare into their competition performances. Since then, tricking has grown past “extreme martial arts” into its own activity.
Trickers are now a devoted international community of athletes who take joy and pride in challenging themselves to throw their body around in impressive ways.
If you've seen The Avengers, or The Matrix movies, or Cirque du Soleil, you've seen trickers in action. One career path for good martial artist trickers is to become a stunt double, fight choreographer, or even Cirque du Soleil performer. Tricking is what makes the flips, kicks and gymastics action so exciting to watch.
Here's a fun vidoe of a tricker and parkour athlete recreating stunts from the movie The Avengers: Age of Ultron, where you can see the movie stunt side-by-side.
I started learning tricking as part of competing in martial arts tournaments. For tricking, I train mostly at a place called Loopkicks in Santa Clara. It's a center for tricking that is actually known internationally and a great place to watch and learn from amazing athletes. They offer tricking classes, private lessons, open gyms and battles for people of all abilities.
Here are some resources to get started.


98% aspirants clear D.El.Ed. test
by Special CorrespondentOf the total 38,443 candidates who appeared for the D.El.Ed. (Diploma in Elementary Education 2017-19) 35,649 of them have passed, recording a pass percentage of 97.73 %. The examinations were held from September 27 to October 4.
A statement issued by the Director of Government Examinations on Wednesday said the dummy memorandum of marks were hosted on the website www.bseap.org for information of the candidates.
Candidates intending to apply for recounting of marks should submit their applications along with fee challan directly to this office by December 5, indicating the subject for which recounting is required. A copy of the dummy marks memo and a self-addressed envelop with required postal stamps should be enclosed to the application. The fee for recounting of marks is ₹500 per subject.


Rescuers searching for 2 after shrimp boat capsizes
by Associated PressMOBILE, Ala. (AP) — Two crew members are missing after a shrimp boat overturned.
The U.S. Coast Guard Sector Mobile says the vessel overturned Friday morning. The accident happened about five miles (8 kilometers) from the entrance of Mobile Bay.
The Alabama Law Enforcement Agency said that the accident involved a 50-foot (15-meter) shrimp boat named “The Chief.” The boats captain, Woody Jones of Bon Secour, was rescued by the crew of another shrimp boat.
The Coast Guard and local agencies are searching for two other people who were on board.


This is just a start page for your Progressive Web Application, to demonstrate PWAssist functionality.


Input Teradata
Input Teradata as the name suggests will unload records from database into a job where source could be either source table name and is present under the Input category in the component palette.
This Component will unload records from database into a job where source could be either source table name or an SQL statements that will select data from one or multiple tables for the further processing of particular job.
The Input Teradata component can be easily distinguished in the component palette.
An enlarged version of the same is depicted when dragged on the canvas.
For further reference click on the links below:


| The Mission Operations Control Room was the focal point for all the activities of the Mission Control Center. At any time during an Apollo mission, one of the four flight control teams would be manning these consoles. Each controller in this room was supported in his operation by other people and facilities, both in the staff support areas within the building and in the world outside the Center. Since the completion of the Apollo missions, this room and the support areas have been reconfigured for other manned space programs like Skylab and Apollo-Soyuz. |


Lake Macquarie Memorial Park to host Remembrance Day ceremony at Ryhope on November 11
AUSTRALIAN members of the armed services who served and perished in wars, conflicts and peacekeeping operations will be remembered in a ceremony at Ryope on Monday.
Lake Macquarie Memorial Park will host a dedicated Remembrance Day ceremony from 5.30pm.
"This event is part of a global day of reverence for the heroic people who have lost their lives for their country, including the brave Anzacs," the park's family service manager Garry Bellenger said.
"We are humbled to provide this opportunity to pay respects to our soldiers and continue their legacy. It's an important occasion to ensure their memory and the gratitude for their service lives on, in this generation and the next."
Remembrance Day evolved from Armistice Day, and traditionally features a moment of silence at 11am. It is observed each year on November 11 to mark the official end to hostilities in World War I in 1918.
"Remembrance Day is more than a memorial. It's also a celebration of our beautiful and distinguished nation, which is sustained by the men and women who bravely serve this country," Mr Bellenger said.
The event at Ryhope will include laying of tributes by community members and local leaders, a speech by Toronto RSL Sub-branch president Ron Mitcherson, refreshments, and a performance by the female musical duo Librans.
Lake Macquarie Memorial Park encourages all locals, and particularly veterans' groups, historical, RSL and ex-service organisations, schools, and families and friends of deceased veterans, to attend.
Visit lakemacquariecrem.com.au


| Modifier and Type | Field and Description |
|---|---|
private static float |
BUTTON_DISTANCE
Distance between Buttons and other stage elements.
|
private static float |
BUTTON_HEIGHT
Height of the Options Menu's Buttons.
|
private static float |
BUTTON_WIDTH
Width of the Options Menu's Buttons.
|
protected Armadillo |
game
The current game session.
|
private HudMenu |
hud
The Hud associated to the current game being played by the User.
|
private static float |
HUD_VIEWPORT_HEIGHT
The height of the viewport in pixels.
|
private static float |
HUD_VIEWPORT_WIDTH
The width of the HUD viewport in pixels.
|
private static float |
LABEL_DISTANCE
Distance between the Labels and the other stage elements
|
protected com.badlogic.gdx.scenes.scene2d.Stage |
menu
A Stage used to represent the Menu that appears when the game is paused / over / won.
|
protected com.badlogic.gdx.scenes.scene2d.ui.Label |
message
Message displayed in the Screen, when the pop up Menu appears.
|
private static float |
MESSAGE_FONT_SCALE
The Scale that should be applied to the Message Label's Font.
|
private static float |
SCORE_FONT_SCALE
The Scale that should be applied to the Score Label's Font.
|
private com.badlogic.gdx.scenes.scene2d.ui.Skin |
skin
Skin used in the table elements.
|
private com.badlogic.gdx.scenes.scene2d.ui.Table |
table
The table containing the elements, that will be added to the stage.
|
| Modifier | Constructor and Description |
|---|---|
protected |
OptionsMenu(com.badlogic.gdx.utils.viewport.Viewport viewport,
Armadillo game,
HudMenu hud)
Options Menu Constructor.
|
| Modifier and Type | Method and Description |
|---|---|
protected void |
addExitBtn()
Function that adds an Exit Button to the Stage.
|
protected void |
addLeaderboardBtn()
Function that adds a Button responsible for showing the Leaderboard of the current Level.
|
protected void |
addNextLvlBtn()
Function that adds a Next Level Button to the Stage.
|
protected void |
addRestartBtn()
Function that adds a Restart Button to the Stage.
|
protected void |
addResumeBtn()
Function that adds a Resume Button to the Stage.
|
protected abstract void |
confStage()
Function responsible for configure the Stage that contains the Pop Up Menu's elements.
|
void |
draw()
Function used to draw the Pop Up Menu in the screen.
|
protected void |
finishStage()
Function used by all the Pop Up Menus for ending the final procedures of the stage configuration.
|
protected void |
initStage()
Function used by all the Pop Up Menus for starting the initial procedures of the stage configuration.
|
private void |
loadLevel()
Function used to load the next available Game level.
|
protected abstract void |
setMessage()
Function used to set the Pop Up Menu's message accordingly.
|
private void |
startLevel()
Function used to start a new Game level.
|
private void |
togglePause()
Function used to pause or unpause the current Game level.
|
protected Armadillo game
private HudMenu hud
protected com.badlogic.gdx.scenes.scene2d.Stage menu
private com.badlogic.gdx.scenes.scene2d.ui.Table table
protected com.badlogic.gdx.scenes.scene2d.ui.Label message
private com.badlogic.gdx.scenes.scene2d.ui.Skin skin
private static final float HUD_VIEWPORT_WIDTH
private static final float HUD_VIEWPORT_HEIGHT
private static final float MESSAGE_FONT_SCALE
private static final float SCORE_FONT_SCALE
private static final float LABEL_DISTANCE
private static final float BUTTON_WIDTH
private static final float BUTTON_HEIGHT
private static final float BUTTON_DISTANCE
protected OptionsMenu(com.badlogic.gdx.utils.viewport.Viewport viewport, Armadillo game, HudMenu hud)
viewport
- The viewport that will be associated to the stage.game
- The current game session.hud
- The current Hud, associated to the current game being played.public void draw()
protected void addExitBtn()
protected void addRestartBtn()
protected void addLeaderboardBtn()
protected void addResumeBtn()
protected void addNextLvlBtn()
private void togglePause()
private void startLevel()
private void loadLevel()
protected void initStage()
protected void finishStage()
protected abstract void confStage()
protected abstract void setMessage()


In each dialog box, information is available for each control. There are three ways to get help on a control:
· Click the question mark box in the upper right-hand corner of the dialog box and with the help-activated pointer, select a control in the dialog box.
· Press the TAB key until the desired control is highlighted and then press F1.
· Right click on a control and the What’s This button will appear. Click the What’s This button to get the control help.