<commit_before>'use strict';

import {Nymph, NymphClassNotAvailableError} from './Nymph';

const sleepErr = 'This entity is in a sleeping reference state. You must use .ready().then() to wake it.';

const isArray = (Array.isArray || function (arr) {
  return Object.prototype.toString.call(arr) === '[object Array]';
});

const indexOf = function (array, item) {
  for (let i = 0; i < array.length; i++) {
    if (array[i] === item) {
      return i;
    }
  }
  return -1;
};

const map = function (arr, fn) {
  const results = [];
  for (let i = 0; i < arr.length; i++) {
    results.push(fn(arr[i], i));
  }
  return results;
};

const arrayUnique = function (array) {
  let a = array.concat();
  for (let i = 0; i < a.length; ++i) {
    for (let j = i + 1; j < a.length; ++j) {
      if (a[i] === a[j]) {
        a.splice(j--, 1);
      }
    }
  }
  return a;
};

const onlyStrings = function (array) {
  const newArray = [];
  for (let i = 0; i < array.length; i++) {
    if (typeof array[i] === 'string') {
      newArray.push(array[i]);
    } else {
      if (typeof array[i].toString === 'function') {
        newArray.push(array[i].toString());
      }
    }
  }
  return newArray;
};

const getDataReference = function (item) {
  if (item instanceof Entity && typeof item.toReference === 'function') {
    // Convert entities to references.
    return item.toReference();
  } else if (isArray(item)) {
    // Recurse into lower arrays.
    return map(item, getDataReference);
  } else if (item instanceof Object) {
    let newObj;
    if (Object.create) {
      newObj = Object.create(item);
    } else {
      const F = function () {};
      F.prototype = item;
      newObj = new F();
    }
    for (let k in item) {
      if (item.hasOwnProperty(k)) {
        newObj[k] = getDataReference(item[k]);
      }
    }
    return newObj;
  }
  // Not an entity or array, just return it.
  return item;
};

const getSleepingReference = function (item) {
  if (isArray(item)) {
    // Check if it's a reference.
    if (item[0] === 'nymph_entity_reference') {
      const EntityClass = Nymph.getEntityClass(item[2]);
      if (!EntityClass) {
        throw new NymphClassNotAvailableError(item[2] + ' class cannot be found.');
      }
      const entity = new (EntityClass)();
      entity.referenceSleep(item);
      return entity;
    } else {
      // Recurse into lower arrays.
      return map(item, getSleepingReference);
    }
  } else if (item instanceof Object && !(item instanceof Entity)) {
    for (let k in item) {
      if (item.hasOwnProperty(k)) {
        item[k] = getSleepingReference(item[k]);
      }
    }
  }
  // Not an array, just return it.
  return item;
};

const sortObj = function (obj) { // adapted from http://am.aurlien.net/post/1221493460/sorting-javascript-objects
  const tempArray = [];
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      tempArray.push(key);
    }
  }
  tempArray.sort();
  const tempObj = {};
  for (let i = 0; i < tempArray.length; i++) {
    tempObj[tempArray[i]] = obj[tempArray[i]];
  }
  return tempObj;
};

export class Entity {
  // === Constructor ===

  constructor (id) {
    // === Instance Properties ===

    this.guid = null;
    this.cdate = null;
    this.mdate = null;
    this.tags = [];
    this.data = {};
    this.isASleepingReference = false;
    this.sleepingReference = false;
    this.readyPromise = null;

    if (typeof id !== 'undefined' && !isNaN(parseInt(id, 10))) {
      this.guid = parseInt(id, 10);
      this.isASleepingReference = true;
      this.sleepingReference = ['nymph_entity_reference', this.guid, this.constructor.class];
      this.ready();
    }
  }

  // === Static Methods ===

  static serverCallStatic (method, params) {
    // Turn the params into a real array, in case an arguments object was passed.
    const paramArray = Array.prototype.slice.call(params);
    return new Promise((resolve, reject) => {
      Nymph.serverCallStatic(this.class, method, paramArray).then((data) => {
        resolve(data.return);
      }, (errObj) => {
        reject(errObj);
      });
    });
  }

  // === Instance Methods ===

  init (entityData) {
    if (entityData == null) {
      return this;
    }

    this.isASleepingReference = false;
    this.sleepingReference = false;

    this.guid = entityData.guid;
    this.cdate = entityData.cdate;
    this.mdate = entityData.mdate;
    this.tags = entityData.tags;
    this.data = entityData.data;
    if (!(entityData instanceof Entity)) {
      for (let k in this.data) {
        if (this.data.hasOwnProperty(k)) {
          this.data[k] = getSleepingReference(this.data[k]);
        }
      }
    }

    return this;
  }

  // Tag methods.
  addTag (...tags) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (isArray(tags[0])) {
      tags = tags[0];
    }
    this.tags = onlyStrings(arrayUnique(this.tags.concat(tags)));
  }

  hasTag (...tags) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (isArray(tags[0])) {
      tags = tags[0];
    }
    for (let i = 0; i < tags.length; i++) {
      if (indexOf(this.tags, tags[i]) === -1) {
        return false;
      }
    }
    return true;
  }

  removeTag (...tags) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    const newTags = [];
    if (isArray(tags[0])) {
      tags = tags[0];
    }
    for (let i = 0; i < this.tags.length; i++) {
      if (indexOf(tags, this.tags[i]) === -1) {
        newTags.push(this.tags[i]);
      }
    }
    this.tags = newTags;
  }

  // Property getter and setter. You can also just access Entity.data directly.
  get (name = null) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (isArray(name)) {
      const result = {};
      for (let i = 0; i < name.length; i++) {
        result[name[i]] = this.data[name[i]];
      }
      return result;
    } else if (name == null) {
      return this.data;
    } else {
      return this.data[name];
    }
  }

  set (name, value = null) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (typeof name === 'object') {
      for (let k in name) {
        if (name.hasOwnProperty(k)) {
          this.data[k] = name[k];
        }
      }
    } else {
      this.data[name] = value;
    }
  }

  save () {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    return Nymph.saveEntity(this);
  }

  delete () {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    return Nymph.deleteEntity(this);
  }

  is (object) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (!(object instanceof Entity)) {
      return false;
    }
    if ((this.guid && this.guid > 0) || (object.guid && object.guid > 0)) {
      return this.guid === object.guid;
    } else if (typeof object.toJSON !== 'function') {
      return false;
    } else {
      const obData = sortObj(object.toJSON());
      obData.tags.sort();
      obData.data = sortObj(obData.data);
      const myData = sortObj(this.toJSON());
      myData.tags.sort();
      myData.data = sortObj(myData.data);
      return JSON.stringify(obData) === JSON.stringify(myData);
    }
  }

  equals (object) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (!(object instanceof Entity)) {
      return false;
    }
    if ((this.guid && this.guid > 0) || (object.guid && object.guid > 0)) {
      if (this.guid !== object.guid) {
        return false;
      }
    }
    if (object.constructor.class !== this.constructor.class) {
      return false;
    }
    // return eq(this, object, [], []);
    const obData = sortObj(object.toJSON());
    obData.tags.sort();
    obData.data = sortObj(obData.data);
    const myData = sortObj(this.toJSON());
    myData.tags.sort();
    myData.data = sortObj(myData.data);
    return JSON.stringify(obData) === JSON.stringify(myData);
  }

  inArray (array, strict) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (!isArray(array)) {
      return false;
    }
    for (let i = 0; i < array.length; i++) {
      if (strict ? this.equals(array[i]) : this.is(array[i])) {
        return true;
      }
    }
    return false;
  }

  arraySearch (array, strict) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (!isArray(array)) {
      return false;
    }
    for (let i = 0; i < array.length; i++) {
      if (strict ? this.equals(array[i]) : this.is(array[i])) {
        return i;
      }
    }
    return false;
  }

  refresh () {
    if (this.isASleepingReference) {
      return this.ready();
    }
    if (this.guid === null) {
      return new Promise((resolve) => {
        resolve(this);
      });
    }
    return new Promise((resolve, reject) => {
      Nymph.getEntityData({'class': this.constructor.class}, {'type': '&', 'guid': this.guid}).then((data) => {
        resolve(this.init(data));
      }, (errObj) => {
        reject(errObj);
      });
    });
  }

  serverCall (method, params, dontUpdateAfterCall) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    // Turn the params into a real array, in case an arguments object was passed.
    const paramArray = Array.prototype.slice.call(params);
    return new Promise((resolve, reject) => {
      Nymph.serverCall(this, method, paramArray).then((data) => {
        if (!dontUpdateAfterCall) {
          this.init(data.entity);
        }
        resolve(data.return);
      }, (errObj) => {
        reject(errObj);
      });
    });
  }

  toJSON () {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    const obj = {};
    obj.guid = this.guid;
    obj.cdate = this.cdate;
    obj.mdate = this.mdate;
    obj.tags = this.tags.slice(0);
    obj.data = {};
    for (let k in this.data) {
      if (this.data.hasOwnProperty(k)) {
        obj.data[k] = getDataReference(this.data[k]);
      }
    }
    obj.class = this.constructor.class;
    return obj;
  }

  toReference () {
    if (this.isASleepingReference) {
      return this.sleepingReference;
    }
    if (this.guid === null) {
      return this;
    }
    return ['nymph_entity_reference', this.guid, this.constructor.class];
  }

  referenceSleep (reference) {
    this.isASleepingReference = true;
    this.guid = parseInt(reference[1], 10);
    this.sleepingReference = [...reference];
  }

  ready (success, error) {
    let promise;
    this.readyPromise = promise = new Promise((resolve, reject) => {
      if (!this.isASleepingReference) {
        this.readyPromise = null;
        resolve(this);
        if (typeof success === 'function') {
          success(this);
        }
      } else {
        if (this.readyPromise) {
          this.readyPromise.then(() => {
            resolve(this);
            if (typeof success === 'function') {
              success(this);
            }
          }, (errObj) => {
            reject(errObj);
            if (typeof error === 'function') {
              error(errObj);
            }
          });
        } else {
          Nymph.getEntityData(
            {'class': this.sleepingReference[2]},
            {'type': '&', 'guid': this.sleepingReference[1]}
          ).then((data) => {
            this.readyPromise = null;
            if (data === null) {
              const errObj = {data, textStatus: 'No data returned.'};
              reject(errObj);
              if (typeof error === 'function') {
                error(errObj);
              }
            } else {
              resolve(this.init(data));
              if (typeof success === 'function') {
                success(this);
              }
            }
          }, (errObj) => {
            this.readyPromise = null;
            reject(errObj);
            if (typeof error === 'function') {
              error(errObj);
            }
          });
        }
      }
    });
    return promise;
  }

  readyAll (success, error, level) {
    return new Promise((resolve, reject) => {
      const readyProps = () => {
        let newLevel;
        // If level is undefined, keep going forever, otherwise, stop once we've
        // gone deep enough.
        if (level !== undefined) {
          newLevel = level - 1;
        }
        if (newLevel === undefined || newLevel >= 0) {
          const promises = [];
          for (let k in this.data) {
            if (this.data.hasOwnProperty(k)) {
              if (this.data[k] instanceof Entity && this.data[k].isASleepingReference) {
                promises.push(this.data[k].readyAll(undefined, undefined, newLevel));
              } else if (isArray(this.data[k])) {
                for (let i = 0; i < this.data[k].length; i++) {
                  if (this.data[k][i] instanceof Entity && this.data[k][i].isASleepingReference) {
                    promises.push(this.data[k][i].readyAll(undefined, undefined, newLevel));
                  }
                }
              }
            }
          }
          if (promises.length) {
            Promise.all(promises).then(() => {
              resolve(this);
              if (typeof success === 'function') {
                success(this);
              }
            }, (errObj) => {
              reject(errObj);
              if (typeof error === 'function') {
                error(errObj);
              }
            });
          } else {
            resolve(this);
            if (typeof success === 'function') {
              success(this);
            }
          }
        } else {
          resolve(this);
          if (typeof success === 'function') {
            success(this);
          }
        }
      };

      if (this.isASleepingReference) {
        this.ready(readyProps, (errObj) => {
          reject(errObj);
          if (typeof error === 'function') {
            error(errObj);
          }
        });
      } else {
        readyProps();
      }
    });
  }
}

// === Static Properties ===

// The name of the server class (Shouldn't start with a \)
Entity.class = 'Nymph\\Entity';

Nymph.setEntityClass(Entity.class, Entity);

// === Error Classes ===

export class EntityIsSleepingReferenceError extends Error {
  constructor (message) {
    super(message);
    this.name = 'EntityIsSleepingReferenceError';
  }
}

export default Entity;
<commit_msg>Added note about readyAll's success callback.<commit_after>'use strict';

import {Nymph, NymphClassNotAvailableError} from './Nymph';

const sleepErr = 'This entity is in a sleeping reference state. You must use .ready().then() to wake it.';

const isArray = (Array.isArray || function (arr) {
  return Object.prototype.toString.call(arr) === '[object Array]';
});

const indexOf = function (array, item) {
  for (let i = 0; i < array.length; i++) {
    if (array[i] === item) {
      return i;
    }
  }
  return -1;
};

const map = function (arr, fn) {
  const results = [];
  for (let i = 0; i < arr.length; i++) {
    results.push(fn(arr[i], i));
  }
  return results;
};

const arrayUnique = function (array) {
  let a = array.concat();
  for (let i = 0; i < a.length; ++i) {
    for (let j = i + 1; j < a.length; ++j) {
      if (a[i] === a[j]) {
        a.splice(j--, 1);
      }
    }
  }
  return a;
};

const onlyStrings = function (array) {
  const newArray = [];
  for (let i = 0; i < array.length; i++) {
    if (typeof array[i] === 'string') {
      newArray.push(array[i]);
    } else {
      if (typeof array[i].toString === 'function') {
        newArray.push(array[i].toString());
      }
    }
  }
  return newArray;
};

const getDataReference = function (item) {
  if (item instanceof Entity && typeof item.toReference === 'function') {
    // Convert entities to references.
    return item.toReference();
  } else if (isArray(item)) {
    // Recurse into lower arrays.
    return map(item, getDataReference);
  } else if (item instanceof Object) {
    let newObj;
    if (Object.create) {
      newObj = Object.create(item);
    } else {
      const F = function () {};
      F.prototype = item;
      newObj = new F();
    }
    for (let k in item) {
      if (item.hasOwnProperty(k)) {
        newObj[k] = getDataReference(item[k]);
      }
    }
    return newObj;
  }
  // Not an entity or array, just return it.
  return item;
};

const getSleepingReference = function (item) {
  if (isArray(item)) {
    // Check if it's a reference.
    if (item[0] === 'nymph_entity_reference') {
      const EntityClass = Nymph.getEntityClass(item[2]);
      if (!EntityClass) {
        throw new NymphClassNotAvailableError(item[2] + ' class cannot be found.');
      }
      const entity = new (EntityClass)();
      entity.referenceSleep(item);
      return entity;
    } else {
      // Recurse into lower arrays.
      return map(item, getSleepingReference);
    }
  } else if (item instanceof Object && !(item instanceof Entity)) {
    for (let k in item) {
      if (item.hasOwnProperty(k)) {
        item[k] = getSleepingReference(item[k]);
      }
    }
  }
  // Not an array, just return it.
  return item;
};

const sortObj = function (obj) { // adapted from http://am.aurlien.net/post/1221493460/sorting-javascript-objects
  const tempArray = [];
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      tempArray.push(key);
    }
  }
  tempArray.sort();
  const tempObj = {};
  for (let i = 0; i < tempArray.length; i++) {
    tempObj[tempArray[i]] = obj[tempArray[i]];
  }
  return tempObj;
};

export class Entity {
  // === Constructor ===

  constructor (id) {
    // === Instance Properties ===

    this.guid = null;
    this.cdate = null;
    this.mdate = null;
    this.tags = [];
    this.data = {};
    this.isASleepingReference = false;
    this.sleepingReference = false;
    this.readyPromise = null;

    if (typeof id !== 'undefined' && !isNaN(parseInt(id, 10))) {
      this.guid = parseInt(id, 10);
      this.isASleepingReference = true;
      this.sleepingReference = ['nymph_entity_reference', this.guid, this.constructor.class];
      this.ready();
    }
  }

  // === Static Methods ===

  static serverCallStatic (method, params) {
    // Turn the params into a real array, in case an arguments object was passed.
    const paramArray = Array.prototype.slice.call(params);
    return new Promise((resolve, reject) => {
      Nymph.serverCallStatic(this.class, method, paramArray).then((data) => {
        resolve(data.return);
      }, (errObj) => {
        reject(errObj);
      });
    });
  }

  // === Instance Methods ===

  init (entityData) {
    if (entityData == null) {
      return this;
    }

    this.isASleepingReference = false;
    this.sleepingReference = false;

    this.guid = entityData.guid;
    this.cdate = entityData.cdate;
    this.mdate = entityData.mdate;
    this.tags = entityData.tags;
    this.data = entityData.data;
    if (!(entityData instanceof Entity)) {
      for (let k in this.data) {
        if (this.data.hasOwnProperty(k)) {
          this.data[k] = getSleepingReference(this.data[k]);
        }
      }
    }

    return this;
  }

  // Tag methods.
  addTag (...tags) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (isArray(tags[0])) {
      tags = tags[0];
    }
    this.tags = onlyStrings(arrayUnique(this.tags.concat(tags)));
  }

  hasTag (...tags) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (isArray(tags[0])) {
      tags = tags[0];
    }
    for (let i = 0; i < tags.length; i++) {
      if (indexOf(this.tags, tags[i]) === -1) {
        return false;
      }
    }
    return true;
  }

  removeTag (...tags) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    const newTags = [];
    if (isArray(tags[0])) {
      tags = tags[0];
    }
    for (let i = 0; i < this.tags.length; i++) {
      if (indexOf(tags, this.tags[i]) === -1) {
        newTags.push(this.tags[i]);
      }
    }
    this.tags = newTags;
  }

  // Property getter and setter. You can also just access Entity.data directly.
  get (name = null) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (isArray(name)) {
      const result = {};
      for (let i = 0; i < name.length; i++) {
        result[name[i]] = this.data[name[i]];
      }
      return result;
    } else if (name == null) {
      return this.data;
    } else {
      return this.data[name];
    }
  }

  set (name, value = null) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (typeof name === 'object') {
      for (let k in name) {
        if (name.hasOwnProperty(k)) {
          this.data[k] = name[k];
        }
      }
    } else {
      this.data[name] = value;
    }
  }

  save () {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    return Nymph.saveEntity(this);
  }

  delete () {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    return Nymph.deleteEntity(this);
  }

  is (object) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (!(object instanceof Entity)) {
      return false;
    }
    if ((this.guid && this.guid > 0) || (object.guid && object.guid > 0)) {
      return this.guid === object.guid;
    } else if (typeof object.toJSON !== 'function') {
      return false;
    } else {
      const obData = sortObj(object.toJSON());
      obData.tags.sort();
      obData.data = sortObj(obData.data);
      const myData = sortObj(this.toJSON());
      myData.tags.sort();
      myData.data = sortObj(myData.data);
      return JSON.stringify(obData) === JSON.stringify(myData);
    }
  }

  equals (object) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (!(object instanceof Entity)) {
      return false;
    }
    if ((this.guid && this.guid > 0) || (object.guid && object.guid > 0)) {
      if (this.guid !== object.guid) {
        return false;
      }
    }
    if (object.constructor.class !== this.constructor.class) {
      return false;
    }
    // return eq(this, object, [], []);
    const obData = sortObj(object.toJSON());
    obData.tags.sort();
    obData.data = sortObj(obData.data);
    const myData = sortObj(this.toJSON());
    myData.tags.sort();
    myData.data = sortObj(myData.data);
    return JSON.stringify(obData) === JSON.stringify(myData);
  }

  inArray (array, strict) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (!isArray(array)) {
      return false;
    }
    for (let i = 0; i < array.length; i++) {
      if (strict ? this.equals(array[i]) : this.is(array[i])) {
        return true;
      }
    }
    return false;
  }

  arraySearch (array, strict) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    if (!isArray(array)) {
      return false;
    }
    for (let i = 0; i < array.length; i++) {
      if (strict ? this.equals(array[i]) : this.is(array[i])) {
        return i;
      }
    }
    return false;
  }

  refresh () {
    if (this.isASleepingReference) {
      return this.ready();
    }
    if (this.guid === null) {
      return new Promise((resolve) => {
        resolve(this);
      });
    }
    return new Promise((resolve, reject) => {
      Nymph.getEntityData({'class': this.constructor.class}, {'type': '&', 'guid': this.guid}).then((data) => {
        resolve(this.init(data));
      }, (errObj) => {
        reject(errObj);
      });
    });
  }

  serverCall (method, params, dontUpdateAfterCall) {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    // Turn the params into a real array, in case an arguments object was passed.
    const paramArray = Array.prototype.slice.call(params);
    return new Promise((resolve, reject) => {
      Nymph.serverCall(this, method, paramArray).then((data) => {
        if (!dontUpdateAfterCall) {
          this.init(data.entity);
        }
        resolve(data.return);
      }, (errObj) => {
        reject(errObj);
      });
    });
  }

  toJSON () {
    if (this.isASleepingReference) {
      throw new EntityIsSleepingReferenceError(sleepErr);
    }
    const obj = {};
    obj.guid = this.guid;
    obj.cdate = this.cdate;
    obj.mdate = this.mdate;
    obj.tags = this.tags.slice(0);
    obj.data = {};
    for (let k in this.data) {
      if (this.data.hasOwnProperty(k)) {
        obj.data[k] = getDataReference(this.data[k]);
      }
    }
    obj.class = this.constructor.class;
    return obj;
  }

  toReference () {
    if (this.isASleepingReference) {
      return this.sleepingReference;
    }
    if (this.guid === null) {
      return this;
    }
    return ['nymph_entity_reference', this.guid, this.constructor.class];
  }

  referenceSleep (reference) {
    this.isASleepingReference = true;
    this.guid = parseInt(reference[1], 10);
    this.sleepingReference = [...reference];
  }

  ready (success, error) {
    let promise;
    this.readyPromise = promise = new Promise((resolve, reject) => {
      if (!this.isASleepingReference) {
        this.readyPromise = null;
        resolve(this);
        if (typeof success === 'function') {
          success(this);
        }
      } else {
        if (this.readyPromise) {
          this.readyPromise.then(() => {
            resolve(this);
            if (typeof success === 'function') {
              success(this);
            }
          }, (errObj) => {
            reject(errObj);
            if (typeof error === 'function') {
              error(errObj);
            }
          });
        } else {
          Nymph.getEntityData(
            {'class': this.sleepingReference[2]},
            {'type': '&', 'guid': this.sleepingReference[1]}
          ).then((data) => {
            this.readyPromise = null;
            if (data === null) {
              const errObj = {data, textStatus: 'No data returned.'};
              reject(errObj);
              if (typeof error === 'function') {
                error(errObj);
              }
            } else {
              resolve(this.init(data));
              if (typeof success === 'function') {
                success(this);
              }
            }
          }, (errObj) => {
            this.readyPromise = null;
            reject(errObj);
            if (typeof error === 'function') {
              error(errObj);
            }
          });
        }
      }
    });
    return promise;
  }

  // Please note that the success callback may be run immediately. If you need
  // your callback to be deferred, you should use the returned promise instead.
  readyAll (success, error, level) {
    return new Promise((resolve, reject) => {
      const readyProps = () => {
        let newLevel;
        // If level is undefined, keep going forever, otherwise, stop once we've
        // gone deep enough.
        if (level !== undefined) {
          newLevel = level - 1;
        }
        if (newLevel === undefined || newLevel >= 0) {
          const promises = [];
          for (let k in this.data) {
            if (this.data.hasOwnProperty(k)) {
              if (this.data[k] instanceof Entity && this.data[k].isASleepingReference) {
                promises.push(this.data[k].readyAll(undefined, undefined, newLevel));
              } else if (isArray(this.data[k])) {
                for (let i = 0; i < this.data[k].length; i++) {
                  if (this.data[k][i] instanceof Entity && this.data[k][i].isASleepingReference) {
                    promises.push(this.data[k][i].readyAll(undefined, undefined, newLevel));
                  }
                }
              }
            }
          }
          if (promises.length) {
            Promise.all(promises).then(() => {
              resolve(this);
              if (typeof success === 'function') {
                success(this);
              }
            }, (errObj) => {
              reject(errObj);
              if (typeof error === 'function') {
                error(errObj);
              }
            });
          } else {
            resolve(this);
            if (typeof success === 'function') {
              success(this);
            }
          }
        } else {
          resolve(this);
          if (typeof success === 'function') {
            success(this);
          }
        }
      };

      if (this.isASleepingReference) {
        this.ready(readyProps, (errObj) => {
          reject(errObj);
          if (typeof error === 'function') {
            error(errObj);
          }
        });
      } else {
        readyProps();
      }
    });
  }
}

// === Static Properties ===

// The name of the server class (Shouldn't start with a \)
Entity.class = 'Nymph\\Entity';

Nymph.setEntityClass(Entity.class, Entity);

// === Error Classes ===

export class EntityIsSleepingReferenceError extends Error {
  constructor (message) {
    super(message);
    this.name = 'EntityIsSleepingReferenceError';
  }
}

export default Entity;
<|endoftext|>


<commit_before>import ui.ImageView as ImageView;
import ui.resource.loader as loader;
var _imageMap = loader.getMap();

import .EntityPhysics;

var uid = 1;

exports = Class(function() {
	// default prototype properties, should usually be overridden by subclasses
	this.name = "Entity";
	this.viewClass = ImageView;

	this.init = function(opts) {
		// unique IDs are helpful for logging and debugging
		this.id = this.name + uid++;

		// primary position point
		this.x = 0;
		this.y = 0;

		// simple physics: velocity and acceleration
		this.vx = 0;
		this.vy = 0;
		this.ax = 0;
		this.ay = 0;

		// entities are either circles or rectangles
		this.isCircle = false;

		// collision bounds, offset from primary point
		this.hitBounds = createBounds();

		// view bounds, offset from primary point
		this.viewBounds = createBounds();

		// entities optionally support views
		if (this.viewClass) {
			this.view = new this.viewClass(opts);

			// updating view bounds updates the view's style, but not vice-versa
			var vs = this.view.style;
			Object.defineProperties(this.viewBounds, {
				w: {
					enumerable: true,
					get: function() { return vs.width; },
					set: function(val) { vs.width = val; }
				},
				h: {
					enumerable: true,
					get: function() { return vs.height; },
					set: function(val) { vs.height = val; }
				}
			});
		} else {
			this.view = null;
		}

		// physics component
		this.physics = opts.physics || EntityPhysics;

		// EntityPool properties
		this.pool = opts.pool || null;
		this.poolIndex = opts.poolIndex || 0;
	};

	this.reset = function(x, y, config) {
		this.x = x || 0;
		this.y = y || 0;

		config = config || {};
		this.vx = config.vx || 0;
		this.vy = config.vy || 0;
		this.ax = config.ax || 0;
		this.ay = config.ay || 0;
		this.isCircle = config.isCircle || false;

		applyBoundsFromConfig(config.hitBounds, this.hitBounds, config, 'hit');
		applyBoundsFromConfig(config.viewBounds, this.viewBounds, config, 'view');

		this.view && this.resetView(config);
	};

	this.resetView = function(config) {
		var v = this.view;
		var s = v.style;
		var b = this.viewBounds;
		s.x = this.x + b.x;
		s.y = this.y + b.y;
		s.visible = true;

		// setImage is expensive, so only call it if we have to
		var image = config.image;
		if (image && v.setImage && v.currImage !== image) {
			v.setImage(image);
			v.currImage = image;
		}
	};

	this.update = function(dt) {
		this.physics.stepPosition(this, dt);
		this.view && this.updateView(dt);
	};

	this.updateView = function(dt) {
		var s = this.view.style;
		var b = this.viewBounds;
		s.x = this.x + b.x;
		s.y = this.y + b.y;
	};

	this.collidesWith = function(entity) {
		return this.physics.collidesWith(this, entity);
	};

	this.release = function() {
		this.pool.release(this);
		this.view && (this.view.style.visible = false);
	};
});

/**
 * Entity Bounds are simple objects that support rectangles and circles
 *
 * Rects:
 * x and y are offsets to the top-left corner from the primary point
 * r can be used for rotation but is not used by default
 * w and h are width and height respectively
 *
 * Circles:
 * x and y are offsets to the center point from the primary point
 * r is the radius of the circle
 * w and h are not used
 */

var createBounds =
exports.createBounds = function() {
	return { x: 0, y: 0, r: 0, w: 0, h: 0 };
};

var applyBounds =
exports.applyBounds = function(src, dest) {
	dest.x = src.x || 0;
	dest.y = src.y || 0;
	dest.r = src.r || 0;
	dest.w = src.w || 0;
	dest.h = src.h || 0;
};

var applyBoundsFromImage =
exports.applyBoundsFromImage = function(src, dest, config, type) {
	var b = _imageMap[config.image];
	dest.w = b.w + b.marginLeft + b.marginRight;
	dest.h = b.h + b.marginTop + b.marginBottom;
	if (config.isCircle) {
		// default radius based on average of image width and height
		if (!src) {
			dest.r = (dest.w + dest.h) / 4;
			// circle's are assumed to be centered, so offset our view
			if (type === 'view') {
				dest.x = -dest.w / 2;
				dest.y = -dest.h / 2;
			}
		}
	}
};

var applyBoundsFromConfig =
exports.applyBoundsFromConfig = function(src, dest, config, type) {
	applyBounds(src || createBounds(), dest);
	if (config.image && !dest.r && (!dest.w || !dest.h)) {
		applyBoundsFromImage(src, dest, config, type);
	}
};
<commit_msg>track the previous position of the entity<commit_after>import ui.ImageView as ImageView;
import ui.resource.loader as loader;
var _imageMap = loader.getMap();

import .EntityPhysics;

var uid = 1;

exports = Class(function() {
	// default prototype properties, should usually be overridden by subclasses
	this.name = "Entity";
	this.viewClass = ImageView;

	this.init = function(opts) {
		// unique IDs are helpful for logging and debugging
		this.id = this.name + uid++;

		// primary position point
		this.x = 0;
		this.y = 0;

		// simple physics: velocity and acceleration
		this.vx = 0;
		this.vy = 0;
		this.ax = 0;
		this.ay = 0;

		// position from the previous frame
		this.xPrev = 0;
		this.yPrev = 0;

		// entities are either circles or rectangles
		this.isCircle = false;

		// collision bounds, offset from primary point
		this.hitBounds = createBounds();

		// view bounds, offset from primary point
		this.viewBounds = createBounds();

		// entities optionally support views
		if (this.viewClass) {
			this.view = new this.viewClass(opts);

			// updating view bounds updates the view's style, but not vice-versa
			var vs = this.view.style;
			Object.defineProperties(this.viewBounds, {
				w: {
					enumerable: true,
					get: function() { return vs.width; },
					set: function(val) { vs.width = val; }
				},
				h: {
					enumerable: true,
					get: function() { return vs.height; },
					set: function(val) { vs.height = val; }
				}
			});
		} else {
			this.view = null;
		}

		// physics component
		this.physics = opts.physics || EntityPhysics;

		// EntityPool properties
		this.pool = opts.pool || null;
		this.poolIndex = opts.poolIndex || 0;
	};

	this.reset = function(x, y, config) {
		this.x = x || 0;
		this.y = y || 0;
		this.xPrev = this.x;
		this.yPrev = this.y;

		config = config || {};
		this.vx = config.vx || 0;
		this.vy = config.vy || 0;
		this.ax = config.ax || 0;
		this.ay = config.ay || 0;
		this.isCircle = config.isCircle || false;

		applyBoundsFromConfig(config.hitBounds, this.hitBounds, config, 'hit');
		applyBoundsFromConfig(config.viewBounds, this.viewBounds, config, 'view');

		this.view && this.resetView(config);
	};

	this.resetView = function(config) {
		var v = this.view;
		var s = v.style;
		var b = this.viewBounds;
		s.x = this.x + b.x;
		s.y = this.y + b.y;
		s.visible = true;

		// setImage is expensive, so only call it if we have to
		var image = config.image;
		if (image && v.setImage && v.currImage !== image) {
			v.setImage(image);
			v.currImage = image;
		}
	};

	this.update = function(dt) {
		this.xPrev = this.x;
		this.yPrev = this.y;
		this.physics.stepPosition(this, dt);
		this.view && this.updateView(dt);
	};

	this.updateView = function(dt) {
		var s = this.view.style;
		var b = this.viewBounds;
		s.x = this.x + b.x;
		s.y = this.y + b.y;
	};

	this.collidesWith = function(entity) {
		return this.physics.collidesWith(this, entity);
	};

	this.release = function() {
		this.pool.release(this);
		this.view && (this.view.style.visible = false);
	};
});

/**
 * Entity Bounds are simple objects that support rectangles and circles
 *
 * Rects:
 * x and y are offsets to the top-left corner from the primary point
 * r can be used for rotation but is not used by default
 * w and h are width and height respectively
 *
 * Circles:
 * x and y are offsets to the center point from the primary point
 * r is the radius of the circle
 * w and h are not used
 */

var createBounds =
exports.createBounds = function() {
	return { x: 0, y: 0, r: 0, w: 0, h: 0 };
};

var applyBounds =
exports.applyBounds = function(src, dest) {
	dest.x = src.x || 0;
	dest.y = src.y || 0;
	dest.r = src.r || 0;
	dest.w = src.w || 0;
	dest.h = src.h || 0;
};

var applyBoundsFromImage =
exports.applyBoundsFromImage = function(src, dest, config, type) {
	var b = _imageMap[config.image];
	dest.w = b.w + b.marginLeft + b.marginRight;
	dest.h = b.h + b.marginTop + b.marginBottom;
	if (config.isCircle) {
		// default radius based on average of image width and height
		if (!src) {
			dest.r = (dest.w + dest.h) / 4;
			// circle's are assumed to be centered, so offset our view
			if (type === 'view') {
				dest.x = -dest.w / 2;
				dest.y = -dest.h / 2;
			}
		}
	}
};

var applyBoundsFromConfig =
exports.applyBoundsFromConfig = function(src, dest, config, type) {
	applyBounds(src || createBounds(), dest);
	if (config.image && !dest.r && (!dest.w || !dest.h)) {
		applyBoundsFromImage(src, dest, config, type);
	}
};
<|endoftext|>


<commit_before>'use strict';

var famous = require('famous');
var Consts = require('./Consts.js');
var Cell = require('./Cell.js');

var Node = famous.core.Node;
var Position = famous.components.Position;
var DOMElement = famous.domRenderables.DOMElement;

function Figure(id, randomId) {
	Node.call(this);

	// Center dot.
	this
		.setMountPoint(0, 0)
		.setAlign(0.5, 0.5)
		.setSizeMode('absolute', 'absolute')
		.setAbsoluteSize(Consts.DOT_SIDE * Consts.DIMENSION / 2, Consts.DOT_SIDE * Consts.DIMENSION / 2);

	this.domElement = new DOMElement(this, {
		tagName: 'h1',
		classes: ['Figure']
	});

	this.domElement.setAttribute('role', 'grid');
	this.domElement.setAttribute('aria-live', 'polite');

	this.id = id;
	this.randomId = randomId;

	this.cells = [];
	for (let cellCounter = 0; cellCounter < 4; cellCounter++) {
		let cell = new Cell(cellCounter, Consts.FIGURES[randomId][cellCounter].x, Consts.FIGURES[randomId][cellCounter].y);
		this.addChild(cell);
		this.cells.push(cell);
	}

	this.position = new Position(this);

	this.addUIEvent('click');
}

Figure.prototype = Object.create(Node.prototype);
Figure.prototype.constructor = Figure;

/*jshint -W074 */
Figure.prototype.onReceive = function onReceive(type, ev) {
	switch (type) {
	case 'click':
			this._parent.figureUpdate(this.id);
			this._parent.scoreSurcharge();
			this.emit('id', this.id).emit('randomId', this.randomId);
			break;
	default:
			return false;
	}
};/*jshint +W074 */

module.exports = Figure;
<commit_msg>Disallow generating new Figure by clicking on them<commit_after>'use strict';

var famous = require('famous');
var Consts = require('./Consts.js');
var Cell = require('./Cell.js');

var Node = famous.core.Node;
var Position = famous.components.Position;
var DOMElement = famous.domRenderables.DOMElement;

function Figure(id, randomId) {
	Node.call(this);

	// Center dot.
	this
		.setMountPoint(0, 0)
		.setAlign(0.5, 0.5)
		.setSizeMode('absolute', 'absolute')
		.setAbsoluteSize(Consts.DOT_SIDE * Consts.DIMENSION / 2, Consts.DOT_SIDE * Consts.DIMENSION / 2);

	this.domElement = new DOMElement(this, {
		tagName: 'h1',
		classes: ['Figure']
	});

	this.domElement.setAttribute('role', 'grid');
	this.domElement.setAttribute('aria-live', 'polite');

	this.id = id;
	this.randomId = randomId;

	this.cells = [];
	for (let cellCounter = 0; cellCounter < 4; cellCounter++) {
		let cell = new Cell(cellCounter, Consts.FIGURES[randomId][cellCounter].x, Consts.FIGURES[randomId][cellCounter].y);
		this.addChild(cell);
		this.cells.push(cell);
	}

	this.position = new Position(this);
}

Figure.prototype = Object.create(Node.prototype);
Figure.prototype.constructor = Figure;

module.exports = Figure;
<|endoftext|>


<commit_before>(function(d,i,u){function o(a,c){a.className+=" "+c}function z(a,c){a.className=a.className.replace(RegExp("\\b"+c+"\\b"),"")}function p(){return(new Date).getTime()}function Q(a,c){j||(j=f.body);R.push(p()-Aa+"ms: "+a);if(S&&(m||(m=c)||j&&(m=f.createElement("div"))&&j.insertBefore(m,j.firstChild)))m.innerHTML=["

",R.join("

"),"

"].join("")}function T(){for(var a=arguments,c=a[0],b,e,d=1,f=a.length;d<f;d++)for(b in e=a[d],e)e.hasOwnProperty(b)&&(U(e[b])?(c[b]=V(e[b])?[]:{},
T(c[b],e[b])):c[b]=e[b]);return c}function A(a,c,b){a.attachEvent?a.attachEvent("on"+c,b):a.addEventListener&&a.addEventListener(c,b,!1)}function W(a){function c(){v();B(a)}n(f.readyState,"m")?c():A(i,X,c)}function q(a,c){for(var b=0,e=a.length;b<e;b++)c.call(a,b,a[b])}function V(a){return a&&n(a.constructor.toString(),"rray")}function U(a){return typeof a===C}function D(a){return typeof a===Y}function Z(a){return a.replace(/^\s\s*/,"").replace(/\s\s*$/,"")}function n(a,c){return a&&a.indexOf(c)!==
-1}function $(a,c){var b;j||(j=f.body);c&&(c*=1E3);j&&w(function(){b=f.createElement(aa?C:"img");b.src=b.data=a;b.alt="";b.width=b.height=0;b.style.position="absolute";j.appendChild(b)},c||0)}function E(a,c,b){var e=f.createElement(F),d=0,b=b||c||{},c=D(c)?c:Ba;e.src=a;e.type=b.type||"";e.async=b.async||!1;e[ba]=e[ca]=function(){if(!d&&(!e[G]||e[G]==="loaded"||e[G]===Ca))d=1,c(a),e[ba]=e[ca]=null};w(function(){da.insertBefore(e,H)},0)}function I(){x.shift();J()}function J(a){var c=x[0]||{},b=c.src||
c;ea[a]=1;ea[b]&&!fa[b]?(K=b,fa[b]=1,L?I():E(b,I)):D(b)&&(L?b(K):w(function(){b(K)},0),I())}function ga(a){for(;a[0];)ha(a[0]),a.shift()}function ha(){q(arguments,function(a,c){var b={},e,d;switch(typeof c){case ia:b.src=c;break;case Y:b.callback=c;break;case C:b=c,e=b.defer,d=b.callback,b.defer=u}e==="ready"?(ja.push(b),ka(function(){ga(ja)})):e===X?(la.push(b),W(function(){ga(la)})):(e=b.src,d=b.callback,b.callback=u,n(b.type,"cache")?e&&!ma[e]&&$(e,b.delay):e&&!ma[e]&&(x.push(b),E(e,J,{type:Da})),
d&&x.push(d));J()})}function r(a,c){var b=M[a];b&&q(b,function(a){b[a].call(c,c)})}function na(a){var c=oa.cloneNode(0),b=c.styleSheet;b?b.cssText=a:(a=f.createTextNode(a),c.appendChild(a));da.insertBefore(c,H)}function pa(a){var c=f.createElement("div");c.innerHTML=a;return c.firstChild}function N(a,c,b,e){var d=Ea++,f=p(),g,h=!1;qa[d]=setInterval(function(){g=p()-f;if(a()||e&&(h=g>e))c.call(i,h,g),clearInterval(qa[d])},b)}function Fa(a,c){var b=ra.call(arguments,2);return setTimeout(function(){return a.apply(a,
b)},c)}function B(a){return Fa.apply({},[a,1].concat(ra.call(arguments,1)))}function sa(a,c,b){var e;return function(){function d(){e=u;a.call(this)}b&&clearTimeout(e);if(b||!e)e=w(d,c)}}function ta(a,c){return sa(a,c,!1)}function ua(){var a=h.clientWidth,c=[],b,e;if(a!==va){for(e=0;e<Ga;e++)b=wa[e],c.push((a<=b?"lt-":"gt-")+b);va=a;c=c.join(" ");c!=y&&(z(h,y),o(h,c),y=c,r("boot.screen-update",{screens:y,width:a}))}}var d=i[d]||(i[d]={}),f=i.document,O=i.JSON,w=setTimeout,ra=Array.prototype.slice,
X="load",ia="string",Y="function",C="object",F="script",G="readyState",ca="onreadystatechange",ba="onload",Ca="complete";d.now=p;var m,j,R=[],Aa=p(),S=0;Q.init=function(a){S=1;m=a.elem};d.log=Q;d.extend=T;var xa=0,ya=0,s=[],za=function(){return n(f.readyState,"e")},v=function(){xa=1;q(s,function(a){B(s[a])});s=[]},ka=function(a){xa?B(a):ya?s.push(a):(ya=1,s=[a],za()?v():f.addEventListener?f.addEventListener("DOMContentLoaded",v,!1):N(za,v,50))};d.ready=ka;d.bind=A;d.load=W;var oa=f.createElement("style");
d.attr=function(a,c,b){if(b!==u)b===null?a.removeAttribute(c):c==="style"&&oa.styleSheet?a.cssText=b:a.setAttribute(c,b);else return a.getAttribute(c)};d.each=q;d.globalEval=function(a){(i.execScript||function(a){i.eval.call(i,a)})(a)};d.isArray=V;d.isObject=U;d.isString=function(a){return typeof a===ia};d.isBoolean=function(a){return typeof a==="boolean"};d.isFunction=D;d.isNumber=function(a){return typeof a==="number"};d.trim=Z;d.parseJSON=function(a){try{a=Z(a);if(O&&O.parse)return O.parse(a);
return(new Function("return "+a))()}catch(c){i.console&&console.log("Bad JSON: "+a)}};d.contains=n;d.cacheScript=$;var Ba=function(){},H=f.getElementsByTagName(F)[0],da=H.parentNode;d.getScript=E;var ma={},ea={},fa={},x=[],ja=[],la=[],K,h=f.documentElement,aa="MozAppearance"in h.style,L=aa||i.opera||f.createElement(F).async===!0,Da=L?"":"c";d.getJS=ha;var M={};d.on=function(a,c){(M[a]||(M[a]=[])).push(c)};d.emit=r;d.inlineCSS=na;d.create=pa;var qa={},Ea=0;d.poll=N;var P={namespace:"wf-",path:"fonts/{f}/{f}-webfont",
fontface:"@font-face { font-family: '{f}'; src: url('{p}.eot'); src: url('{p}.eot?#iefix') format('embedded-opentype'), url('{p}.woff') format('woff'), url('{p}.ttf') format('truetype'), url('{p}.svg#{f}') format('svg'); font-weight: normal; font-style: normal; }"},t;d.getFont=function(){t||(t=pa('
BESs
'),h.appendChild(t));for(var a=
arguments,c=/{f}/g,b=/{p}/g,e,d,f=[],g=0,i=a.length;g<i;g++)d=a[g].toLowerCase(),e=P.path.replace(c,d),e=P.fontface.replace(c,d).replace(b,e),f.push(e),e=t.cloneNode(!0),e.style.fontFamily="'"+d+"',serif",h.appendChild(e),d=P.namespace+d,r(d+"-loading"),o(h,d+"-loading"),function(a,b){N(function(){return t.offsetWidth!==a.offsetWidth},function(a){a?(z(h,b+"-loading"),o(h,b+"-inactive"),r(b+"-inactive")):(z(h,b+"-loading"),o(h,b+"-active"),r(b+"-active"))},25,1E4)}(e,d);na(f.join(""))};d.debounce=
function(a,c){return sa(a,c,!0)};d.throttle=ta;var wa=[320,640,800,1024,1152,1280,1366,1440,1600,1680,1920],Ga=wa.length,va,y;ua();A(i,"resize",ta(ua,100));var g=navigator.userAgent.toLowerCase(),k,l;k=[];g=/(firefox)[ \/]([\w.]+)/.exec(g)||/(chrome)[ \/]([\w.]+)/.exec(g)||n(g,"safari")&&/(version)[ \/]([\w.]+)/.exec(g)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(g)||/(msie) ([\w.]+)/.exec(g)||/(webkit)[ \/]([\w.]+)/.exec(g)||[];l=g[1];g=g[2];l==="msie"&&(l="ie",g=f.documentMode||g);l==="version"&&
(l="safari");k.push(l);k.push(l+parseInt(g));k.push(l+g.toString().replace(".","-").replace(/\..*/,""));o(h,k.join(" "));k={version:g};k[l]=!0;d.browser=k;k.ie&&q("abbr article aside audio canvas details figcaption figure footer header hgroup mark meter nav output progress section summary time video".split(" "),function(a,c){f.createElement(c)})})("Boot",this);<commit_msg>Forgot the minified version. Wupsies.<commit_after>(function(d,i,v){function o(a,c){a.className+=" "+c}function z(a,c){a.className=a.className.replace(RegExp("\\b"+c+"\\b"),"")}function p(){return(new Date).getTime()}function R(a,c){j||(j=f.body);S.push(p()-Ba+"ms: "+a);if(T&&(m||(m=c)||j&&(m=f.createElement("div"))&&j.insertBefore(m,j.firstChild)))m.innerHTML=["

",S.join("

"),"

"].join("")}function U(){for(var a=arguments,c=a[0],b,e,d=1,f=a.length;d<f;d++)for(b in e=a[d],e)e.hasOwnProperty(b)&&(V(e[b])?(c[b]=W(e[b])?[]:{},
U(c[b],e[b])):c[b]=e[b]);return c}function A(a,c,b){a.attachEvent?a.attachEvent("on"+c,b):a.addEventListener&&a.addEventListener(c,b,!1)}function X(a){function c(){w();q(a)}n(f.readyState,"m")?c():A(i,Y,c)}function r(a,c){for(var b=0,e=a.length;b<e;b++)c.call(a,b,a[b])}function W(a){return a&&n(a.constructor.toString(),"rray")}function V(a){return typeof a===B}function C(a){return typeof a===Z}function $(a){return a.replace(/^\s\s*/,"").replace(/\s\s*$/,"")}function n(a,c){return a&&a.indexOf(c)!==
-1}function aa(a,c){var b;j||(j=f.body);c&&(c*=1E3);j&&D(function(){b=f.createElement(ba?B:"img");b.src=b.data=a;b.alt="";b.width=b.height=0;b.style.position="absolute";j.appendChild(b)},c||0)}function E(a,c,b){var e=f.createElement(F),d=0,b=b||c||{},c=C(c)?c:Ca;e.src=a;e.type=b.type||"";e.async=b.async||!1;e[ca]=e[da]=function(){if(!d&&(!e[G]||e[G]==="loaded"||e[G]===Da))d=1,c(a),e[ca]=e[da]=null};q(function(){ea.insertBefore(e,H)})}function I(){x.shift();J()}function J(a){var c=x[0]||{},b=c.src||
c;fa[a]=1;fa[b]&&!ga[b]?(K=b,L=!!c.test,ga[b]=1,M?I():E(b,I)):C(b)&&(M?b(K,L):q(function(){b(K,L)}),I())}function ha(a){for(;a[0];)ia(a[0]),a.shift()}function ia(){r(arguments,function(a,c){var b={},e,d;switch(typeof c){case ja:b.src=c;break;case Z:b.callback=c;break;case B:b=c,e=b.defer,d=b.callback,b.defer=v}if(e==="ready")ka.push(b),la(function(){ha(ka)});else if(e===Y)ma.push(b),X(function(){ha(ma)});else{e=b.src;if(!e&&b.nay)e=b.test?b.yay:b.nay,b.src=e;d=b.callback;b.callback=v;n(b.type,"cache")?
e&&!na[e]&&aa(e,b.delay):e&&!na[e]&&(x.push(b),E(e,J,{type:Ea}));d&&x.push(d)}J()})}function s(a,c){var b=N[a];b&&r(b,function(a){b[a].call(c,c)})}function oa(a){var c=pa.cloneNode(0),b=c.styleSheet;b?b.cssText=a:(a=f.createTextNode(a),c.appendChild(a));ea.insertBefore(c,H)}function qa(a){var c=f.createElement("div");c.innerHTML=a;return c.firstChild}function O(a,c,b,e){var d=Fa++,f=p(),g,h=!1;ra[d]=setInterval(function(){g=p()-f;if(a()||e&&(h=g>e))c.call(i,h,g),clearInterval(ra[d])},b)}function Ga(a,
c){var b=sa.call(arguments,2);return D(function(){return a.apply(a,b)},c)}function q(a){return Ga.apply({},[a,1].concat(sa.call(arguments,1)))}function ta(a,c,b){var e;return function(){function d(){e=v;a.call(this)}b&&clearTimeout(e);if(b||!e)e=D(d,c)}}function ua(a,c){return ta(a,c,!1)}function va(){var a=h.clientWidth,c=[],b,e;if(a!==wa){for(e=0;e<Ha;e++)b=xa[e],c.push((a<=b?"lt-":"gt-")+b);wa=a;c=c.join(" ");c!=y&&(z(h,y),o(h,c),y=c,s("boot.screen-update",{screens:y,width:a}))}}var d=i[d]||(i[d]=
{}),f=i.document,P=i.JSON,D=setTimeout,sa=Array.prototype.slice,Y="load",ja="string",Z="function",B="object",F="script",G="readyState",da="onreadystatechange",ca="onload",Da="complete";d.now=p;var m,j,S=[],Ba=p(),T=0;R.init=function(a){T=1;m=a.elem};d.log=R;d.extend=U;var ya=0,za=0,t=[],Aa=function(){return n(f.readyState,"e")},w=function(){ya=1;r(t,function(a){q(t[a])});t=[]},la=function(a){ya?q(a):za?t.push(a):(za=1,t=[a],Aa()?w():f.addEventListener?f.addEventListener("DOMContentLoaded",w,!1):O(Aa,
w,50))};d.ready=la;d.bind=A;d.load=X;var pa=f.createElement("style");d.attr=function(a,c,b){if(b!==v)b===null?a.removeAttribute(c):c==="style"&&pa.styleSheet?a.cssText=b:a.setAttribute(c,b);else return a.getAttribute(c)};d.each=r;d.globalEval=function(a){(i.execScript||function(a){i.eval.call(i,a)})(a)};d.isArray=W;d.isObject=V;d.isString=function(a){return typeof a===ja};d.isBoolean=function(a){return typeof a==="boolean"};d.isFunction=C;d.isNumber=function(a){return typeof a==="number"};d.trim=
$;d.parseJSON=function(a){try{a=$(a);if(P&&P.parse)return P.parse(a);return(new Function("return "+a))()}catch(c){i.console&&console.log("Bad JSON: "+a)}};d.contains=n;d.cacheScript=aa;var Ca=function(){},H=f.getElementsByTagName(F)[0],ea=H.parentNode;d.getScript=E;var na={},fa={},ga={},x=[],ka=[],ma=[],K,L,h=f.documentElement,ba="MozAppearance"in h.style,M=ba||i.opera||f.createElement(F).async,Ea=M?"":"c";d.getJS=ia;var N={};d.on=function(a,c){(N[a]||(N[a]=[])).push(c)};d.emit=s;d.inlineCSS=oa;d.create=
qa;var ra={},Fa=0;d.poll=O;var Q={namespace:"wf-",path:"fonts/{f}/{f}-webfont",fontface:"@font-face { font-family: '{f}'; src: url('{p}.eot'); src: url('{p}.eot?#iefix') format('embedded-opentype'), url('{p}.woff') format('woff'), url('{p}.ttf') format('truetype'), url('{p}.svg#{f}') format('svg'); font-weight: normal; font-style: normal; }"},u;d.getFont=function(){u||(u=qa('
BESs
'),
h.appendChild(u));for(var a=arguments,c=/{f}/g,b=/{p}/g,e,d,f=[],g=0,i=a.length;g<i;g++)d=a[g].toLowerCase(),e=Q.path.replace(c,d),e=Q.fontface.replace(c,d).replace(b,e),f.push(e),e=u.cloneNode(!0),e.style.fontFamily="'"+d+"',serif",h.appendChild(e),d=Q.namespace+d,s(d+"-loading"),o(h,d+"-loading"),function(a,b){O(function(){return u.offsetWidth!==a.offsetWidth},function(a){a?(z(h,b+"-loading"),o(h,b+"-inactive"),s(b+"-inactive")):(z(h,b+"-loading"),o(h,b+"-active"),s(b+"-active"))},25,1E4)}(e,d);
oa(f.join(""))};d.throttle=ua;d.debounce=function(a,c){return ta(a,c,!0)};var xa=[320,640,800,1024,1152,1280,1366,1440,1600,1680,1920],Ha=xa.length,wa,y;va();A(i,"resize",ua(va,100));var g=navigator.userAgent.toLowerCase(),k,l;k=[];g=/(firefox)[ \/]([\w.]+)/.exec(g)||/(chrome)[ \/]([\w.]+)/.exec(g)||n(g,"safari")&&/(version)[ \/]([\w.]+)/.exec(g)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(g)||/(msie) ([\w.]+)/.exec(g)||/(webkit)[ \/]([\w.]+)/.exec(g)||[];l=g[1];g=g[2];l==="msie"&&(l="ie",g=f.documentMode||
g);l==="version"&&(l="safari");k.push(l);k.push(l+parseInt(g));k.push(l+g.toString().replace(".","-").replace(/\..*/,""));o(h,k.join(" "));k={version:g};k[l]=!0;d.browser=k;k.ie&&r("abbr article aside audio canvas details figcaption figure footer header hgroup mark meter nav output progress section summary time video".split(" "),function(a,c){f.createElement(c)})})("Boot",this);<|endoftext|>


<commit_before>/*
 * Copyright (c) 1997-2013, SalesLogix, NA., LLC. All rights reserved.
 */

/**
 * @class Mobile.SalesLogix.Format
 *
 * @extends Sage.Platform.Mobile.Format
 * @requires Mobile.SalesLogix.Template
 *
 */
define('Mobile/SalesLogix/Format', [
    'dojo/_base/lang',
    'dojo/_base/array',
    'dojo/string',
    'dojo/number',
    'Mobile/SalesLogix/Template',
    'Sage/Platform/Mobile/Format',
    'moment'
], function(
    lang,
    array,
    string,
    dojoNumber,
    template,
    format,
    moment
) {
    return lang.setObject('Mobile.SalesLogix.Format', lang.mixin({}, format, {
        /**
         * Address Culture Formats as defined by Mobile.SalesLogix.Format.address
         * http://msdn.microsoft.com/en-us/library/cc195167.aspx
         */
        addressCultureFormats: {
            'en': 'a1|a2|a3|m, R p|C',
            'en-GB': 'a1|a2|a3|M|P|C',
            'fr': 'a1|a2|a3|p M|C',
            'de': 'a1|a2|a3|p m|C',
            'it': 'a1|a2|a3|p m Z|C',
            'ru': 'a1|a2|a3|p m|C'
        },
        /**
         * Country name to culture identification
         * http://msdn.microsoft.com/en-us/goglobal/bb896001.aspx
         */
        countryCultures: {
            'USA': 'en',
            'United States': 'en',
            'United States of America': 'en',
            'US': 'en',
            'United Kingdom': 'en-GB',
            'UK': 'en-GB',
            'Britain': 'en-GB',
            'England': 'en-GB',
            'Russia': 'ru',
            'Россия': 'ru',
            'Italy': 'it',
            'Italia': 'it',
            'France': 'fr',
            'Germany': 'de',
            'Deutschland': 'de'
        },
        /**
        Converts the given value using the provided format, joining with the separator character
        If no format given, will use predefined format for the addresses Country (or en-US as final fallback)

        Format    Description                                    Example
        ------    -----------------------------------------    -----------------------
         s         Salutation (Attention, Name)                ATTN: Mr. Bob
         S         Salutation Uppercase                        ATTN: MR. BOB
         a1        Address Line 1                              555 Oak Ave
         a2        Address Line 2                                #2038
         a3        Address Line 3
         m        Municipality (City, town, hamlet)            Phoenix
         M        Municipality Uppercase                        PHOENIX
         z        County (parish, providence)                    Maricopa
         Z         County Uppercase                            MARICOPA
         r        Region (State, area)                        AZ
         R        Region Uppercase                            AZ
         p         Postal Code (ZIP code)                        85021
         P         Postal Code Uppercase                        85021
         c         Country                                     France
         C         Country Uppercase                            FRANCE

         |        separator                                    as defined by separator variable

         @param {object} o Address Entity containing all the SData properties
         @param {boolean} asText If set to true returns text only, if false returns anchor link to google maps
         @param {string|boolean} separator If false - separates with html
,
                              if true - separates with line return,
                              if defined as string - uses string to separate
         @param {string} fmt Address format to use, may also pass a culture string to use predefined format
         @return {string} Formatted address
        */
        address: function(o, asText, separator, fmt) {
            var isEmpty = function(line) {
                var filterSymbols = lang.trim(line.replace(/,|\(|\)|\.|>|-|<|;|:|'|"|\/|\?|\[|\]|{|}|_|=|\+|\\|\||!|@|#|\$|%|\^|&|\*|`|~/g, ''));//'
                return filterSymbols === '';
            },
                _this = Mobile.SalesLogix.Format;

            if (!fmt) {
                var culture = _this.resolveAddressCulture(o);
                fmt = _this.addressCultureFormats[culture] || _this.addressCultureFormats['en'];
            }

            var lines = (fmt.indexOf('|') === -1) ? [fmt] : fmt.split('|'),
                address = [];

            array.forEach(lines, function(line) {
                line = _this.replaceAddressPart(line, o);
                if (!isEmpty(line)) {
                    this.push(_this.encode(_this.collapseSpace(line)));
                }
            }, address);

            if (asText) {
                if (separator === true) {
                    separator = '\n';
                }
                return address.join(separator || '
');
            }

            return string.substitute(
                '${0}',
                [address.join('
'), encodeURIComponent(_this.decode(address.join(' ')))]
            );
        },
        collapseSpace: function(text) {
            return lang.trim(text.replace(/\s+/g, ' '));
        },
        resolveAddressCulture: function(o) {
            return Mobile.SalesLogix.Format.countryCultures[o.Country] || Mobile.CultureInfo.name;
        },
        replaceAddressPart: function(fmt, o) {
            return fmt.replace(/s|S|a1|a2|a3|a4|m|M|z|Z|r|R|p|P|c|C/g,
                function(part) {
                    switch (part) {
                        case "s":
                            return o.Salutation || '';
                        case "S":
                            return (o.Salutation && o.Salutation.toUpperCase()) || '';
                        case "a1":
                            return o.Address1 || '';
                        case "a2":
                            return o.Address2 || '';
                        case "a3":
                            return o.Address3 || '';
                        case "a4":
                            return o.Address4 || '';
                        case "m":
                            return o.City || '';
                        case "M":
                            return (o.City && o.City.toUpperCase()) || '';
                        case "z":
                            return o.County || '';
                        case "Z":
                            return (o.County && o.County.toUpperCase()) || '';
                        case "r":
                            return o.State || '';
                        case "R":
                            return (o.State && o.State.toUpperCase()) || '';
                        case "p":
                            return o.PostalCode || '';
                        case "P":
                            return (o.PostalCode && o.PostalCode.toUpperCase()) || '';
                        case "c":
                            return o.Country || '';
                        case "C":
                            return (o.Country && o.Country.toUpperCase()) || '';
                    }
                }
            );
        },
        // These were added to the SDK, and should not be here. Keeping the alias to not break anyone with a minor update.
        phoneFormat: format.phoneFormat,
        phone: format.phone,
        currency: function(val) {
            if (isNaN(val) || val === null) {
                return val;
            }

            var v = val.toFixed(2), // only 2 decimal places
                f = Math.floor((100 * (v - Math.floor(v))).toPrecision(2)); // for fractional part, only need 2 significant digits

            return string.substitute(
                '${0}'
                    + Mobile.CultureInfo.numberFormat.currencyDecimalSeparator
                    + '${1}', [
                        (Math.floor(v)).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + Mobile.CultureInfo.numberFormat.currencyGroupSeparator.replace("\\.", '.')),
                        (f.toString().length < 2) ? '0' + f.toString() : f.toString()
                    ]
            ).replace(/ /g, '\u00A0'); //keep numbers from breaking
        },
        bigNumberAbbrText: {
            'billion': 'B',
            'million': 'M',
            'thousand': 'K'
        },
        bigNumber: function(val) {
            var numParse = isNaN(val) ? parseFloat(val) : val,
                text = Mobile.SalesLogix.Format.bigNumberAbbrText;

            if (numParse && numParse >= 1000000000) {
                numParse = numParse / 1000000000;
                return dojoNumber.format(numParse, { places: 1 }) + text['billion'];
            } else if (numParse && numParse >= 1000000) {
                numParse = numParse / 1000000;
                return dojoNumber.format(numParse, { places: 1 }) + text['million'];
            } else if (numParse && numParse >= 1000) {
                numParse = numParse / 1000;
                return dojoNumber.format(numParse, { places: 1 }) + text['thousand'];
            }

            return val;
        },
        relativeDate: function(date, timeless) {
            var now;
            date = moment(date);
            if (!date || !date.isValid()) {
                throw new Error('Invalid date passed into Mobile.SalesLogix.Format.relativeDate');
            }

            if (timeless) {
                // utc
                date = date.add({minutes: date.zone()});
            }

            return date.fromNow();
        },
        multiCurrency: function(val, code) {
            return string.substitute('${0} ${1}', [Mobile.SalesLogix.Format.currency(val), code]);
        },
        nameLF: function(val) {
            if (!val) {
                return '';
            }

            var name = template.nameLF.apply(val);

            return name;
        },
        mail: function(val) {
            if (typeof val !== 'string') {
                return val;
            }

            return string.substitute('${0}', [val]);
        },
        userActivityFormatText: {
            'asUnconfirmed': 'Unconfirmed',
            'asAccepted': 'Accepted',
            'asDeclned': 'Declined'
        },
        userActivityStatus: function(val) {
            return Mobile.SalesLogix.Format.userActivityFormatText[val];
        },
        /**
         * Takes a string input and converts name to First amd Last initials
         * `Lee Hogan` -> `LH`
         * @param val
         * @returns {String}
         */
        formatUserInitial: function(user) {
            var firstLast = this.resolveFirstLast(user),
                initials = [firstLast[0].substr(0, 1)];

            if (firstLast[1]) {
                initials.push(firstLast[1].substr(0, 1));
            }

            return initials.join('').toUpperCase();
        },
        /**
        * Takes a string input and the user name to First amd Last name
        * `Hogan, Lee` -> `Lee Hogan`
        * @param val
        * @returns {String}
        */
        formatByUser: function(user) {
            var name = this.resolveFirstLast(user);
            return name.join(' ');
        },
        /**
       * Takes a string input and the user name to First amd Last name
       * `Hogan, Lee` -> `Lee Hogan`
       * @param val
       * @returns {String}
       */
        resolveFirstLast: function(name) {
            var firstLast = [];
            if (name.indexOf(' ') !== -1) {
                var names = name.split(' ');
                if (names[0].indexOf(',') !== -1) {
                    firstLast = [names[1], names[0].slice(0, -1)];
                }
                else {
                    firstLast = [names[0], names[1]];
                }
            }
            else {
                firstLast = [name];
            }
            return firstLast;
        },
        fixedLocale: function(val, d) {
            var num, frac, p, v, f, fVal;
            if (isNaN(val) || val === null) {
                return val;
            }

            if (typeof d !== 'number') {
                d = 2;
            }
            if (d > 0 ) {
                p = Math.pow(10, d);
                v = val.toFixed(d), // only d decimal places
                f = Math.floor((p * (v - Math.floor(v))).toPrecision(d)); // for fractional part, only need d significant digits
                if (f === 0) {
                    f = (p + "").slice(1);
                }
            } else {  //zero decimal palces
               p = Math.pow(10, 0);
               v = (Math.round(val * p) / p);
               f = 0;
            }
            num = Math.floor(v).toString();
            num = num.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + Mobile.CultureInfo.numberFormat.numberGroupSeparator.replace("\\.", '.'));
            if (d > 0) {
                frac = (f.toString().length < d) ? '' : f.toString();
                fVal = string.substitute(
                    '${0}'
                        + Mobile.CultureInfo.numberFormat.numberDecimalSeparator
                        + '${1}', [num, frac]);
            } else {
                fVal = num;
            }
            return fVal.replace(/ /g, '\u00A0'); //keep numbers from breaking
        }
    }));
});

<commit_msg>Fixed comma<commit_after>/*
 * Copyright (c) 1997-2013, SalesLogix, NA., LLC. All rights reserved.
 */

/**
 * @class Mobile.SalesLogix.Format
 *
 * @extends Sage.Platform.Mobile.Format
 * @requires Mobile.SalesLogix.Template
 *
 */
define('Mobile/SalesLogix/Format', [
    'dojo/_base/lang',
    'dojo/_base/array',
    'dojo/string',
    'dojo/number',
    'Mobile/SalesLogix/Template',
    'Sage/Platform/Mobile/Format',
    'moment'
], function(
    lang,
    array,
    string,
    dojoNumber,
    template,
    format,
    moment
) {
    return lang.setObject('Mobile.SalesLogix.Format', lang.mixin({}, format, {
        /**
         * Address Culture Formats as defined by Mobile.SalesLogix.Format.address
         * http://msdn.microsoft.com/en-us/library/cc195167.aspx
         */
        addressCultureFormats: {
            'en': 'a1|a2|a3|m, R p|C',
            'en-GB': 'a1|a2|a3|M|P|C',
            'fr': 'a1|a2|a3|p M|C',
            'de': 'a1|a2|a3|p m|C',
            'it': 'a1|a2|a3|p m Z|C',
            'ru': 'a1|a2|a3|p m|C'
        },
        /**
         * Country name to culture identification
         * http://msdn.microsoft.com/en-us/goglobal/bb896001.aspx
         */
        countryCultures: {
            'USA': 'en',
            'United States': 'en',
            'United States of America': 'en',
            'US': 'en',
            'United Kingdom': 'en-GB',
            'UK': 'en-GB',
            'Britain': 'en-GB',
            'England': 'en-GB',
            'Russia': 'ru',
            'Россия': 'ru',
            'Italy': 'it',
            'Italia': 'it',
            'France': 'fr',
            'Germany': 'de',
            'Deutschland': 'de'
        },
        /**
        Converts the given value using the provided format, joining with the separator character
        If no format given, will use predefined format for the addresses Country (or en-US as final fallback)

        Format    Description                                    Example
        ------    -----------------------------------------    -----------------------
         s         Salutation (Attention, Name)                ATTN: Mr. Bob
         S         Salutation Uppercase                        ATTN: MR. BOB
         a1        Address Line 1                              555 Oak Ave
         a2        Address Line 2                                #2038
         a3        Address Line 3
         m        Municipality (City, town, hamlet)            Phoenix
         M        Municipality Uppercase                        PHOENIX
         z        County (parish, providence)                    Maricopa
         Z         County Uppercase                            MARICOPA
         r        Region (State, area)                        AZ
         R        Region Uppercase                            AZ
         p         Postal Code (ZIP code)                        85021
         P         Postal Code Uppercase                        85021
         c         Country                                     France
         C         Country Uppercase                            FRANCE

         |        separator                                    as defined by separator variable

         @param {object} o Address Entity containing all the SData properties
         @param {boolean} asText If set to true returns text only, if false returns anchor link to google maps
         @param {string|boolean} separator If false - separates with html
,
                              if true - separates with line return,
                              if defined as string - uses string to separate
         @param {string} fmt Address format to use, may also pass a culture string to use predefined format
         @return {string} Formatted address
        */
        address: function(o, asText, separator, fmt) {
            var isEmpty = function(line) {
                var filterSymbols = lang.trim(line.replace(/,|\(|\)|\.|>|-|<|;|:|'|"|\/|\?|\[|\]|{|}|_|=|\+|\\|\||!|@|#|\$|%|\^|&|\*|`|~/g, ''));//'
                return filterSymbols === '';
            },
                _this = Mobile.SalesLogix.Format;

            if (!fmt) {
                var culture = _this.resolveAddressCulture(o);
                fmt = _this.addressCultureFormats[culture] || _this.addressCultureFormats['en'];
            }

            var lines = (fmt.indexOf('|') === -1) ? [fmt] : fmt.split('|'),
                address = [];

            array.forEach(lines, function(line) {
                line = _this.replaceAddressPart(line, o);
                if (!isEmpty(line)) {
                    this.push(_this.encode(_this.collapseSpace(line)));
                }
            }, address);

            if (asText) {
                if (separator === true) {
                    separator = '\n';
                }
                return address.join(separator || '
');
            }

            return string.substitute(
                '${0}',
                [address.join('
'), encodeURIComponent(_this.decode(address.join(' ')))]
            );
        },
        collapseSpace: function(text) {
            return lang.trim(text.replace(/\s+/g, ' '));
        },
        resolveAddressCulture: function(o) {
            return Mobile.SalesLogix.Format.countryCultures[o.Country] || Mobile.CultureInfo.name;
        },
        replaceAddressPart: function(fmt, o) {
            return fmt.replace(/s|S|a1|a2|a3|a4|m|M|z|Z|r|R|p|P|c|C/g,
                function(part) {
                    switch (part) {
                        case "s":
                            return o.Salutation || '';
                        case "S":
                            return (o.Salutation && o.Salutation.toUpperCase()) || '';
                        case "a1":
                            return o.Address1 || '';
                        case "a2":
                            return o.Address2 || '';
                        case "a3":
                            return o.Address3 || '';
                        case "a4":
                            return o.Address4 || '';
                        case "m":
                            return o.City || '';
                        case "M":
                            return (o.City && o.City.toUpperCase()) || '';
                        case "z":
                            return o.County || '';
                        case "Z":
                            return (o.County && o.County.toUpperCase()) || '';
                        case "r":
                            return o.State || '';
                        case "R":
                            return (o.State && o.State.toUpperCase()) || '';
                        case "p":
                            return o.PostalCode || '';
                        case "P":
                            return (o.PostalCode && o.PostalCode.toUpperCase()) || '';
                        case "c":
                            return o.Country || '';
                        case "C":
                            return (o.Country && o.Country.toUpperCase()) || '';
                    }
                }
            );
        },
        // These were added to the SDK, and should not be here. Keeping the alias to not break anyone with a minor update.
        phoneFormat: format.phoneFormat,
        phone: format.phone,
        currency: function(val) {
            if (isNaN(val) || val === null) {
                return val;
            }

            var v = val.toFixed(2), // only 2 decimal places
                f = Math.floor((100 * (v - Math.floor(v))).toPrecision(2)); // for fractional part, only need 2 significant digits

            return string.substitute(
                '${0}'
                    + Mobile.CultureInfo.numberFormat.currencyDecimalSeparator
                    + '${1}', [
                        (Math.floor(v)).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + Mobile.CultureInfo.numberFormat.currencyGroupSeparator.replace("\\.", '.')),
                        (f.toString().length < 2) ? '0' + f.toString() : f.toString()
                    ]
            ).replace(/ /g, '\u00A0'); //keep numbers from breaking
        },
        bigNumberAbbrText: {
            'billion': 'B',
            'million': 'M',
            'thousand': 'K'
        },
        bigNumber: function(val) {
            var numParse = isNaN(val) ? parseFloat(val) : val,
                text = Mobile.SalesLogix.Format.bigNumberAbbrText;

            if (numParse && numParse >= 1000000000) {
                numParse = numParse / 1000000000;
                return dojoNumber.format(numParse, { places: 1 }) + text['billion'];
            } else if (numParse && numParse >= 1000000) {
                numParse = numParse / 1000000;
                return dojoNumber.format(numParse, { places: 1 }) + text['million'];
            } else if (numParse && numParse >= 1000) {
                numParse = numParse / 1000;
                return dojoNumber.format(numParse, { places: 1 }) + text['thousand'];
            }

            return val;
        },
        relativeDate: function(date, timeless) {
            var now;
            date = moment(date);
            if (!date || !date.isValid()) {
                throw new Error('Invalid date passed into Mobile.SalesLogix.Format.relativeDate');
            }

            if (timeless) {
                // utc
                date = date.add({minutes: date.zone()});
            }

            return date.fromNow();
        },
        multiCurrency: function(val, code) {
            return string.substitute('${0} ${1}', [Mobile.SalesLogix.Format.currency(val), code]);
        },
        nameLF: function(val) {
            if (!val) {
                return '';
            }

            var name = template.nameLF.apply(val);

            return name;
        },
        mail: function(val) {
            if (typeof val !== 'string') {
                return val;
            }

            return string.substitute('${0}', [val]);
        },
        userActivityFormatText: {
            'asUnconfirmed': 'Unconfirmed',
            'asAccepted': 'Accepted',
            'asDeclned': 'Declined'
        },
        userActivityStatus: function(val) {
            return Mobile.SalesLogix.Format.userActivityFormatText[val];
        },
        /**
         * Takes a string input and converts name to First amd Last initials
         * `Lee Hogan` -> `LH`
         * @param val
         * @returns {String}
         */
        formatUserInitial: function(user) {
            var firstLast = this.resolveFirstLast(user),
                initials = [firstLast[0].substr(0, 1)];

            if (firstLast[1]) {
                initials.push(firstLast[1].substr(0, 1));
            }

            return initials.join('').toUpperCase();
        },
        /**
        * Takes a string input and the user name to First amd Last name
        * `Hogan, Lee` -> `Lee Hogan`
        * @param val
        * @returns {String}
        */
        formatByUser: function(user) {
            var name = this.resolveFirstLast(user);
            return name.join(' ');
        },
        /**
       * Takes a string input and the user name to First amd Last name
       * `Hogan, Lee` -> `Lee Hogan`
       * @param val
       * @returns {String}
       */
        resolveFirstLast: function(name) {
            var firstLast = [];
            if (name.indexOf(' ') !== -1) {
                var names = name.split(' ');
                if (names[0].indexOf(',') !== -1) {
                    firstLast = [names[1], names[0].slice(0, -1)];
                }
                else {
                    firstLast = [names[0], names[1]];
                }
            }
            else {
                firstLast = [name];
            }
            return firstLast;
        },
        fixedLocale: function(val, d) {
            var num, frac, p, v, f, fVal;
            if (isNaN(val) || val === null) {
                return val;
            }

            if (typeof d !== 'number') {
                d = 2;
            }
            if (d > 0 ) {
                p = Math.pow(10, d);
                v = val.toFixed(d); // only d decimal places
                f = Math.floor((p * (v - Math.floor(v))).toPrecision(d)); // for fractional part, only need d significant digits
                if (f === 0) {
                    f = (p + "").slice(1);
                }
            } else {  //zero decimal palces
               p = Math.pow(10, 0);
               v = (Math.round(val * p) / p);
               f = 0;
            }
            num = Math.floor(v).toString();
            num = num.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + Mobile.CultureInfo.numberFormat.numberGroupSeparator.replace("\\.", '.'));
            if (d > 0) {
                frac = (f.toString().length < d) ? '' : f.toString();
                fVal = string.substitute(
                    '${0}'
                        + Mobile.CultureInfo.numberFormat.numberDecimalSeparator
                        + '${1}', [num, frac]);
            } else {
                fVal = num;
            }
            return fVal.replace(/ /g, '\u00A0'); //keep numbers from breaking
        }
    }));
});

<|endoftext|>


<commit_before>/*!
 * bootlint - https://github.com/cvrebert/bootlint
 * Copyright (c) 2014 Christopher Rebert
 * Licensed under the MIT license.
 */

(function (exports) {
    'use strict';

    var COL_CLASSES = [];
    var SCREENS = ['xs', 'sm', 'md', 'lg'];
    SCREENS.forEach(function (screen) {
        for (var n = 1; n <= 12; n++) {
            COL_CLASSES.push('.col-' + screen + '-' + n);
        }
    });

    function isDoctype(node) {
        return node.type === 'directive' && node.name === '!doctype';
    }

    exports.lintDoctype = function ($) {
        var doctype = $(':root')[0];
        while (doctype && !isDoctype(doctype)) {
            doctype = doctype.prev;
        }
        if (!doctype) {
            return "Document is missing a DOCTYPE declaration";
        }
        var doctypeId = doctype.data.toLowerCase();
        if (doctypeId !== '!doctype html' && doctypeId !== '!doctype html system "about:legacy-compat"') {
            return "Document declares a non-HTML5 DOCTYPE";
        }
        return null;
    };
    exports.lintMetaCharsetUtf8 = function ($) {
        var meta = $('head>meta[charset]');
        var charset = meta.attr('charset');
        if (!charset) {
            return '<head> is missing UTF-8 charset <meta> tag';
        }
        if (charset.toLowerCase() !== "utf-8") {
            return 'charset <meta> tag is specifying a legacy, non-UTF-8 charset';
        }
        return null;
    };
    exports.lintXUaCompatible = function ($) {
        var meta = $('head>meta[http-equiv="X-UA-Compatible"][content="IE=edge"]');
        if (!meta.length) {
            return "<head> is missing X-UA-Compatible <meta> tag that disables old IE compatibility modes";
        }
        return null;
    };
    exports.lintViewport = function ($) {
        var meta = $('head>meta[name="viewport"][content]');
        if (!meta.length) {
            return "<head> is missing viewport <meta> tag that enables responsiveness";
        }
        return null;
    };
    exports.lintBootstrapv2 = function ($) {
        var columnClasses = [];
        for (var n = 1; n <= 12; n++) {
            columnClasses.push('.span' + n);
        }
        var selector = columnClasses.join(',');
        var spanNs = $(selector);
        if (spanNs.length) {
            return "Found one or more uses of outdated Bootstrap v2 `.spanN` grid classes";
        }
        return null;
    };
    exports.lintContainers = function ($) {
        var rowsOutsideContainers = $('*:not(.container):not(.container-fluid)>.row');
        if (rowsOutsideContainers.length) {
            return "Found one or more `.row`s that were not children of a `.container` or `.container-fluid`";
        }
        return null;
    };
    exports.lintRowAndColOnSameElem = function ($) {
        var selector = COL_CLASSES.map(function (col) { return ".row" + col; }).join(',');
        var rowCols = $(selector);
        if (rowCols.length) {
            return "Found both `.row` and `.col-*-*` used on the same element";
        }
        return null;
    };
    exports.lintRemoteModals = function ($) {
        var remoteModalTriggers = $('[data-toggle="modal"][data-remote]');
        if (remoteModalTriggers.length) {
            return "Found one or more modals using the deprecated `remote` option";
        }
        return null;
    };
    exports.lintJquery = function ($) {
        var theWindow = null;
        try {
            theWindow = window;
        }
        catch (e) {
            // deliberately do nothing
        }
        if (theWindow && (theWindow.$ || theWindow.jQuery)) {
            return null;
        }
        var jqueries = $('script[src*="jquery"],script[src*="jQuery"]');
        if (!jqueries.length) {
            return "Unable to locate jQuery, which is required for Bootstrap's JavaScript plugins to work";
        }
        return null;
    };
    exports.lintInputGroupFormControlTypes = function ($) {
        var errs = [];
        var selectInputGroups = $('.input-group select');
        if (selectInputGroups.length) {
            errs.push("`.input-group` contains a <select>; this should be avoided as <select>s cannot be fully styled in WebKit browsers");
        }
        var textareaInputGroups = $('.input-group textarea');
        if (textareaInputGroups.length) {
            errs.push("`.input-group` contains a <textarea>; only text-based <input>s are permitted in an `.input-group`");
        }
        return errs;
    };
    exports.lintBootstrapJs = function ($) {
        if ($('script[src$="bootstrap.js"]').length && $('script[src$="bootstrap.min.js"]').length) {
            return "Only one copy of Bootstrap's JS should be included; currently the webpage includes both bootstrap.js and bootstrap.min.js";
        }
        return null;
    };
    exports.lintTooltipsOnDisabledElems = function ($) {
        var selector = [
            '[disabled][data-toggle="tooltip"]',
            '.disabled[data-toggle="tooltip"]',
            '[disabled][data-toggle="popover"]',
            '.disabled[data-toggle="popover"]'
        ].join(',');
        var disabledWithTooltips = $(selector);
        if (disabledWithTooltips.length) {
            return "Tooltips and popovers on disabled elements cannot be triggered by user interaction unless the element becomes enabled." +
                " To have tooltips and popovers be triggerable by the user even when their associated element is disabled," +
                " put the disabled element inside a wrapper <div> and apply the tooltip or popover to the wrapper <div> instead.";
        }
        return null;
    };
    exports.lintTooltipsInBtnGroups = function ($) {
        var nonBodyContainers = $('.btn-group [data-toggle="tooltip"]:not([data-container="body"]), .btn-group [data-toggle="popover"]:not([data-container="body"])');
        if (nonBodyContainers.length) {
            return "Tooltips and popovers within button groups should have their `container` set to 'body'. Found tooltips/popovers that might lack this setting.";
        }
        return null;
    };
    exports.lintMultipleFormControlsInInputGroup = function ($) {
        var badInputGroups = $('.input-group').filter(function (i, inputGroup) {
            return $(inputGroup).find('.form-control').length > 1;
        });
        if (badInputGroups.length) {
            return "Input groups cannot contain multiple `.form-control`s";
        }
        return null;
    };
    exports.lintFormGroupMixedWithInputGroup = function ($) {
        var badMixes = $('.input-group.form-group');
        if (badMixes.length) {
            return ".input-group and .form-group cannot be used directly on the same element. Instead, nest the .input-group within the .form-group";
        }
        return null;
    };
    exports.lintGridClassMixedWithInputGroup = function ($) {
        var selector = COL_CLASSES.map(function (colClass) { return '.input-group' + colClass; }).join(',');
        var badMixes = $(selector);
        if (badMixes.length) {
            return ".input-group and .col-*-* cannot be used directly on the same element. Instead, nest the .input-group within the .col-*-*";
        }
        return null;
    };
    exports.lintRowChildrenAreCols = function ($) {
        var selector = '.row>*' + COL_CLASSES.map(function (colClass) { return ':not(' + colClass + ')'; }).join('');
        var nonColRowChildren = $(selector);
        if (nonColRowChildren.length) {
            return "Only columns (.col-*-*) may be children of `.row`s";
        }
        return null;
    };
    exports.lintInputGroupsWithMultipleAddOnsPerSide = function ($) {
        var addOnClasses = ['.input-group-addon', '.input-group-btn'];
        var combos = [];
        addOnClasses.forEach(function (first) {
            addOnClasses.forEach(function (second) {
                combos.push('.input-group>' + first + '+' + second);
            });
        });
        var selector = combos.join(',');
        var multipleAddOns = $(selector);
        if (multipleAddOns.length) {
            return "Having multiple add-ons on a single side of an input group is not supported";
        }
        return null;
    };
    exports.lint = function (html) {
        var cheerio = require('cheerio');
        var $ = cheerio.load(html);
        var errs = [];
        errs.push(this.lintDoctype($));
        errs.push(this.lintMetaCharsetUtf8($));
        errs.push(this.lintXUaCompatible($));
        errs.push(this.lintBootstrapv2($));
        errs.push(this.lintContainers($));
        errs.push(this.lintViewport($));
        errs.push(this.lintRowAndColOnSameElem($));
        errs.push(this.lintRowChildrenAreCols($));
        errs.push(this.lintRemoteModals($));
        errs.push(this.lintJquery($));
        errs.push(this.lintBootstrapJs($));
        errs.push(this.lintTooltipsOnDisabledElems($));
        errs.push(this.lintTooltipsInBtnGroups($));
        errs.push(this.lintMultipleFormControlsInInputGroup($));
        errs.push(this.lintFormGroupMixedWithInputGroup($));
        errs.push(this.lintGridClassMixedWithInputGroup($));
        errs.push(this.lintInputGroupsWithMultipleAddOnsPerSide($));
        errs = errs.concat(this.lintInputGroupFormControlTypes($));
        errs = errs.filter(function (item) { return item !== null; });
        return errs;
    };

}(typeof exports === 'object' && exports || this));
<commit_msg>add special-cases for the Bootstrap docs themselves<commit_after>/*!
 * bootlint - https://github.com/cvrebert/bootlint
 * Copyright (c) 2014 Christopher Rebert
 * Licensed under the MIT license.
 */

(function (exports) {
    'use strict';

    var COL_CLASSES = [];
    var SCREENS = ['xs', 'sm', 'md', 'lg'];
    SCREENS.forEach(function (screen) {
        for (var n = 1; n <= 12; n++) {
            COL_CLASSES.push('.col-' + screen + '-' + n);
        }
    });

    function isDoctype(node) {
        return node.type === 'directive' && node.name === '!doctype';
    }

    exports.lintDoctype = function ($) {
        var doctype = $(':root')[0];
        while (doctype && !isDoctype(doctype)) {
            doctype = doctype.prev;
        }
        if (!doctype) {
            return "Document is missing a DOCTYPE declaration";
        }
        var doctypeId = doctype.data.toLowerCase();
        if (doctypeId !== '!doctype html' && doctypeId !== '!doctype html system "about:legacy-compat"') {
            return "Document declares a non-HTML5 DOCTYPE";
        }
        return null;
    };
    exports.lintMetaCharsetUtf8 = function ($) {
        var meta = $('head>meta[charset]');
        var charset = meta.attr('charset');
        if (!charset) {
            return '<head> is missing UTF-8 charset <meta> tag';
        }
        if (charset.toLowerCase() !== "utf-8") {
            return 'charset <meta> tag is specifying a legacy, non-UTF-8 charset';
        }
        return null;
    };
    exports.lintXUaCompatible = function ($) {
        var meta = $('head>meta[http-equiv="X-UA-Compatible"][content="IE=edge"]');
        if (!meta.length) {
            return "<head> is missing X-UA-Compatible <meta> tag that disables old IE compatibility modes";
        }
        return null;
    };
    exports.lintViewport = function ($) {
        var meta = $('head>meta[name="viewport"][content]');
        if (!meta.length) {
            return "<head> is missing viewport <meta> tag that enables responsiveness";
        }
        return null;
    };
    exports.lintBootstrapv2 = function ($) {
        var columnClasses = [];
        for (var n = 1; n <= 12; n++) {
            columnClasses.push('.span' + n);
        }
        var selector = columnClasses.join(',');
        var spanNs = $(selector);
        if (spanNs.length) {
            return "Found one or more uses of outdated Bootstrap v2 `.spanN` grid classes";
        }
        return null;
    };
    exports.lintContainers = function ($) {
        var rowsOutsideContainers = $('*:not(.container):not(.container-fluid):not(.bs-example)>.row');
        if (rowsOutsideContainers.length) {
            return "Found one or more `.row`s that were not children of a `.container` or `.container-fluid`";
        }
        return null;
    };
    exports.lintRowAndColOnSameElem = function ($) {
        var selector = COL_CLASSES.map(function (col) { return ".row" + col; }).join(',');
        var rowCols = $(selector);
        if (rowCols.length) {
            return "Found both `.row` and `.col-*-*` used on the same element";
        }
        return null;
    };
    exports.lintRemoteModals = function ($) {
        var remoteModalTriggers = $('[data-toggle="modal"][data-remote]');
        if (remoteModalTriggers.length) {
            return "Found one or more modals using the deprecated `remote` option";
        }
        return null;
    };
    exports.lintJquery = function ($) {
        var theWindow = null;
        try {
            theWindow = window;
        }
        catch (e) {
            // deliberately do nothing
        }
        if (theWindow && (theWindow.$ || theWindow.jQuery)) {
            return null;
        }
        var jqueries = $('script[src*="jquery"],script[src*="jQuery"]');
        if (!jqueries.length) {
            return "Unable to locate jQuery, which is required for Bootstrap's JavaScript plugins to work";
        }
        return null;
    };
    exports.lintInputGroupFormControlTypes = function ($) {
        var errs = [];
        var selectInputGroups = $('.input-group select');
        if (selectInputGroups.length) {
            errs.push("`.input-group` contains a <select>; this should be avoided as <select>s cannot be fully styled in WebKit browsers");
        }
        var textareaInputGroups = $('.input-group textarea');
        if (textareaInputGroups.length) {
            errs.push("`.input-group` contains a <textarea>; only text-based <input>s are permitted in an `.input-group`");
        }
        return errs;
    };
    exports.lintBootstrapJs = function ($) {
        if ($('script[src$="bootstrap.js"]').length && $('script[src$="bootstrap.min.js"]').length) {
            return "Only one copy of Bootstrap's JS should be included; currently the webpage includes both bootstrap.js and bootstrap.min.js";
        }
        return null;
    };
    exports.lintTooltipsOnDisabledElems = function ($) {
        var selector = [
            '[disabled][data-toggle="tooltip"]',
            '.disabled[data-toggle="tooltip"]',
            '[disabled][data-toggle="popover"]',
            '.disabled[data-toggle="popover"]'
        ].join(',');
        var disabledWithTooltips = $(selector);
        if (disabledWithTooltips.length) {
            return "Tooltips and popovers on disabled elements cannot be triggered by user interaction unless the element becomes enabled." +
                " To have tooltips and popovers be triggerable by the user even when their associated element is disabled," +
                " put the disabled element inside a wrapper <div> and apply the tooltip or popover to the wrapper <div> instead.";
        }
        return null;
    };
    exports.lintTooltipsInBtnGroups = function ($) {
        var nonBodyContainers = $('.btn-group [data-toggle="tooltip"]:not([data-container="body"]), .btn-group [data-toggle="popover"]:not([data-container="body"])');
        if (nonBodyContainers.length) {
            return "Tooltips and popovers within button groups should have their `container` set to 'body'. Found tooltips/popovers that might lack this setting.";
        }
        return null;
    };
    exports.lintMultipleFormControlsInInputGroup = function ($) {
        var badInputGroups = $('.input-group').filter(function (i, inputGroup) {
            return $(inputGroup).find('.form-control').length > 1;
        });
        if (badInputGroups.length) {
            return "Input groups cannot contain multiple `.form-control`s";
        }
        return null;
    };
    exports.lintFormGroupMixedWithInputGroup = function ($) {
        var badMixes = $('.input-group.form-group');
        if (badMixes.length) {
            return ".input-group and .form-group cannot be used directly on the same element. Instead, nest the .input-group within the .form-group";
        }
        return null;
    };
    exports.lintGridClassMixedWithInputGroup = function ($) {
        var selector = COL_CLASSES.map(function (colClass) { return '.input-group' + colClass; }).join(',');
        var badMixes = $(selector);
        if (badMixes.length) {
            return ".input-group and .col-*-* cannot be used directly on the same element. Instead, nest the .input-group within the .col-*-*";
        }
        return null;
    };
    exports.lintRowChildrenAreCols = function ($) {
        var ALLOWED_CHILD_CLASSES = COL_CLASSES.concat(['.clearfix', '.bs-customizer-input']);
        var selector = '.row>*' + ALLOWED_CHILD_CLASSES.map(function (colClass) { return ':not(' + colClass + ')'; }).join('');
        var nonColRowChildren = $(selector);
        if (nonColRowChildren.length) {
            return "Only columns (.col-*-*) may be children of `.row`s";
        }
        return null;
    };
    exports.lintInputGroupsWithMultipleAddOnsPerSide = function ($) {
        var addOnClasses = ['.input-group-addon', '.input-group-btn'];
        var combos = [];
        addOnClasses.forEach(function (first) {
            addOnClasses.forEach(function (second) {
                combos.push('.input-group>' + first + '+' + second);
            });
        });
        var selector = combos.join(',');
        var multipleAddOns = $(selector);
        if (multipleAddOns.length) {
            return "Having multiple add-ons on a single side of an input group is not supported";
        }
        return null;
    };
    exports.lint = function (html) {
        var cheerio = require('cheerio');
        var $ = cheerio.load(html);
        var errs = [];
        errs.push(this.lintDoctype($));
        errs.push(this.lintMetaCharsetUtf8($));
        errs.push(this.lintXUaCompatible($));
        errs.push(this.lintBootstrapv2($));
        errs.push(this.lintContainers($));
        errs.push(this.lintViewport($));
        errs.push(this.lintRowAndColOnSameElem($));
        errs.push(this.lintRowChildrenAreCols($));
        errs.push(this.lintRemoteModals($));
        errs.push(this.lintJquery($));
        errs.push(this.lintBootstrapJs($));
        errs.push(this.lintTooltipsOnDisabledElems($));
        errs.push(this.lintTooltipsInBtnGroups($));
        errs.push(this.lintMultipleFormControlsInInputGroup($));
        errs.push(this.lintFormGroupMixedWithInputGroup($));
        errs.push(this.lintGridClassMixedWithInputGroup($));
        errs.push(this.lintInputGroupsWithMultipleAddOnsPerSide($));
        errs = errs.concat(this.lintInputGroupFormControlTypes($));
        errs = errs.filter(function (item) { return item !== null; });
        return errs;
    };

}(typeof exports === 'object' && exports || this));
<|endoftext|>