<commit_before>let _loaderInstance = null;
class TBLoader {
  constructor(args = null){
    //Make a singleton instance
    if(!_loaderInstance) {
      _loaderInstance = this;
    }

    this.preloadQueue = null;
    this.backgroundQueue = null;

    this.totalNumberOfPreloadAssets = 0;
    this.numberOfPreloadedAssets = 0;

    this.totalNumberOfBackgroundAssets = 0;
    this.numberOfBackgroundAssets = 0;

    this.preloadProgressCallback = args.preloadProgressCallback || null;
    this.preloadCompletedCallback = args.preloadCompletedCallback || null;

    this.backgroundProgressCallback = args.backgroundProgressCallback || null;
    this.backgroundCompletedCallback = args.backgroundCompletedCallback || null;

    this.autoStartBackgroundLoad = false || args.autoStartBackgroundLoad;

    if(args.preload){
      this.initializePreloadQueue(args.preload);
    }

    if(args.backgroundLoad) {
      this.initializeBackgroundQueue(args.backgroundLoad);
    }

    return _loaderInstance;
  }

  startLoad() {
    if(this.preloadQueue){
      this.startPreload();
    }
  }

  initializePreloadQueue(args) {
    if(args == null || !args){
      return;
    }

    this.preloadQueue = [];
    for(let asset of args) {
      if((/\.(gif|jpg|jpeg|tiff|png)$/i).test(asset)) {
        this.preloadQueue.push({
          type: 'image',
          src: asset,
        });
      } else if((/\.(mp4|webm)$/i).test(asset)) {
        this.preloadQueue.push({
          type: 'video',
          src: asset
        });
      }

      this.totalNumberOfPreloadAssets++;
    }
  }

  initializeBackgroundQueue(args) {

    if(args == null || !args){
      return;
    }

    this.backgroundQueue = [];
    for(let asset of args) {
      if((/\.(gif|jpg|jpeg|tiff|png)$/i).test(asset)) {
        this.backgroundQueue.push({
          type: 'image',
          src: asset,
        });
      } else if((/\.(mp4|webm)$/i).test(asset)) {
        this.backgroundQueue.push({
          type: 'video',
          src: asset
        });
      }

      this.totalNumberOfBackgroundAssets++;
    }
  }

  startPreload() {
    for(let asset of this.preloadQueue) {
      var t = this.preloadAsset(asset.src, asset.type);
      t.then(() => {
        this.preloadProgressHandler();
      })
      .catch(() => {
        this.errorHandler();
      });
    }
  }

  startBackgroundLoad() {
    for(let asset of this.backgroundQueue) {
      var t = this.preloadAsset(asset.src, asset.type);
      t.then(() => {
        this.backgroundProgressHandler();
      })
      .catch((e) => {
        console.log(e);
        this.errorHandler();
      });
    }
  }

  preloadAsset(path, type) {
    return new Promise((resolve, reject) => {
        let asset;
        if(type == 'image') {
          asset = new Image();
        } else if(type == 'video') {
          asset = document.createElement('video');
          asset.addEventListener('suspend', resolve);
        }

        asset.onload = resolve;
        asset.onerror = reject;
        asset.src = path + "?_=" + (new Date().getTime());
        if(type == 'video') {
          asset.load();
        }
    });
  }

  preloadProgressHandler() {
    this.numberOfPreloadedAssets++;

    if(this.preloadProgressCallback) {
      let data = {
        completed: this.numberOfPreloadedAssets,
        total: this.totalNumberOfPreloadAssets,
        percentage: Math.round(((this.numberOfPreloadedAssets / this.totalNumberOfPreloadAssets) * 100))
      };

      this.preloadProgressCallback(data);
    }

    if(this.numberOfPreloadedAssets == this.totalNumberOfPreloadAssets) {
      this.preloadCompletedHandler();
    }
  }

  backgroundProgressHandler(progress) {
    this.numberOfBackgroundAssets++;

    if(this.backgroundProgressCallback) {
      let data = {
        completed: this.numberOfBackgroundAssets,
        total: this.totalNumberOfBackgroundAssets,
        percentage: Math.round(((this.numberOfBackgroundAssets / this.totalNumberOfBackgroundAssets) * 100))
      };

      this.backgroundProgressCallback(data);
    }

    if(this.numberOfBackgroundAssets == this.totalNumberOfBackgroundAssets) {
      this.backgroundCompletedHandler();
    }
  }

  preloadCompletedHandler() {
    if(this.preloadCompletedCallback) {
      this.preloadCompletedCallback();
    }

    if(this.autoStartBackgroundLoad) {
      this.startBackgroundLoad();
    }

  }

  backgroundCompletedHandler() {
    if(this.backgroundCompletedCallback) {
      this.backgroundCompletedCallback();
    }

    this.resetAllCallbacks();
  }

  resetAllCallbacks() {
    this.preloadProgressCallback =  null;
    this.preloadCompletedCallback =  null;

    this.backgroundProgressCallback = null;
    this.backgroundCompletedCallback = null;
  }

  errorHandler() {
    console.log("An error occured");
  }
}

export default TBLoader;
<commit_msg>Added better error handling for files not found<commit_after>let _loaderInstance = null;
class TBLoader {
  constructor(args = null){
    //Make a singleton instance
    if(!_loaderInstance) {
      _loaderInstance = this;
    }

    this.preloadQueue = null;
    this.backgroundQueue = null;

    this.totalNumberOfPreloadAssets = 0;
    this.numberOfPreloadedAssets = 0;

    this.totalNumberOfBackgroundAssets = 0;
    this.numberOfBackgroundAssets = 0;

    this.preloadProgressCallback = args.preloadProgressCallback || null;
    this.preloadCompletedCallback = args.preloadCompletedCallback || null;

    this.backgroundProgressCallback = args.backgroundProgressCallback || null;
    this.backgroundCompletedCallback = args.backgroundCompletedCallback || null;

    this.autoStartBackgroundLoad = false || args.autoStartBackgroundLoad;

    if(args.preload){
      this.initializePreloadQueue(args.preload);
    }

    if(args.backgroundLoad) {
      this.initializeBackgroundQueue(args.backgroundLoad);
    }

    return _loaderInstance;
  }

  startLoad() {
    if(this.preloadQueue){
      this.startPreload();
    }
  }

  initializePreloadQueue(args) {
    if(args == null || !args){
      return;
    }

    this.preloadQueue = [];
    for(let asset of args) {
      if((/\.(gif|jpg|jpeg|tiff|png)$/i).test(asset)) {
        this.preloadQueue.push({
          type: 'image',
          src: asset,
        });
      } else if((/\.(mp4|webm)$/i).test(asset)) {
        this.preloadQueue.push({
          type: 'video',
          src: asset
        });
      }

      this.totalNumberOfPreloadAssets++;
    }
  }

  initializeBackgroundQueue(args) {

    if(args == null || !args){
      return;
    }

    this.backgroundQueue = [];
    for(let asset of args) {
      if((/\.(gif|jpg|jpeg|tiff|png)$/i).test(asset)) {
        this.backgroundQueue.push({
          type: 'image',
          src: asset,
        });
      } else if((/\.(mp4|webm)$/i).test(asset)) {
        this.backgroundQueue.push({
          type: 'video',
          src: asset
        });
      }

      this.totalNumberOfBackgroundAssets++;
    }
  }

  startPreload() {
    for(let asset of this.preloadQueue) {
      var t = this.preloadAsset(asset.src, asset.type);
      t.then(() => {
        this.preloadProgressHandler();
      })
      .catch(() => {
        this.errorHandler(asset.src);
      });
    }
  }

  startBackgroundLoad() {
    for(let asset of this.backgroundQueue) {
      var t = this.preloadAsset(asset.src, asset.type);
      t.then(() => {
        this.backgroundProgressHandler();
      })
      .catch((e) => {
        console.log(e);
        this.errorHandler(asset.src);
      });
    }
  }

  preloadAsset(path, type) {
    return new Promise((resolve, reject) => {
        let asset;
        if(type == 'image') {
          asset = new Image();
        } else if(type == 'video') {
          asset = document.createElement('video');
          asset.addEventListener('suspend', resolve);
        }

        asset.onload = resolve;
        asset.onerror = reject;
        asset.src = path + "?_=" + (new Date().getTime());
        if(type == 'video') {
          asset.load();
        }
    });
  }

  preloadProgressHandler() {
    this.numberOfPreloadedAssets++;

    if(this.preloadProgressCallback) {
      let data = {
        completed: this.numberOfPreloadedAssets,
        total: this.totalNumberOfPreloadAssets,
        percentage: Math.round(((this.numberOfPreloadedAssets / this.totalNumberOfPreloadAssets) * 100))
      };

      this.preloadProgressCallback(data);
    }

    if(this.numberOfPreloadedAssets == this.totalNumberOfPreloadAssets) {
      this.preloadCompletedHandler();
    }
  }

  backgroundProgressHandler(progress) {
    this.numberOfBackgroundAssets++;

    if(this.backgroundProgressCallback) {
      let data = {
        completed: this.numberOfBackgroundAssets,
        total: this.totalNumberOfBackgroundAssets,
        percentage: Math.round(((this.numberOfBackgroundAssets / this.totalNumberOfBackgroundAssets) * 100))
      };

      this.backgroundProgressCallback(data);
    }

    if(this.numberOfBackgroundAssets == this.totalNumberOfBackgroundAssets) {
      this.backgroundCompletedHandler();
    }
  }

  preloadCompletedHandler() {
    if(this.preloadCompletedCallback) {
      this.preloadCompletedCallback();
    }

    if(this.autoStartBackgroundLoad) {
      this.startBackgroundLoad();
    }

  }

  backgroundCompletedHandler() {
    if(this.backgroundCompletedCallback) {
      this.backgroundCompletedCallback();
    }

    this.resetAllCallbacks();
  }

  resetAllCallbacks() {
    this.preloadProgressCallback =  null;
    this.preloadCompletedCallback =  null;

    this.backgroundProgressCallback = null;
    this.backgroundCompletedCallback = null;
  }

  errorHandler(asset) {
    this.abortLoad();
    throw "Cannot find file " + asset;
  }

  abortLoad() {
    this.resetAllCallbacks();
    this.preloadQueue = null;
    this.backgroundQueue = null;
  }

}

export default TBLoader;
<|endoftext|>


<commit_before>//
// ES6 module loader
//
// Minimal System loader implementation based on
// https://github.com/caridy/es6-micro-loader
//
// Add class and babel transpile support. Transpile targets modern
// chrome browsers and omits much ES5 compatible transformations.
//
import * as path from 'path'
import * as babel from 'babel-core'

export class Loader {
  constructor(options = {}) {
    this._registry = Object.create(null)

    if (options.base) {
      this._base = new URL(options.base)
    }
  }

  get(name) {
    let mod = this._registry[name]

    if (mod && !mod.executed) {
      mod.execute()
    }

    return mod && mod.proxy
  }

  register(name, dependencies, wrapper) {
    if (Array.isArray(name)) {
      this._anonymousEntry = []
      this._anonymousEntry.push.apply(this._anonymousEntry, arguments)
      return // breaking to let the _load function to name the module
    }

    let proxy = Object.create(null)
    let values = Object.create(null)
    let mod, meta

    // creating a new entry in the internal registry
    this._registry[name] = mod = {

      // live bindings
      proxy: proxy,

      // exported values
      values: values,

      // if module is already initialized
      executed: false,

      // normalized dependencies
      dependencies: dependencies.map(dep => {
        return path.normalize(path.resolve(name, '..', dep))
      }),

      // other modules that depends on this so we can push updates into those modules
      dependants: [],

      // method used to push updates of dependencies into the module body
      update: (moduleName, moduleObj) => {
        meta.setters[mod.dependencies.indexOf(moduleName)](moduleObj)
      },

      execute: () => {
        // Flag as executed
        mod.executed = true

        mod.dependencies.map(dep => {
          let imports = this.get(dep) && this._registry[dep].values // optimization to pass plain values instead of bindings

          if (imports) {
            this._registry[dep].dependants.push(name)

            mod.update(dep, imports)
          }
        })

        meta.execute()
      }
    }

    let _export = (identifier, value) => {
      if (typeof identifier === 'object') {
        for (let prop in Object.getOwnPropertyNames(identifier)) {
          _export(prop, identifier[prop])
        }

        return identifier
      }

      values[identifier] = value

      // locking down the updates on the module to avoid infinite loop
      mod.lock = true

      mod.dependants.forEach(function(moduleName) {
        if (this._registry[moduleName] && !this._registry[moduleName].lock) {
          this._registry[moduleName].update(name, values)
        }
      })

      mod.lock = false

      if (!Object.getOwnPropertyDescriptor(proxy, identifier)) {
          Object.defineProperty(proxy, identifier, {
              enumerable: true,
              get: () => {
                  return values[identifier]
              }
          })
      }

      return value
    }

    // collecting execute() and setters[]
    meta = wrapper(_export)
  }

  async import(modName, options = {}) {
    let name = path.normalize(modName)
    let mod = this.get(name)

    if (mod) {
      return mod
    }

    await this.load(name, options)

    return this.get(name)
  }

  async transpile(blob, {filename}) {
    let source = babel.transform(blob, {
      plugins: [
        require("babel-plugin-syntax-async-functions"),
        require("babel-plugin-syntax-async-generators"),
        require("babel-plugin-syntax-do-expressions"),
        require("babel-plugin-syntax-exponentiation-operator"),
        require("babel-plugin-syntax-export-extensions"),
        require("babel-plugin-syntax-function-bind"),
        require("babel-plugin-syntax-object-rest-spread"),
        require("babel-plugin-syntax-trailing-function-commas"),
        require("babel-plugin-transform-async-to-generator"),
        require("babel-plugin-transform-async-to-module-method"),
        require("babel-plugin-transform-do-expressions"),
        require("babel-plugin-transform-es2015-destructuring"),
        require("babel-plugin-transform-es2015-modules-systemjs"),
        require("babel-plugin-transform-exponentiation-operator"),
        require("babel-plugin-transform-export-extensions"),
        require("babel-plugin-transform-function-bind"),
        require("babel-plugin-transform-object-rest-spread"),
      ],
      sourceMaps: 'inline',
      filename: filename,
      sourceFileName: filename,
      compact: true,
    })

    return source
  }

  async resolve(name) {
    return do {
      if (this._base) {
        new URL(path.normalize('./' + name), this._base)
      } else {
        name
      }
    }
  }

  async fetch(uri) {
    let response = await self.fetch(uri)

    if (response.status != 200) {
      throw new Error('Could not fetch: ' + name)
    }

    let blob = await response.text()

    return blob
  }

  async load(name, options = {}) {
    let uri = await this.resolve(name, options)
    let blob = await this.fetch(uri, options)

    let source = await this.transpile(blob, {
      moduleId: name,
      filename: name
    })

    let code = source.code + '\n//# sourceURL=' + uri + '!transpiled'

    new Function('System', code)(this)

    if (this._anonymousEntry) {
      this.register(name, this._anonymousEntry[0], this._anonymousEntry[1]);
      this._anonymousEntry = undefined;
    }

    let mod = this._registry[name]

    if (!mod) {
      throw new Error('Error loading module ' + name)
    }

    return Promise.all(mod.dependencies.map(dependency => {
      if (this._registry[dependency]) {
        return Promise.resolve()
      } else {
        return this.load(dependency)
      }
    }))
  }
}
<commit_msg>Do not pathify single name modules for special cases<commit_after>//
// ES6 module loader
//
// Minimal System loader implementation based on
// https://github.com/caridy/es6-micro-loader
//
// Add class and babel transpile support. Transpile targets modern
// chrome browsers and omits much ES5 compatible transformations.
//
import * as path from 'path'
import * as babel from 'babel-core'

export class Loader {
  constructor(options = {}) {
    this._registry = Object.create(null)

    if (options.base) {
      this._base = new URL(options.base)
    }
  }

  get(name) {
    let mod = this._registry[name]

    if (mod && !mod.executed) {
      mod.execute()
    }

    return mod && mod.proxy
  }

  register(name, dependencies, wrapper) {
    if (Array.isArray(name)) {
      this._anonymousEntry = []
      this._anonymousEntry.push.apply(this._anonymousEntry, arguments)
      return // breaking to let the _load function to name the module
    }

    let proxy = Object.create(null)
    let values = Object.create(null)
    let mod, meta

    // creating a new entry in the internal registry
    this._registry[name] = mod = {

      // live bindings
      proxy: proxy,

      // exported values
      values: values,

      // if module is already initialized
      executed: false,

      // normalized dependencies
      dependencies: dependencies.map(dep => do {
        // Handle special cases for import names like "kernel"
        // They must not be path and must not have an extension
        if (dep.indexOf('/') < 0 && dep.indexOf('.') < 0) {
          dep
        } else {
          path.normalize(path.resolve(name, '..', dep))
        }
      }),

      // other modules that depends on this so we can push updates into those modules
      dependants: [],

      // method used to push updates of dependencies into the module body
      update: (moduleName, moduleObj) => {
        meta.setters[mod.dependencies.indexOf(moduleName)](moduleObj)
      },

      execute: () => {
        // Flag as executed
        mod.executed = true

        mod.dependencies.map(dep => {
          let imports = this.get(dep) && this._registry[dep].values // optimization to pass plain values instead of bindings

          if (imports) {
            this._registry[dep].dependants.push(name)

            mod.update(dep, imports)
          }
        })

        meta.execute()
      }
    }

    let _export = (identifier, value) => {
      if (typeof identifier === 'object') {
        for (let prop in Object.getOwnPropertyNames(identifier)) {
          _export(prop, identifier[prop])
        }

        return identifier
      }

      values[identifier] = value

      // locking down the updates on the module to avoid infinite loop
      mod.lock = true

      mod.dependants.forEach(function(moduleName) {
        if (this._registry[moduleName] && !this._registry[moduleName].lock) {
          this._registry[moduleName].update(name, values)
        }
      })

      mod.lock = false

      if (!Object.getOwnPropertyDescriptor(proxy, identifier)) {
          Object.defineProperty(proxy, identifier, {
              enumerable: true,
              get: () => {
                  return values[identifier]
              }
          })
      }

      return value
    }

    // collecting execute() and setters[]
    meta = wrapper(_export)
  }

  async import(modName, options = {}) {
    let name = path.normalize(modName)
    let mod = this.get(name)

    if (mod) {
      return mod
    }

    await this.load(name, options)

    return this.get(name)
  }

  async transpile(blob, {filename}) {
    let source = babel.transform(blob, {
      plugins: [
        require("babel-plugin-syntax-async-functions"),
        require("babel-plugin-syntax-async-generators"),
        require("babel-plugin-syntax-do-expressions"),
        require("babel-plugin-syntax-exponentiation-operator"),
        require("babel-plugin-syntax-export-extensions"),
        require("babel-plugin-syntax-function-bind"),
        require("babel-plugin-syntax-object-rest-spread"),
        require("babel-plugin-syntax-trailing-function-commas"),
        require("babel-plugin-transform-async-to-generator"),
        require("babel-plugin-transform-async-to-module-method"),
        require("babel-plugin-transform-do-expressions"),
        require("babel-plugin-transform-es2015-destructuring"),
        require("babel-plugin-transform-es2015-modules-systemjs"),
        require("babel-plugin-transform-exponentiation-operator"),
        require("babel-plugin-transform-export-extensions"),
        require("babel-plugin-transform-function-bind"),
        require("babel-plugin-transform-object-rest-spread"),
      ],
      sourceMaps: 'inline',
      filename: filename,
      sourceFileName: filename,
      compact: true,
    })

    return source
  }

  async resolve(name) {
    return do {
      if (this._base) {
        new URL(path.normalize('./' + name), this._base)
      } else {
        name
      }
    }
  }

  async fetch(uri) {
    let response = await self.fetch(uri)

    if (response.status != 200) {
      throw new Error('Could not fetch: ' + name)
    }

    let blob = await response.text()

    return blob
  }

  async load(name, options = {}) {
    let uri = await this.resolve(name, options)
    let blob = await this.fetch(uri, options)

    let source = await this.transpile(blob, {
      moduleId: name,
      filename: name
    })

    let code = source.code + '\n//# sourceURL=' + uri + '!transpiled'

    new Function('System', code)(this)

    if (this._anonymousEntry) {
      this.register(name, this._anonymousEntry[0], this._anonymousEntry[1]);
      this._anonymousEntry = undefined;
    }

    let mod = this._registry[name]

    if (!mod) {
      throw new Error('Error loading module ' + name)
    }

    return Promise.all(mod.dependencies.map(dependency => {
      if (this._registry[dependency]) {
        return Promise.resolve()
      } else {
        return this.load(dependency)
      }
    }))
  }
}
<|endoftext|>


<commit_before>/**
 * Utility functions for the notification route handlers.
 */

var async = require('async');
var config = require('config');
var lodash = require('lodash');
var logger = require('log4js').getLogger('server');

var models = require('../../db/models');
var MessageAdapter = require('../../message_adapters/message_adapter');

var SUPPORTED_CHANNELS = config.get('SUPPORTED_CHANNELS');

/**
 * Constructs a Sequelize-friendly criteria object to search for notifications.
 *
 * @param query The query parameters submitted to the server
 * @returns {{offset: Number, limit: Number, order: *}}
 */
var getNotificationFindCriteria = function(query) {
  // NOTE: due to its complexity and the fact it's a 3rd-party lib, the getNotifications query
  //       object from datatables isn't Joi-validated
  var search = query.search.value;

  var findCriteria = {
    offset: parseInt(query.start),
    limit: parseInt(query.length),
    order: lodash.map(query.order, function(order) {
      return [query.columns[order.column].data, order.dir];
    })
  };

  if (search !== '') {
    findCriteria.where = ["payload LIKE '%" + search + "%'"];
  }

  return findCriteria;
};

/**
 * Creates a clean notification object from a Hapi request payload.
 *
 * @param payload
 * @returns {Object}
 */
var notificationFromPayload = function(payload) {

  var channels = lodash.isUndefined(payload.channels) ? SUPPORTED_CHANNELS : payload.channels;

  var emptyStats = {idCount: 0, success: 0, unregistered: 0, failure: 0};
  var stats = lodash.zipObject(lodash.map(channels, function(channel) {
    return [channel, lodash.clone(emptyStats)];
  }));
  stats.total = lodash.clone(emptyStats);

  // TODO(leah): Add in an assertion check to ensure that if deviceIds have been provided
  //             that the notification is only going to a single channel.
  var notification = {
    title: lodash.isUndefined(payload.title) ? null : payload.title,
    message: payload.message,
    sound: lodash.isUndefined(payload.sound) ? null : payload.sound,
    data: lodash.isUndefined(payload.data) ? null : payload.data,
    channels: channels,
    mode: lodash.isUndefined(payload.mode) ? 'prod' : payload.mode, // NOTE: default prod
    deviceIds: lodash.isUndefined(payload.deviceIds) ? null : payload.deviceIds,
    state: 'pending',
    stats: stats
  };
  notification.payload = lodash.cloneDeep(notification);

  return notification;
};

/**
 * Fetches the device ids subscribed to the supplied channels.
 *
 * @param channels The channels to fetch device ids for.
 * @param done The callback to call once the fetch completes.
 */
var fetchDeviceIdsForChannels = function(channels, success, error) {

  var queryCriteria = {
    where: {channel: channels},
    attributes: ['subscriptionId', 'language', 'deviceId', 'channel'],
    // Use raw to reduce object footprint
    raw: true
  };

  // TODO(leah): This should move to a limit / offset based iterator. Unfortunately, sequelize
  //             doesn't seem to support lazy iteration of query results. So, implement a wrapper
  //             to protect against pulling a huge result and getting mem issues.
  models.Subscriptions
    .findAll(queryCriteria)
    .then(function(subscriptions) {

      var groupedSubscriptions = lodash.zipObject(lodash.map(channels, function(channel) {
        return [channel, []];
      }));

      lodash.forEach(subscriptions, function(subscription) {
        groupedSubscriptions[subscription.channel].push({
          subscriptionId: subscription.subscriptionId,
          language: subscription.language,
          deviceId: subscription.deviceId
        });
      });

      success(groupedSubscriptions);
    }, error);
};

/**
 * Sends a notification out via the supported channels
 *
 * @param notification The notification to send.
 * @param {function} dispatchFn The function responsible for sending the adapted messages and
 *     deviceIds to the remote servers for distribution.
 */
var sendNotification = function(notification, dispatchFn) {

  var noDeviceIds = (
    lodash.isUndefined(notification.deviceIds) ||
    notification.deviceIds === null ||
    lodash.isEmpty(notification.deviceIds)
  );

  if (noDeviceIds) {
    // TODO(leah): Update this to use an iterator of some kind, so we're not shuttling around objects
    //             that could be arbitrarily large.
    fetchDeviceIdsForChannels(
      notification.channels,
      function(groupedSubscriptions) {
        var arrLengths = lodash.map(groupedSubscriptions, function(val) {
          return val.length;
        });

        var devicesToSendTo = lodash.reduce(arrLengths, function(sum, num) {
          return sum + num;
        }) > 0;

        if (devicesToSendTo) {
          sendNotificationToSubscribers(notification, groupedSubscriptions, dispatchFn);
        } else {
          updateNotificationStateAndStats(notification.notificationId, 'success', undefined);
        }
      },
      function(err) {
        logger.error('Fetching device ids for channels %s failed with:\n%s', channels, err.toString());
        updateNotificationStateAndStats(notification.notificationId, 'error', undefined);
      }
    );
  } else {
    var groupedSubscriptions = lodash.zipObject(
      [notification.channels[0]], [notification.deviceIds]);
    sendNotificationToSubscribers(notification, groupedSubscriptions, dispatchFn);
  }
};

/**
 *
 * @param notification
 * @param groupedSubscriptions
 * @param {function} dispatchFn The function responsible for sending the adapted messages and
 *     deviceIds to the remote servers for distribution.
 */
var sendNotificationToSubscribers = function(notification, groupedSubscriptions, dispatchFn) {
  var msgAdapter = new MessageAdapter(notification, groupedSubscriptions);

  var wrappedDispatchFn = function(channel, deviceIds, message, callback) {
    dispatchFn(channel, deviceIds, message, function(err, results) {
      callback(err, lodash.zipObject([channel], [results]))
    });
  };

  var channelDispatchFns = lodash.map(msgAdapter.adapters, function(adapter, channel) {
    return lodash.partial(wrappedDispatchFn, channel, adapter.deviceIds, adapter.message);
  });

  async.parallel(channelDispatchFns, function(err, results) {

    var stats = summarizeNotificationStats(results);

    if (lodash.isUndefined(err)) {
      updateNotificationStateAndStats(notification.notificationId, 'success', stats);
    } else {
      updateNotificationStateAndStats(notification.notificationId, 'failed', stats);
    }
  });
};

/**
 * Gets a stats object showing total success across all channels.
 *
 * @param {Array.<Object>} results array of stats objects to summarize.
 * @returns {*}
 */
var summarizeNotificationStats = function(results) {
  var emptyStats = {idCount: 0, success: 0, unregistered: 0, failure: 0};

  var incrementStats = function(total, subTotal) {
    total.idCount += subTotal.idCount;
    total.success += subTotal.success;
    total.unregistered += subTotal.unregistered;
    total.failure += subTotal.failure;
  };

  return lodash.reduce(results, function(accumulator, subTotal) {

    var channel = lodash.keys(subTotal)[0];
    var subTotalStats = lodash.values(subTotal)[0];

    if (!lodash.has(accumulator, channel)) {
      accumulator[channel] = lodash.clone(emptyStats);
    }

    incrementStats(accumulator.total, subTotalStats);
    incrementStats(accumulator[channel], subTotalStats);

    return accumulator;
  }, {total: lodash.cloneDeep(emptyStats)});
};

/**
 * Updates the specified notification to the supplied state.
 * @param notificationId
 * @param state
 * @param opt_stats
 */
var updateNotificationStateAndStats = function(notificationId, state, opt_stats) {
  models.Notifications
    .find({where: {notificationId: notificationId}})
    .then(function(notification) {
      notification.state = state;

      if (!lodash.isUndefined(opt_stats)) {
        notification.stats = opt_stats;
      }

      notification.save()
        .then(function() {}, function(err) {
          logger.error(
            'Unable to update notificationId %s to state %s, failed with:\n%s',
            notificationId, state, err.toString());
        });
    },
    function(err) {
      logger.error(
        'Unable to update notificationId %s to failed state, failed with:\n%s',
        notificationId, err.toString());
    });
};

module.exports.getNotificationFindCriteria = getNotificationFindCriteria;
module.exports.notificationFromPayload = notificationFromPayload;
module.exports.fetchDeviceIdsForChannels = fetchDeviceIdsForChannels;
module.exports.sendNotification = sendNotification;
module.exports.summarizeNotificationStats = summarizeNotificationStats;
<commit_msg>return the promise<commit_after>/**
 * Utility functions for the notification route handlers.
 */

var async = require('async');
var config = require('config');
var lodash = require('lodash');
var logger = require('log4js').getLogger('server');

var models = require('../../db/models');
var MessageAdapter = require('../../message_adapters/message_adapter');

var SUPPORTED_CHANNELS = config.get('SUPPORTED_CHANNELS');

/**
 * Constructs a Sequelize-friendly criteria object to search for notifications.
 *
 * @param query The query parameters submitted to the server
 * @returns {{offset: Number, limit: Number, order: *}}
 */
var getNotificationFindCriteria = function(query) {
  // NOTE: due to its complexity and the fact it's a 3rd-party lib, the getNotifications query
  //       object from datatables isn't Joi-validated
  var search = query.search.value;

  var findCriteria = {
    offset: parseInt(query.start),
    limit: parseInt(query.length),
    order: lodash.map(query.order, function(order) {
      return [query.columns[order.column].data, order.dir];
    })
  };

  if (search !== '') {
    findCriteria.where = ["payload LIKE '%" + search + "%'"];
  }

  return findCriteria;
};

/**
 * Creates a clean notification object from a Hapi request payload.
 *
 * @param payload
 * @returns {Object}
 */
var notificationFromPayload = function(payload) {

  var channels = lodash.isUndefined(payload.channels) ? SUPPORTED_CHANNELS : payload.channels;

  var emptyStats = {idCount: 0, success: 0, unregistered: 0, failure: 0};
  var stats = lodash.zipObject(lodash.map(channels, function(channel) {
    return [channel, lodash.clone(emptyStats)];
  }));
  stats.total = lodash.clone(emptyStats);

  // TODO(leah): Add in an assertion check to ensure that if deviceIds have been provided
  //             that the notification is only going to a single channel.
  var notification = {
    title: lodash.isUndefined(payload.title) ? null : payload.title,
    message: payload.message,
    sound: lodash.isUndefined(payload.sound) ? null : payload.sound,
    data: lodash.isUndefined(payload.data) ? null : payload.data,
    channels: channels,
    mode: lodash.isUndefined(payload.mode) ? 'prod' : payload.mode, // NOTE: default prod
    deviceIds: lodash.isUndefined(payload.deviceIds) ? null : payload.deviceIds,
    state: 'pending',
    stats: stats
  };
  notification.payload = lodash.cloneDeep(notification);

  return notification;
};

/**
 * Fetches the device ids subscribed to the supplied channels.
 *
 * @param channels The channels to fetch device ids for.
 * @param done The callback to call once the fetch completes.
 */
var fetchDeviceIdsForChannels = function(channels, success, error) {

  var queryCriteria = {
    where: {channel: channels},
    attributes: ['subscriptionId', 'language', 'deviceId', 'channel'],
    // Use raw to reduce object footprint
    raw: true
  };

  // TODO(leah): This should move to a limit / offset based iterator. Unfortunately, sequelize
  //             doesn't seem to support lazy iteration of query results. So, implement a wrapper
  //             to protect against pulling a huge result and getting mem issues.
  models.Subscriptions
    .findAll(queryCriteria)
    .then(function(subscriptions) {

      var groupedSubscriptions = lodash.zipObject(lodash.map(channels, function(channel) {
        return [channel, []];
      }));

      lodash.forEach(subscriptions, function(subscription) {
        groupedSubscriptions[subscription.channel].push({
          subscriptionId: subscription.subscriptionId,
          language: subscription.language,
          deviceId: subscription.deviceId
        });
      });

      success(groupedSubscriptions);
    }, error);
};

/**
 * Sends a notification out via the supported channels
 *
 * @param notification The notification to send.
 * @param {function} dispatchFn The function responsible for sending the adapted messages and
 *     deviceIds to the remote servers for distribution.
 */
var sendNotification = function(notification, dispatchFn) {

  var noDeviceIds = (
    lodash.isUndefined(notification.deviceIds) ||
    notification.deviceIds === null ||
    lodash.isEmpty(notification.deviceIds)
  );

  if (noDeviceIds) {
    // TODO(leah): Update this to use an iterator of some kind, so we're not shuttling around objects
    //             that could be arbitrarily large.
    fetchDeviceIdsForChannels(
      notification.channels,
      function(groupedSubscriptions) {
        var arrLengths = lodash.map(groupedSubscriptions, function(val) {
          return val.length;
        });

        var devicesToSendTo = lodash.reduce(arrLengths, function(sum, num) {
          return sum + num;
        }) > 0;

        if (devicesToSendTo) {
          sendNotificationToSubscribers(notification, groupedSubscriptions, dispatchFn);
        } else {
          updateNotificationStateAndStats(notification.notificationId, 'success', undefined);
        }
      },
      function(err) {
        logger.error('Fetching device ids for channels %s failed with:\n%s', channels, err.toString());
        updateNotificationStateAndStats(notification.notificationId, 'error', undefined);
      }
    );
  } else {
    var groupedSubscriptions = lodash.zipObject(
      [notification.channels[0]], [notification.deviceIds]);
    sendNotificationToSubscribers(notification, groupedSubscriptions, dispatchFn);
  }
};

/**
 *
 * @param notification
 * @param groupedSubscriptions
 * @param {function} dispatchFn The function responsible for sending the adapted messages and
 *     deviceIds to the remote servers for distribution.
 */
var sendNotificationToSubscribers = function(notification, groupedSubscriptions, dispatchFn) {
  var msgAdapter = new MessageAdapter(notification, groupedSubscriptions);

  var wrappedDispatchFn = function(channel, deviceIds, message, callback) {
    dispatchFn(channel, deviceIds, message, function(err, results) {
      callback(err, lodash.zipObject([channel], [results]))
    });
  };

  var channelDispatchFns = lodash.map(msgAdapter.adapters, function(adapter, channel) {
    return lodash.partial(wrappedDispatchFn, channel, adapter.deviceIds, adapter.message);
  });

  async.parallel(channelDispatchFns, function(err, results) {

    var stats = summarizeNotificationStats(results);

    if (lodash.isUndefined(err)) {
      updateNotificationStateAndStats(notification.notificationId, 'success', stats);
    } else {
      updateNotificationStateAndStats(notification.notificationId, 'failed', stats);
    }
  });
};

/**
 * Gets a stats object showing total success across all channels.
 *
 * @param {Array.<Object>} results array of stats objects to summarize.
 * @returns {*}
 */
var summarizeNotificationStats = function(results) {
  var emptyStats = {idCount: 0, success: 0, unregistered: 0, failure: 0};

  var incrementStats = function(total, subTotal) {
    total.idCount += subTotal.idCount;
    total.success += subTotal.success;
    total.unregistered += subTotal.unregistered;
    total.failure += subTotal.failure;
  };

  return lodash.reduce(results, function(accumulator, subTotal) {

    var channel = lodash.keys(subTotal)[0];
    var subTotalStats = lodash.values(subTotal)[0];

    if (!lodash.has(accumulator, channel)) {
      accumulator[channel] = lodash.clone(emptyStats);
    }

    incrementStats(accumulator.total, subTotalStats);
    incrementStats(accumulator[channel], subTotalStats);

    return accumulator;
  }, {total: lodash.cloneDeep(emptyStats)});
};

/**
 * Updates the specified notification to the supplied state.
 * @param notificationId
 * @param state
 * @param opt_stats
 */
var updateNotificationStateAndStats = function(notificationId, state, opt_stats) {
  models.Notifications
    .find({where: {notificationId: notificationId}})
    .then(function(notification) {
      notification.state = state;

      if (!lodash.isUndefined(opt_stats)) {
        notification.stats = opt_stats;
      }

      return notification.save()
        .then(function() {}, function(err) {
          logger.error(
            'Unable to update notificationId %s to state %s, failed with:\n%s',
            notificationId, state, err.toString());
        });
    },
    function(err) {
      logger.error(
        'Unable to update notificationId %s to failed state, failed with:\n%s',
        notificationId, err.toString());
    });
};

module.exports.getNotificationFindCriteria = getNotificationFindCriteria;
module.exports.notificationFromPayload = notificationFromPayload;
module.exports.fetchDeviceIdsForChannels = fetchDeviceIdsForChannels;
module.exports.sendNotification = sendNotification;
module.exports.summarizeNotificationStats = summarizeNotificationStats;
<|endoftext|>


<commit_before>//
//  This class wraps composable pieces of logic for manipulating chunk data.
//  To use call one of the static methods to get an instance, and then apply
//  mutations as desired before calling the generate function to get the final
//  chunk description data.
//
//  Example:
//      ChunkBuilder.newEmpty()
//          .fillSquare('grass', {width: 20, height: 20})
//          .addCoast()
//          .padWithWater(10)
//          .generateChunk();
//
const TILE_SIZE = 32;   // TODO: this should be configured with the tile set to be flexible

class ChunkBuilder {
    // Static Initializers
    static newEmpty() {
        return new ChunkBuilder();
    }

    // Modifier API
    fillSquare(tileType, {top = 0, left = 0, width = 1, height = 1} = {}) { // jshint ignore:line
        const totalWidth = left + width;
        const totalHeight = top + height;

        while (this.height < totalHeight) {
            this.addEmptyRow();
        }

        while (this.width < totalWidth) {
            this.addEmptyColumn();
        }

        for (let x = left; x < totalWidth; x++) {
            for (let y = top; y < totalHeight; y++) {
                this.grid[y][x].tile = tileType;
            }
        }

        return this;
    }

    addCoast() {
        return this;
    }

    padWithWater(paddingDepth = 1) {
        return this;
    }

    generateChunk() {
        const tilePositions = [];

        for (let x = 0; x < this.width; x++) {
            for (let y = 0; y < this.height; y++) {
                const cell = this.grid[y][x];

                tilePositions.push({
                    type: cell.tile,
                    position: {
                        x: x * TILE_SIZE,
                        y: y * TILE_SIZE
                    }
                });
            }
        }

        return tilePositions;
    }

    // Private helpers
    constructor() {
        this.width = 0;
        this.height = 0;
        this.grid = [[]];   // initialize to a 0x0 matrix
    }

    addEmptyRow() {
        const row = [];
        for (let i = 0; i < this.width; i++) {
            row.push(new Cell());
        }
        this.grid.push(row);
        this.height++;
    }

    addEmptyColumn() {
        this.grid.forEach(row => row.push(new Cell()));
        this.width++;
    }
}

class Cell {
    constructor() {
        this.tile = null;
        this.clutter = null;    // not implemented
        this.passable = true;   // not implemented
    }
}

export default ChunkBuilder;<commit_msg>make row and column functions take a tile type to make them more generically useful<commit_after>//
//  This class wraps composable pieces of logic for manipulating chunk data.
//  To use call one of the static methods to get an instance, and then apply
//  mutations as desired before calling the generate function to get the final
//  chunk description data.
//
//  Example:
//      ChunkBuilder.newEmpty()
//          .fillSquare('grass', {width: 20, height: 20})
//          .addCoast()
//          .padWithWater(10)
//          .generateChunk();
//
const TILE_SIZE = 32;   // TODO: this should be configured with the tile set to be flexible

class ChunkBuilder {
    // Static Initializers
    static newEmpty() {
        return new ChunkBuilder();
    }

    // Modifier API
    fillSquare(tileType, {top = 0, left = 0, width = 1, height = 1} = {}) { // jshint ignore:line
        const totalWidth = left + width;
        const totalHeight = top + height;

        while (this.height < totalHeight) {
            this.addRow();
        }

        while (this.width < totalWidth) {
            this.addColumn();
        }

        for (let x = left; x < totalWidth; x++) {
            for (let y = top; y < totalHeight; y++) {
                this.grid[y][x].tile = tileType;
            }
        }

        return this;
    }

    addCoast() {
        // TODO: This is very locked into the one tileset, we should generalize this sort of logic at some point

        return this;
    }

    padWithWater(paddingDepth = 1) {
        return this;
    }

    generateChunk() {
        const tilePositions = [];

        for (let x = 0; x < this.width; x++) {
            for (let y = 0; y < this.height; y++) {
                const cell = this.grid[y][x];

                tilePositions.push({
                    type: cell.tile,
                    position: {
                        x: x * TILE_SIZE,
                        y: y * TILE_SIZE
                    }
                });
            }
        }

        return tilePositions;
    }

    // Private helpers
    constructor() {
        this.width = 0;
        this.height = 0;
        this.grid = [[]];   // initialize to a 0x0 matrix
    }

    addRow(tile = null) {
        const row = [];
        for (let i = 0; i < this.width; i++) {
            row.push(new Cell(tile));
        }
        this.grid.push(row);
        this.height++;
    }

    addColumn(tile = null) {
        this.grid.forEach(row => row.push(new Cell(tile)));
        this.width++;
    }
}

class Cell {
    constructor(tile) {
        this.tile = tile;
        this.clutter = null;    // not implemented
        this.passable = true;   // not implemented
    }
}

export default ChunkBuilder;<|endoftext|>


<commit_before>import {sendBeacon} from './polyfill.js';
import {iframeAnnounce} from './lib/announce.js';

// defer extra scripts until after 'load' event
window.addEventListener('load', (ev) => {
  iframeAnnounce('load');

  window.requestAnimationFrame(() => {
    const scriptPWACompat = document.createElement('script');
    scriptPWACompat.src = 'https://cdn.jsdelivr.net/npm/pwacompat@2.0.9/pwacompat.min.js';
    scriptPWACompat.setAttribute('integrity', 'sha384-VcI6S+HIsE80FVM1jgbd6WDFhzKYA0PecD/LcIyMQpT4fMJdijBh0I7Iblaacawc');
    scriptPWACompat.setAttribute('crossorigin', 'anonymous');
    document.head.appendChild(scriptPWACompat);
    // nb. the outerHTML trick doesn't seem to work

    if (!document.currentScript) {
      // absence indicates we're in module mode, so load extended code
      const scriptExtended = document.createElement('script');
      scriptExtended.src = document.body.getAttribute('data-ext');
      scriptExtended.type = 'module';
      document.head.appendChild(scriptExtended);
    }

    if (window._dev) {
      return;  // don't analytics in dev
    }

    const scriptAnalytics = document.createElement('script');
    scriptAnalytics.src = 'https://www.google-analytics.com/analytics.js';
    document.head.appendChild(scriptAnalytics);
  });
});

// create local GA, this matches the 'isogram' code
const tempGA = function() {
  tempGA['q'].push(arguments);
};
tempGA['q'] = [];
tempGA['l'] = 1 * new Date;
window['ga'] = tempGA;
window['GoogleAnalyticsObject'] = 'ga';

window.addEventListener('message', (ev) => {
  const type = ev.data.type || '';
  switch (type) {
    case 'focus':
      // used by extension to trigger focus
      // Chrome disallows autofocus, but programatic works (as of 75): I don't think it'll last.
      typer.focus();
      break;
    case 'ga':
      // used by extension to log load time
      ga.apply(null, ev.data.payload);
      break;
    default:
      console.debug('unhandled message', ev.data);
  }
});

// enqueue initial GA events
sendBeacon || ga('set', 'transport', 'beacon');
ga('create', 'UA-39885839-6', 'auto');
ga('send', 'pageview');<commit_msg>use unpkg pwacompat<commit_after>import {sendBeacon} from './polyfill.js';
import {iframeAnnounce} from './lib/announce.js';

// defer extra scripts until after 'load' event
window.addEventListener('load', (ev) => {
  iframeAnnounce('load');

  window.requestAnimationFrame(() => {
    const scriptPWACompat = document.createElement('script');
    scriptPWACompat.src = 'https://unpkg.com/pwacompat';
    scriptPWACompat.setAttribute('crossorigin', 'anonymous');
    document.head.appendChild(scriptPWACompat);
    // nb. the outerHTML trick doesn't seem to work

    if (!document.currentScript) {
      // absence indicates we're in module mode, so load extended code
      const scriptExtended = document.createElement('script');
      scriptExtended.src = document.body.getAttribute('data-ext');
      scriptExtended.type = 'module';
      document.head.appendChild(scriptExtended);
    }

    if (window._dev) {
      return;  // don't analytics in dev
    }

    const scriptAnalytics = document.createElement('script');
    scriptAnalytics.src = 'https://www.google-analytics.com/analytics.js';
    document.head.appendChild(scriptAnalytics);
  });
});

// create local GA, this matches the 'isogram' code
const tempGA = function() {
  tempGA['q'].push(arguments);
};
tempGA['q'] = [];
tempGA['l'] = 1 * new Date;
window['ga'] = tempGA;
window['GoogleAnalyticsObject'] = 'ga';

window.addEventListener('message', (ev) => {
  const type = ev.data.type || '';
  switch (type) {
    case 'focus':
      // used by extension to trigger focus
      // Chrome disallows autofocus, but programatic works (as of 75): I don't think it'll last.
      typer.focus();
      break;
    case 'ga':
      // used by extension to log load time
      ga.apply(null, ev.data.payload);
      break;
    default:
      console.debug('unhandled message', ev.data);
  }
});

// enqueue initial GA events
sendBeacon || ga('set', 'transport', 'beacon');
ga('create', 'UA-39885839-6', 'auto');
ga('send', 'pageview');
<|endoftext|>


<commit_before>/*
* @Author: gbk
* @Date:   2016-05-02 22:07:46
* @Last Modified by:   gbk
* @Last Modified time: 2017-06-21 20:00:57
*/

'use strict';

var os = require('os');
var path = require('path');

var util = require('./util');

module.exports = function(options) {
  var srcPath = util.cwdPath(options.src);
  if (options.includes) {
    srcPath = [
      srcPath
    ].concat(options.includes.map(function(include) {
      return util.cwdPath(include);
    }));
  }
  var preLoader = options.keepcss ? 'style-loader!export-css-loader?remove=false' : 'style-loader';
  var presets = util.babel('preset', [
    {
      name: 'es2015',
      options: {
        loose: !!options.loose
      }
    },
    'stage-0',
    'react'
  ]);
  var cacheDirectory = path.join(os.tmpdir(), options.loose ? 'babel-loose' : 'babel-strict');
  var plugins = [
    'add-module-exports',
    'transform-decorators-legacy',
    'transform-es3-member-expression-literals',
    'transform-es3-property-literals',
    {
      name: 'transform-runtime',
      options: {
        polyfill: !!options.polyfill,
        helpers: false,
        regenerator: true
      }
    }
  ];
  if (options.loose) {
    plugins.push('transform-proto-to-assign');
  }
  return [{
    test: /\.jsx?$/,
    loader: 'babel-loader',
    include: srcPath,
    query: options.lazyload ? {
      plugins: util.babel('plugin', plugins),
      presets: presets,
      cacheDirectory: cacheDirectory,
      babelrc: false
    } : {
      plugins: util.babel('plugin', [
        'add-module-exports',
        'transform-decorators-legacy',
        {
          name: 'transform-runtime',
          options: {
            polyfill: !!options.polyfill,
            helpers: false,
            regenerator: true
          }
        },
        {
          name: 'react-transform',
          options: {
            transforms: [
              {
                transform: 'react-transform-hmr',
                imports: [ 'react' ],
                locals: [ 'module' ]
              }, {
                transform: 'react-transform-catch-errors',
                imports: [ 'react', 'redbox-react' ]
              }
            ]
          }
        }
      ]),
      presets: presets,
      cacheDirectory: cacheDirectory,
      babelrc: false
    }
  }, {
    test: /\.js$/,
    loader: 'es3ify-loader',
    include: function(path) {
      return ~path.indexOf('babel-runtime');
    }
  }, {
    test: /\.css$/,
    loader: preLoader + '!css-loader?sourceMap',
  }, {
    test: /\.less$/,
    loader: preLoader + '!css-loader?sourceMap!less-loader',
  }, {
    test: /\.styl$/,
    loader: preLoader + '!css-loader?sourceMap!stylus-loader',
  }, {
    test: /\.svg$/,
    loader: 'babel-loader',
    query: {
      presets: presets,
      cacheDirectory: cacheDirectory,
      babelrc: false
    }
  }, {
    test: /\.svg$/,
    loader: 'svg2react-loader',
  }, {
    test: /\.json$/,
    loader: 'json-loader',
  }, {
    test: /\.(png|jpe?g|gif|woff|woff2|ttf|otf)$/,
    loader: 'url-loader',
  },{
    test: /\.tsx?$/,
    loader: 'ts-loader',
    include: srcPath,
    query: {
      transpileOnly: true
    }
  }];
};
<commit_msg>fix loose/lazyload issue<commit_after>/*
* @Author: gbk
* @Date:   2016-05-02 22:07:46
* @Last Modified by:   gbk
* @Last Modified time: 2017-06-21 20:00:57
*/

'use strict';

var os = require('os');
var path = require('path');

var util = require('./util');

module.exports = function(options) {
  var srcPath = util.cwdPath(options.src);
  if (options.includes) {
    srcPath = [
      srcPath
    ].concat(options.includes.map(function(include) {
      return util.cwdPath(include);
    }));
  }
  var preLoader = options.keepcss ? 'style-loader!export-css-loader?remove=false' : 'style-loader';
  var presets = util.babel('preset', [
    {
      name: 'es2015',
      options: {
        loose: !!options.loose
      }
    },
    'stage-0',
    'react'
  ]);
  var cacheDirectory = path.join(os.tmpdir(), options.loose ? 'babel-loose' : 'babel-strict');
  var plugins = [
    'add-module-exports',
    'transform-decorators-legacy',
    'transform-es3-member-expression-literals',
    'transform-es3-property-literals',
    options.loose && 'transform-proto-to-assign',
    {
      name: 'transform-runtime',
      options: {
        polyfill: !!options.polyfill,
        helpers: false,
        regenerator: true
      }
    }
  ].filter(Boolean);
  return [{
    test: /\.jsx?$/,
    loader: 'babel-loader',
    include: srcPath,
    query: options.lazyload ? {
      plugins: util.babel('plugin', plugins),
      presets: presets,
      cacheDirectory: cacheDirectory,
      babelrc: false
    } : {
      plugins: util.babel('plugin', [
        'add-module-exports',
        'transform-decorators-legacy',
        options.loose && 'transform-proto-to-assign',
        {
          name: 'transform-runtime',
          options: {
            polyfill: !!options.polyfill,
            helpers: false,
            regenerator: true
          }
        },
        {
          name: 'react-transform',
          options: {
            transforms: [
              {
                transform: 'react-transform-hmr',
                imports: [ 'react' ],
                locals: [ 'module' ]
              }, {
                transform: 'react-transform-catch-errors',
                imports: [ 'react', 'redbox-react' ]
              }
            ]
          }
        }
      ].filter(Boolean)),
      presets: presets,
      cacheDirectory: cacheDirectory,
      babelrc: false
    }
  }, {
    test: /\.js$/,
    loader: 'es3ify-loader',
    include: function(path) {
      return ~path.indexOf('babel-runtime');
    }
  }, {
    test: /\.css$/,
    loader: preLoader + '!css-loader?sourceMap',
  }, {
    test: /\.less$/,
    loader: preLoader + '!css-loader?sourceMap!less-loader',
  }, {
    test: /\.styl$/,
    loader: preLoader + '!css-loader?sourceMap!stylus-loader',
  }, {
    test: /\.svg$/,
    loader: 'babel-loader',
    query: {
      presets: presets,
      cacheDirectory: cacheDirectory,
      babelrc: false
    }
  }, {
    test: /\.svg$/,
    loader: 'svg2react-loader',
  }, {
    test: /\.json$/,
    loader: 'json-loader',
  }, {
    test: /\.(png|jpe?g|gif|woff|woff2|ttf|otf)$/,
    loader: 'url-loader',
  },{
    test: /\.tsx?$/,
    loader: 'ts-loader',
    include: srcPath,
    query: {
      transpileOnly: true
    }
  }];
};
<|endoftext|>


<commit_before>App.view.items_Shortcuts = Ext.Array.push(App.view.items_Shortcuts || [], [
{
    text:
'' +
'

' +
l10n.um.users +
'
'
   ,height:110 ,minWidth:92
   ,tooltip: l10n.um.tooltip
   ,handler:
    function open_userman(btn){
    var tb = Ext.getCmp('wm').items.getByKey('um.view.Userman')
        if(tb){
            tb.toggle(true)
        } else {
            App.create('um.controller.Userman', btn)
        }
    }
}
,
{
    text:
'' +
'

' +
l10n.um.chat.title +
'
'
   ,height:110 ,minWidth:92
   ,tooltip: l10n.um.chat.tooltip
   ,handler:
    function open_chat(btn){
    var id = 'Chat', tb = Ext.getCmp('wm').items.getByKey(id)
        if(tb){
            tb.toggle(true)
        } else {
            if(!App.getApplication().controllers.getByKey(id)){
                App.create('controller.' + id, btn)
            }
        }
    }
}
])
<commit_msg>um items_Shortcuts Chat: update for consistency<commit_after>App.view.items_Shortcuts = Ext.Array.push(App.view.items_Shortcuts || [], [
{
    text:
'' +
'

' +
l10n.um.users +
'
'
   ,height:110 ,minWidth:92
   ,tooltip: l10n.um.tooltip
   ,handler:
    function open_userman(btn){
    var tb = Ext.getCmp('wm').items.getByKey('um.view.Userman')
        if(tb){
            tb.toggle(true)
        } else {
            App.create('um.controller.Userman', btn)
        }
    }
}
,
{
    text:
'' +
'

' +
l10n.um.chat.title +
'
'
   ,height:110 ,minWidth:92
   ,tooltip: l10n.um.chat.tooltip
   ,handler:
    function open_chat(btn){
    var tb = Ext.getCmp('wm').items.getByKey('view.Chat')
        if(tb){
            tb.toggle(true)
        } else {
            App.create('controller.Chat', btn)
        }
    }
}
])
<|endoftext|>


<commit_before>import test from "ava"; import "babel-core/register"

import beautifyHTML from "../../../__tests__/utils/beautifyHTML"
import htmlMetas from "../../../html-metas"

import toHTML, { writeAllHTMLFiles } from "../index"

import { testStore, testRoutes } from "./utils"

test("don't break if there is nothing to transform", async (t) => {
  toHTML({
    urls: [],
    // metadata: {},
    // pagesData: {},
    // destination: "destination",
    // routes: {},
    // store: {},
    // baseUrl: { path: "/" },
  })
  .then((files) => {
    t.is(files.length, 0)
  })
  .catch((error) => {
    t.fail(error)
  })
})

test("writeAllHTMLFiles", (t) => {
  t.plan(5)

  return writeAllHTMLFiles({
    // metadata: {},
    urls: [
      "test-url",
    ],
    pagesData: {},
    store: testStore,
    routes: testRoutes,
    destination: "destination",
    baseUrl: { path: "/" },
    ghPages: true,
    setPageData: (url, uri/* , pagesData, store */) => {
      t.is(url, "test-url")
      t.is(uri, "test-url")
    },
    writeHTMLFile: (basename, html) => {
      const expectedHTML = (
      `<!doctype html>

  ${ htmlMetas({ baseUrl: { path: "/" }, css: true }).join("\n  ") }
  <title data-react-helmet="true"></title>

TestContainer

`
      )
      t.is(basename, "destination/test-url")
      t.is(
        beautifyHTML(html),
        expectedHTML
      )
    },
    forgetPageData: (uri) => {
      t.is(uri, "test-url")
    },
  }, true)
  .catch((error) => {
    t.fail(error)
  })
})
<commit_msg>Fix a tested path for Windows compat<commit_after>import test from "ava"; import "babel-core/register"

import { join } from "path"
import beautifyHTML from "../../../__tests__/utils/beautifyHTML"
import htmlMetas from "../../../html-metas"

import toHTML, { writeAllHTMLFiles } from "../index"

import { testStore, testRoutes } from "./utils"

test("don't break if there is nothing to transform", async (t) => {
  toHTML({
    urls: [],
    // metadata: {},
    // pagesData: {},
    // destination: "destination",
    // routes: {},
    // store: {},
    // baseUrl: { path: "/" },
  })
  .then((files) => {
    t.is(files.length, 0)
  })
  .catch((error) => {
    t.fail(error)
  })
})

test("writeAllHTMLFiles", (t) => {
  t.plan(5)

  return writeAllHTMLFiles({
    // metadata: {},
    urls: [
      "test-url",
    ],
    pagesData: {},
    store: testStore,
    routes: testRoutes,
    destination: "destination",
    baseUrl: { path: "/" },
    ghPages: true,
    setPageData: (url, uri/* , pagesData, store */) => {
      t.is(url, "test-url")
      t.is(uri, "test-url")
    },
    writeHTMLFile: (basename, html) => {
      const expectedHTML = (
      `<!doctype html>

  ${ htmlMetas({ baseUrl: { path: "/" }, css: true }).join("\n  ") }
  <title data-react-helmet="true"></title>

TestContainer

`
      )
      t.is(basename, join("destination/test-url"))
      t.is(
        beautifyHTML(html),
        expectedHTML
      )
    },
    forgetPageData: (uri) => {
      t.is(uri, "test-url")
    },
  }, true)
  .catch((error) => {
    t.fail(error)
  })
})
<|endoftext|>


<commit_before>(function(Two) {

  /**
   * Constants
   */
  var cos = Math.cos, sin = Math.sin, tan = Math.tan;
  var _ = Two.Utils;

  /**
   * Two.Matrix contains an array of elements that represent
   * the two dimensional 3 x 3 matrix as illustrated below:
   *
   * =====
   * a b c
   * d e f
   * g h i  // this row is not really used in 2d transformations
   * =====
   *
   * String order is for transform strings: a, d, b, e, c, f
   *
   * @class
   */
  var Matrix = Two.Matrix = function(a, b, c, d, e, f) {

    this.elements = new Two.Array(9);

    var elements = a;
    if (!_.isArray(elements)) {
      elements = _.toArray(arguments);
    }

    // initialize the elements with default values.

    this.identity().set(elements);

  };

  _.extend(Matrix, {

    Identity: [
      1, 0, 0,
      0, 1, 0,
      0, 0, 1
    ],

    /**
     * Multiply two matrix 3x3 arrays
     */
    Multiply: function(A, B, C) {

      if (B.length <= 3) { // Multiply Vector

        var x, y, z, e = A;

        var a = B[0] || 0,
            b = B[1] || 0,
            c = B[2] || 0;

        // Go down rows first
        // a, d, g, b, e, h, c, f, i

        x = e[0] * a + e[1] * b + e[2] * c;
        y = e[3] * a + e[4] * b + e[5] * c;
        z = e[6] * a + e[7] * b + e[8] * c;

        return { x: x, y: y, z: z };

      }

      var A0 = A[0], A1 = A[1], A2 = A[2];
      var A3 = A[3], A4 = A[4], A5 = A[5];
      var A6 = A[6], A7 = A[7], A8 = A[8];

      var B0 = B[0], B1 = B[1], B2 = B[2];
      var B3 = B[3], B4 = B[4], B5 = B[5];
      var B6 = B[6], B7 = B[7], B8 = B[8];

      C = C || new Two.Array(9);

      C[0] = A0 * B0 + A1 * B3 + A2 * B6;
      C[1] = A0 * B1 + A1 * B4 + A2 * B7;
      C[2] = A0 * B2 + A1 * B5 + A2 * B8;
      C[3] = A3 * B0 + A4 * B3 + A5 * B6;
      C[4] = A3 * B1 + A4 * B4 + A5 * B7;
      C[5] = A3 * B2 + A4 * B5 + A5 * B8;
      C[6] = A6 * B0 + A7 * B3 + A8 * B6;
      C[7] = A6 * B1 + A7 * B4 + A8 * B7;
      C[8] = A6 * B2 + A7 * B5 + A8 * B8;

      return C;

    }

  });

  _.extend(Matrix.prototype, Two.Utils.Events, {

    /**
     * Takes an array of elements or the arguments list itself to
     * set and update the current matrix's elements. Only updates
     * specified values.
     */
    set: function(a) {

      var elements = a;
      if (!_.isArray(elements)) {
        elements = _.toArray(arguments);
      }

      _.extend(this.elements, elements);

      return this.trigger(Two.Events.change);

    },

    /**
     * Turn matrix to identity, like resetting.
     */
    identity: function() {

      this.set(Matrix.Identity);

      return this;

    },

    /**
     * Multiply scalar or multiply by another matrix.
     */
    multiply: function(a, b, c, d, e, f, g, h, i) {

      var elements = arguments, l = elements.length;

      // Multiply scalar

      if (l <= 1) {

        _.each(this.elements, function(v, i) {
          this.elements[i] = v * a;
        }, this);

        return this.trigger(Two.Events.change);

      }

      if (l <= 3) { // Multiply Vector

        var x, y, z;
        a = a || 0;
        b = b || 0;
        c = c || 0;
        e = this.elements;

        // Go down rows first
        // a, d, g, b, e, h, c, f, i

        x = e[0] * a + e[1] * b + e[2] * c;
        y = e[3] * a + e[4] * b + e[5] * c;
        z = e[6] * a + e[7] * b + e[8] * c;

        return { x: x, y: y, z: z };

      }

      // Multiple matrix

      var A = this.elements;
      var B = elements;

      var A0 = A[0], A1 = A[1], A2 = A[2];
      var A3 = A[3], A4 = A[4], A5 = A[5];
      var A6 = A[6], A7 = A[7], A8 = A[8];

      var B0 = B[0], B1 = B[1], B2 = B[2];
      var B3 = B[3], B4 = B[4], B5 = B[5];
      var B6 = B[6], B7 = B[7], B8 = B[8];

      this.elements[0] = A0 * B0 + A1 * B3 + A2 * B6;
      this.elements[1] = A0 * B1 + A1 * B4 + A2 * B7;
      this.elements[2] = A0 * B2 + A1 * B5 + A2 * B8;

      this.elements[3] = A3 * B0 + A4 * B3 + A5 * B6;
      this.elements[4] = A3 * B1 + A4 * B4 + A5 * B7;
      this.elements[5] = A3 * B2 + A4 * B5 + A5 * B8;

      this.elements[6] = A6 * B0 + A7 * B3 + A8 * B6;
      this.elements[7] = A6 * B1 + A7 * B4 + A8 * B7;
      this.elements[8] = A6 * B2 + A7 * B5 + A8 * B8;

      return this.trigger(Two.Events.change);

    },

    inverse: function(out) {

      var a = this.elements;
      out = out || new Two.Matrix();

      var a00 = a[0], a01 = a[1], a02 = a[2];
      var a10 = a[3], a11 = a[4], a12 = a[5];
      var a20 = a[6], a21 = a[7], a22 = a[8];

      var b01 = a22 * a11 - a12 * a21;
      var b11 = -a22 * a10 + a12 * a20;
      var b21 = a21 * a10 - a11 * a20;

      // Calculate the determinant
      var det = a00 * b01 + a01 * b11 + a02 * b21;

      if (!det) {
        return null;
      }

      det = 1.0 / det;

      out.elements[0] = b01 * det;
      out.elements[1] = (-a22 * a01 + a02 * a21) * det;
      out.elements[2] = (a12 * a01 - a02 * a11) * det;
      out.elements[3] = b11 * det;
      out.elements[4] = (a22 * a00 - a02 * a20) * det;
      out.elements[5] = (-a12 * a00 + a02 * a10) * det;
      out.elements[6] = b21 * det;
      out.elements[7] = (-a21 * a00 + a01 * a20) * det;
      out.elements[8] = (a11 * a00 - a01 * a10) * det;

      return out;

    },

    /**
     * Set a scalar onto the matrix.
     */
    scale: function(sx, sy) {

      var l = arguments.length;
      if (l <= 1) {
        sy = sx;
      }

      return this.multiply(sx, 0, 0, 0, sy, 0, 0, 0, 1);

    },

    /**
     * Rotate the matrix.
     */
    rotate: function(radians) {

      var c = cos(radians);
      var s = sin(radians);

      return this.multiply(c, -s, 0, s, c, 0, 0, 0, 1);

    },

    /**
     * Translate the matrix.
     */
    translate: function(x, y) {

      return this.multiply(1, 0, x, 0, 1, y, 0, 0, 1);

    },

    /*
     * Skew the matrix by an angle in the x axis direction.
     */
    skewX: function(radians) {

      var a = tan(radians);

      return this.multiply(1, a, 0, 0, 1, 0, 0, 0, 1);

    },

    /*
     * Skew the matrix by an angle in the y axis direction.
     */
    skewY: function(radians) {

      var a = tan(radians);

      return this.multiply(1, 0, 0, a, 1, 0, 0, 0, 1);

    },

    /**
     * Create a transform string to be used with rendering apis.
     */
    toString: function(fullMatrix) {
      var temp = [];

      this.toArray(fullMatrix, temp);

      return temp.join(' ');

    },

    /**
     * Create a transform array to be used with rendering apis.
     */
    toArray: function(fullMatrix, output) {

     var elements = this.elements;
     var hasOutput = !!output;

     var a = parseFloat(elements[0].toFixed(3));
     var b = parseFloat(elements[1].toFixed(3));
     var c = parseFloat(elements[2].toFixed(3));
     var d = parseFloat(elements[3].toFixed(3));
     var e = parseFloat(elements[4].toFixed(3));
     var f = parseFloat(elements[5].toFixed(3));

      if (!!fullMatrix) {

        var g = parseFloat(elements[6].toFixed(3));
        var h = parseFloat(elements[7].toFixed(3));
        var i = parseFloat(elements[8].toFixed(3));

        if (hasOutput) {
          output[0] = a;
          output[1] = d;
          output[2] = g;
          output[3] = b;
          output[4] = e;
          output[5] = h;
          output[6] = c;
          output[7] = f;
          output[8] = i;
          return;
        }

        return [
          a, d, g, b, e, h, c, f, i
        ];
      }

      if (hasOutput) {
        output[0] = a;
        output[1] = d;
        output[2] = b;
        output[3] = e;
        output[4] = c;
        output[5] = f;
        return;
      }

      return [
        a, d, b, e, c, f  // Specific format see LN:19
      ];

    },

    /**
     * Clone the current matrix.
     */
    clone: function() {
      var a, b, c, d, e, f, g, h, i;

      a = this.elements[0];
      b = this.elements[1];
      c = this.elements[2];
      d = this.elements[3];
      e = this.elements[4];
      f = this.elements[5];
      g = this.elements[6];
      h = this.elements[7];
      i = this.elements[8];

      return new Two.Matrix(a, b, c, d, e, f, g, h, i);

    }

  });

})((typeof global !== 'undefined' ? global : (this || window)).Two);
<commit_msg>Issue 135 improved Matrix performance<commit_after>(function(Two) {

  /**
   * Constants
   */
  var cos = Math.cos, sin = Math.sin, tan = Math.tan;
  var _ = Two.Utils;

  /**
   * Two.Matrix contains an array of elements that represent
   * the two dimensional 3 x 3 matrix as illustrated below:
   *
   * =====
   * a b c
   * d e f
   * g h i  // this row is not really used in 2d transformations
   * =====
   *
   * String order is for transform strings: a, d, b, e, c, f
   *
   * @class
   */
  var Matrix = Two.Matrix = function(a, b, c, d, e, f) {

    this.elements = new Two.Array(9);

    var elements = a;
    if (!_.isArray(elements)) {
      elements = _.toArray(arguments);
    }

    // initialize the elements with default values.

    this.identity().set(elements);

  };

  _.extend(Matrix, {

    Identity: [
      1, 0, 0,
      0, 1, 0,
      0, 0, 1
    ],

    /**
     * Multiply two matrix 3x3 arrays
     */
    Multiply: function(A, B, C) {

      if (B.length <= 3) { // Multiply Vector

        var x, y, z, e = A;

        var a = B[0] || 0,
            b = B[1] || 0,
            c = B[2] || 0;

        // Go down rows first
        // a, d, g, b, e, h, c, f, i

        x = e[0] * a + e[1] * b + e[2] * c;
        y = e[3] * a + e[4] * b + e[5] * c;
        z = e[6] * a + e[7] * b + e[8] * c;

        return { x: x, y: y, z: z };

      }

      var A0 = A[0], A1 = A[1], A2 = A[2];
      var A3 = A[3], A4 = A[4], A5 = A[5];
      var A6 = A[6], A7 = A[7], A8 = A[8];

      var B0 = B[0], B1 = B[1], B2 = B[2];
      var B3 = B[3], B4 = B[4], B5 = B[5];
      var B6 = B[6], B7 = B[7], B8 = B[8];

      C = C || new Two.Array(9);

      C[0] = A0 * B0 + A1 * B3 + A2 * B6;
      C[1] = A0 * B1 + A1 * B4 + A2 * B7;
      C[2] = A0 * B2 + A1 * B5 + A2 * B8;
      C[3] = A3 * B0 + A4 * B3 + A5 * B6;
      C[4] = A3 * B1 + A4 * B4 + A5 * B7;
      C[5] = A3 * B2 + A4 * B5 + A5 * B8;
      C[6] = A6 * B0 + A7 * B3 + A8 * B6;
      C[7] = A6 * B1 + A7 * B4 + A8 * B7;
      C[8] = A6 * B2 + A7 * B5 + A8 * B8;

      return C;

    }

  });

  _.extend(Matrix.prototype, Two.Utils.Events, {

    /**
     * Takes an array of elements or the arguments list itself to
     * set and update the current matrix's elements. Only updates
     * specified values.
     */
    set: function(a) {

      var elements = a;
      if (!_.isArray(elements)) {
        elements = _.toArray(arguments);
      }

      this.elements[0] = elements[0];
      this.elements[1] = elements[1];
      this.elements[2] = elements[2];
      this.elements[3] = elements[3];
      this.elements[4] = elements[4];
      this.elements[5] = elements[5];
      this.elements[6] = elements[6];
      this.elements[7] = elements[7];
      this.elements[8] = elements[8];

      return this.trigger(Two.Events.change);

    },

    /**
     * Turn matrix to identity, like resetting.
     */
    identity: function() {

      this.elements[0] = Matrix.Identity[0];
      this.elements[1] = Matrix.Identity[1];
      this.elements[2] = Matrix.Identity[2];
      this.elements[3] = Matrix.Identity[3];
      this.elements[4] = Matrix.Identity[4];
      this.elements[5] = Matrix.Identity[5];
      this.elements[6] = Matrix.Identity[6];
      this.elements[7] = Matrix.Identity[7];
      this.elements[8] = Matrix.Identity[8];

      return this.trigger(Two.Events.change);

    },

    /**
     * Multiply scalar or multiply by another matrix.
     */
    multiply: function(a, b, c, d, e, f, g, h, i) {

      var elements = arguments, l = elements.length;

      // Multiply scalar

      if (l <= 1) {

        _.each(this.elements, function(v, i) {
          this.elements[i] = v * a;
        }, this);

        return this.trigger(Two.Events.change);

      }

      if (l <= 3) { // Multiply Vector

        var x, y, z;
        a = a || 0;
        b = b || 0;
        c = c || 0;
        e = this.elements;

        // Go down rows first
        // a, d, g, b, e, h, c, f, i

        x = e[0] * a + e[1] * b + e[2] * c;
        y = e[3] * a + e[4] * b + e[5] * c;
        z = e[6] * a + e[7] * b + e[8] * c;

        return { x: x, y: y, z: z };

      }

      // Multiple matrix

      var A = this.elements;
      var B = elements;

      var A0 = A[0], A1 = A[1], A2 = A[2];
      var A3 = A[3], A4 = A[4], A5 = A[5];
      var A6 = A[6], A7 = A[7], A8 = A[8];

      var B0 = B[0], B1 = B[1], B2 = B[2];
      var B3 = B[3], B4 = B[4], B5 = B[5];
      var B6 = B[6], B7 = B[7], B8 = B[8];

      this.elements[0] = A0 * B0 + A1 * B3 + A2 * B6;
      this.elements[1] = A0 * B1 + A1 * B4 + A2 * B7;
      this.elements[2] = A0 * B2 + A1 * B5 + A2 * B8;

      this.elements[3] = A3 * B0 + A4 * B3 + A5 * B6;
      this.elements[4] = A3 * B1 + A4 * B4 + A5 * B7;
      this.elements[5] = A3 * B2 + A4 * B5 + A5 * B8;

      this.elements[6] = A6 * B0 + A7 * B3 + A8 * B6;
      this.elements[7] = A6 * B1 + A7 * B4 + A8 * B7;
      this.elements[8] = A6 * B2 + A7 * B5 + A8 * B8;

      return this.trigger(Two.Events.change);

    },

    inverse: function(out) {

      var a = this.elements;
      out = out || new Two.Matrix();

      var a00 = a[0], a01 = a[1], a02 = a[2];
      var a10 = a[3], a11 = a[4], a12 = a[5];
      var a20 = a[6], a21 = a[7], a22 = a[8];

      var b01 = a22 * a11 - a12 * a21;
      var b11 = -a22 * a10 + a12 * a20;
      var b21 = a21 * a10 - a11 * a20;

      // Calculate the determinant
      var det = a00 * b01 + a01 * b11 + a02 * b21;

      if (!det) {
        return null;
      }

      det = 1.0 / det;

      out.elements[0] = b01 * det;
      out.elements[1] = (-a22 * a01 + a02 * a21) * det;
      out.elements[2] = (a12 * a01 - a02 * a11) * det;
      out.elements[3] = b11 * det;
      out.elements[4] = (a22 * a00 - a02 * a20) * det;
      out.elements[5] = (-a12 * a00 + a02 * a10) * det;
      out.elements[6] = b21 * det;
      out.elements[7] = (-a21 * a00 + a01 * a20) * det;
      out.elements[8] = (a11 * a00 - a01 * a10) * det;

      return out;

    },

    /**
     * Set a scalar onto the matrix.
     */
    scale: function(sx, sy) {

      var l = arguments.length;
      if (l <= 1) {
        sy = sx;
      }

      return this.multiply(sx, 0, 0, 0, sy, 0, 0, 0, 1);

    },

    /**
     * Rotate the matrix.
     */
    rotate: function(radians) {

      var c = cos(radians);
      var s = sin(radians);

      return this.multiply(c, -s, 0, s, c, 0, 0, 0, 1);

    },

    /**
     * Translate the matrix.
     */
    translate: function(x, y) {

      return this.multiply(1, 0, x, 0, 1, y, 0, 0, 1);

    },

    /*
     * Skew the matrix by an angle in the x axis direction.
     */
    skewX: function(radians) {

      var a = tan(radians);

      return this.multiply(1, a, 0, 0, 1, 0, 0, 0, 1);

    },

    /*
     * Skew the matrix by an angle in the y axis direction.
     */
    skewY: function(radians) {

      var a = tan(radians);

      return this.multiply(1, 0, 0, a, 1, 0, 0, 0, 1);

    },

    /**
     * Create a transform string to be used with rendering apis.
     */
    toString: function(fullMatrix) {
      var temp = [];

      this.toArray(fullMatrix, temp);

      return temp.join(' ');

    },

    /**
     * Create a transform array to be used with rendering apis.
     */
    toArray: function(fullMatrix, output) {

     var elements = this.elements;
     var hasOutput = !!output;
     var fix = _.toFixed;

     var a = fix(elements[0]);
     var b = fix(elements[1]);
     var c = fix(elements[2]);
     var d = fix(elements[3]);
     var e = fix(elements[4]);
     var f = fix(elements[5]);

      if (!!fullMatrix) {

        var g = fix(elements[6]);
        var h = fix(elements[7]);
        var i = fix(elements[8]);

        if (hasOutput) {
          output[0] = a;
          output[1] = d;
          output[2] = g;
          output[3] = b;
          output[4] = e;
          output[5] = h;
          output[6] = c;
          output[7] = f;
          output[8] = i;
          return;
        }

        return [
          a, d, g, b, e, h, c, f, i
        ];
      }

      if (hasOutput) {
        output[0] = a;
        output[1] = d;
        output[2] = b;
        output[3] = e;
        output[4] = c;
        output[5] = f;
        return;
      }

      return [
        a, d, b, e, c, f  // Specific format see LN:19
      ];

    },

    /**
     * Clone the current matrix.
     */
    clone: function() {
      var a, b, c, d, e, f, g, h, i;

      a = this.elements[0];
      b = this.elements[1];
      c = this.elements[2];
      d = this.elements[3];
      e = this.elements[4];
      f = this.elements[5];
      g = this.elements[6];
      h = this.elements[7];
      i = this.elements[8];

      return new Two.Matrix(a, b, c, d, e, f, g, h, i);

    }

  });

})((typeof global !== 'undefined' ? global : (this || window)).Two);
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2007-2015 Ariel Flesler - afleslergmail<d>com | http://flesler.blogspot.com
 * Licensed under MIT
 * @author Ariel Flesler
 * @version 2.1.1
 */
;(function(f){"use strict";"function"===typeof define&&define.amd?define(["jquery"],f):"undefined"!==typeof module&&module.exports?module.exports=f(require("jquery")):f(jQuery)})(function($){"use strict";function n(a){return!a.nodeName||-1!==$.inArray(a.nodeName.toLowerCase(),["iframe","#document","html","body"])}function h(a){return $.isFunction(a)||$.isPlainObject(a)?a:{top:a,left:a}}var p=$.scrollTo=function(a,d,b){return $(window).scrollTo(a,d,b)};p.defaults={axis:"xy",duration:0,limit:!0};$.fn.scrollTo=function(a,d,b){"object"=== typeof d&&(b=d,d=0);"function"===typeof b&&(b={onAfter:b});"max"===a&&(a=9E9);b=$.extend({},p.defaults,b);d=d||b.duration;var u=b.queue&&1<b.axis.length;u&&(d/=2);b.offset=h(b.offset);b.over=h(b.over);return this.each(function(){function k(a){var k=$.extend({},b,{queue:!0,duration:d,complete:a&&function(){a.call(q,e,b)}});r.animate(f,k)}if(null!==a){var l=n(this),q=l?this.contentWindow||window:this,r=$(q),e=a,f={},t;switch(typeof e){case "number":case "string":if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(e)){e= h(e);break}e=l?$(e):$(e,q);if(!e.length)return;case "object":if(e.is||e.style)t=(e=$(e)).offset()}var v=$.isFunction(b.offset)&&b.offset(q,e)||b.offset;$.each(b.axis.split(""),function(a,c){var d="x"===c?"Left":"Top",m=d.toLowerCase(),g="scroll"+d,h=r[g](),n=p.max(q,c);t?(f[g]=t[m]+(l?0:h-r.offset()[m]),b.margin&&(f[g]-=parseInt(e.css("margin"+d),10)||0,f[g]-=parseInt(e.css("border"+d+"Width"),10)||0),f[g]+=v[m]||0,b.over[m]&&(f[g]+=e["x"===c?"width":"height"]()*b.over[m])):(d=e[m],f[g]=d.slice&& "%"===d.slice(-1)?parseFloat(d)/100*n:d);b.limit&&/^\d+$/.test(f[g])&&(f[g]=0>=f[g]?0:Math.min(f[g],n));!a&&1<b.axis.length&&(h===f[g]?f={}:u&&(k(b.onAfterFirst),f={}))});k(b.onAfter)}})};p.max=function(a,d){var b="x"===d?"Width":"Height",h="scroll"+b;if(!n(a))return a[h]-$(a)[b.toLowerCase()]();var b="client"+b,k=a.ownerDocument||a.document,l=k.documentElement,k=k.body;return Math.max(l[h],k[h])-Math.min(l[b],k[b])};$.Tween.propHooks.scrollLeft=$.Tween.propHooks.scrollTop={get:function(a){return $(a.elem)[a.prop]()}, set:function(a){var d=this.get(a);if(a.options.interrupt&&a._last&&a._last!==d)return $(a.elem).stop();var b=Math.round(a.now);d!==b&&($(a.elem)[a.prop](b),a._last=this.get(a))}};return p});<commit_msg>Use jQuery.scrollTo 2.1.2<commit_after>/**
 * Copyright (c) 2007-2015 Ariel Flesler - afleslergmail<d>com | http://flesler.blogspot.com
 * Licensed under MIT
 * @author Ariel Flesler
 * @version 2.1.2
 */
;(function(f){"use strict";"function"===typeof define&&define.amd?define(["jquery"],f):"undefined"!==typeof module&&module.exports?module.exports=f(require("jquery")):f(jQuery)})(function($){"use strict";function n(a){return!a.nodeName||-1!==$.inArray(a.nodeName.toLowerCase(),["iframe","#document","html","body"])}function h(a){return $.isFunction(a)||$.isPlainObject(a)?a:{top:a,left:a}}var p=$.scrollTo=function(a,d,b){return $(window).scrollTo(a,d,b)};p.defaults={axis:"xy",duration:0,limit:!0};$.fn.scrollTo=function(a,d,b){"object"=== typeof d&&(b=d,d=0);"function"===typeof b&&(b={onAfter:b});"max"===a&&(a=9E9);b=$.extend({},p.defaults,b);d=d||b.duration;var u=b.queue&&1<b.axis.length;u&&(d/=2);b.offset=h(b.offset);b.over=h(b.over);return this.each(function(){function k(a){var k=$.extend({},b,{queue:!0,duration:d,complete:a&&function(){a.call(q,e,b)}});r.animate(f,k)}if(null!==a){var l=n(this),q=l?this.contentWindow||window:this,r=$(q),e=a,f={},t;switch(typeof e){case "number":case "string":if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(e)){e= h(e);break}e=l?$(e):$(e,q);case "object":if(e.length===0)return;if(e.is||e.style)t=(e=$(e)).offset()}var v=$.isFunction(b.offset)&&b.offset(q,e)||b.offset;$.each(b.axis.split(""),function(a,c){var d="x"===c?"Left":"Top",m=d.toLowerCase(),g="scroll"+d,h=r[g](),n=p.max(q,c);t?(f[g]=t[m]+(l?0:h-r.offset()[m]),b.margin&&(f[g]-=parseInt(e.css("margin"+d),10)||0,f[g]-=parseInt(e.css("border"+d+"Width"),10)||0),f[g]+=v[m]||0,b.over[m]&&(f[g]+=e["x"===c?"width":"height"]()*b.over[m])):(d=e[m],f[g]=d.slice&& "%"===d.slice(-1)?parseFloat(d)/100*n:d);b.limit&&/^\d+$/.test(f[g])&&(f[g]=0>=f[g]?0:Math.min(f[g],n));!a&&1<b.axis.length&&(h===f[g]?f={}:u&&(k(b.onAfterFirst),f={}))});k(b.onAfter)}})};p.max=function(a,d){var b="x"===d?"Width":"Height",h="scroll"+b;if(!n(a))return a[h]-$(a)[b.toLowerCase()]();var b="client"+b,k=a.ownerDocument||a.document,l=k.documentElement,k=k.body;return Math.max(l[h],k[h])-Math.min(l[b],k[b])};$.Tween.propHooks.scrollLeft=$.Tween.propHooks.scrollTop={get:function(a){return $(a.elem)[a.prop]()}, set:function(a){var d=this.get(a);if(a.options.interrupt&&a._last&&a._last!==d)return $(a.elem).stop();var b=Math.round(a.now);d!==b&&($(a.elem)[a.prop](b),a._last=this.get(a))}};return p});<|endoftext|>


<commit_before><commit_msg>fix the wrong spelling of word author<commit_after><|endoftext|>


<commit_before>/*
MagJS v0.22.9
http://github.com/magnumjs/mag.js
(c) Michael Glazer
License: MIT
*/
(function(mag, document) {

  'use strict';

  var modules = [],
    controllers = []

  var mod = {
    cache: []
  }

  mod.getState = function(index) {
    return modules[index][1]
  }
  mod.setState = function(index, state) {
    modules[index][1] = state
  }
  mod.getView = function(index) {
    return modules[index][0]
  }
  mod.getProps = function(index) {
    return modules[index][2]
  }
  mod.setProps = function(index, props) {
    return modules[index][2] = props
  }
  mod.remove = function(index) {
    modules.splice(index, 1)
  }
  mod.getId = function(index) {
    return modules[index] && modules[index][3]
  }
  mod.exists = function(index) {
    return typeof modules[index] != 'undefined' ? true : false
  }
  mod.setFrameId = function(index, fid) {
    modules[index][4] = fid;
  }
  mod.getFrameId = function(index) {
    return modules[index][4];
  }
  mod.submodule = function(id, index, module, props) {
    if (modules[index]) {
      // new call to existing
      // update props
      mod.setProps(index, props)
        // reinitialize the controller ?
      return modules[index]
    }
    modules[index] = [0, 0, 0, 0, 0]
    mod.setProps(index, props)
    var controller = function(context) {
        return (module.controller || function() {}).call(context, mod.getProps(index)) || context
      },
      view = function(index, state, ele) {
        module.view.call(module, state, mod.getProps(index), ele)
      }.bind({}, index),
      output = {
        controller: controller,
        view: view
      }
    modules[index][0] = output.view;
    modules[index][3] = id;
    modules[index][1] = getController(output.controller, index, id);

    // register the module
    return modules[index]
  }

  var timers = [];
  var prevs = [];

  function findMissing(change, element) {
    var prop = change.name;
    if (typeof change.object[change.name] == 'undefined') {
      // prop might be hierarchical?
      // getparent Object property chain?
      // get value of property from DOM
      var a = mag.fill.find(element, prop),
        greedy = prop[0] === '$',
        v, // can be an array, object or string
        // for each
        tmp = [];

      a.reverse().forEach(function(item, index) {
        if (a[index]) {
          if (a[index].value && a[index].value.length > 0) {
            v = a[index].value
            if (a[index].type && (a[index].type == 'checkbox' || a[index].type == 'radio')) {
              v = {
                _value: v,
                _checked: a[index].checked
              }
              tmp.push(v)
            }
          } else if (a[index].innerText && a[index].innerText.length > 0) {
            v = a[index].innerText
          } else if (a[0].innerHTML && a[index].innerHTML.length > 0) {
            v = a[index].innerHTML
          }
        }
      })
      if (tmp.length > 0 && greedy) return tmp
      return v
    }
  }

  function getController(ctrl, index, id) {
    var controller;
    if (typeof Proxy !== 'undefined') {

      var handler = function(type, index, change) {

        var current = JSON.stringify(change.object);
        var sname = String(change.name);
        if (current === prevs[index+sname]) {
          return;
        }
        prevs[index+sname]  =current;

        if (change.type == 'get' && type != 'props' && !~mag.fill.ignorekeys.indexOf(change.name.toString()) && typeof change.oldValue == 'undefined' && Object.keys(change.object).length === 0) {
          var res = findMissing(change, document.getElementById(mod.getId(index)));
              if(typeof res != 'undefined'){
                  cached[index] = 0;
                  return res;
              }
        } else
        if (change.type == 'set' && change.oldValue && typeof change.oldValue.draw == 'function' && change.object[change.name] && !change.object[change.name].draw) {

          // call unloader for module
          var id = change.oldValue.getId()
          mag.utils.callLCEvent('onunload', mag.mod.getState(id), mag.getNode(mag.mod.getId(id)), id);
          mag.clear(id);
          // remove clones
          change.oldValue.clones().length = 0;
        }

        // call setup handler
        var fun = mod.getFrameId(index);
        if (typeof fun == 'function' && change.type == 'set') {
          //debounce
          cancelAnimationFrame(timers[index]);
          timers[index] = requestAnimationFrame(fun);
        }

      };

      var base = mod.getProps(index);
      var baseP = mag.proxy(base, handler.bind({}, 'props', index));
      mod.setProps(index, baseP);

      var p = mag.proxy({}, handler.bind({}, 'state', index));

      controller = new ctrl(p);
    } else {
      controller = new ctrl({})
    }

    return controller;
  }

  mod.iscached = function(key, data) {
    if (mod.cache[key] && mod.cache[key] === JSON.stringify(data)) {
      return true
    }
    mod.cache[key] = JSON.stringify(data);
  }

  mod.clear = function(key) {
    if (key > -1 && mod.cache[key]) {
      mod.cache.splice(key, 1)
    }
  }

  var cached = []
  mod.callView = function(node, index) {

    var module = mod.getView(index)

    if (!cached[index]) {
      mag.props.attachToArgs(index, mod.getState(index), node)
      cached[index] = 1
    }
    module(mod.getState(index), node)
  }

  mag.mod = mod;

}(window.mag || {}, document));
<commit_msg>Update module.js<commit_after>/*
MagJS v0.22.10
http://github.com/magnumjs/mag.js
(c) Michael Glazer
License: MIT
*/
(function(mag, document) {

  'use strict';

  var modules = [],
    controllers = []

  var mod = {
    cache: []
  }

  mod.getState = function(index) {
    return modules[index][1]
  }
  mod.setState = function(index, state) {
    modules[index][1] = state
  }
  mod.getView = function(index) {
    return modules[index][0]
  }
  mod.getProps = function(index) {
    return modules[index][2]
  }
  mod.setProps = function(index, props) {
    return modules[index][2] = props
  }
  mod.remove = function(index) {
    modules.splice(index, 1)
  }
  mod.getId = function(index) {
    return modules[index] && modules[index][3]
  }
  mod.exists = function(index) {
    return typeof modules[index] != 'undefined' ? true : false
  }
  mod.setFrameId = function(index, fid) {
    modules[index][4] = fid;
  }
  mod.getFrameId = function(index) {
    return modules[index][4];
  }
  mod.submodule = function(id, index, module, props) {
    if (modules[index]) {
      // new call to existing
      // update props
      mod.setProps(index, props)
        // reinitialize the controller ?
      return modules[index]
    }
    modules[index] = [0, 0, 0, 0, 0]
    mod.setProps(index, props)
    var controller = function(context) {
        return (module.controller || function() {}).call(context, mod.getProps(index)) || context
      },
      view = function(index, state, ele) {
        module.view.call(module, state, mod.getProps(index), ele)
      }.bind({}, index),
      output = {
        controller: controller,
        view: view
      }
    modules[index][0] = output.view;
    modules[index][3] = id;
    modules[index][1] = getController(output.controller, index, id);

    // register the module
    return modules[index]
  }

  var timers = [];
  var prevs = [];

  function findMissing(change, element) {
    var prop = change.name;
    if (typeof change.object[change.name] == 'undefined') {
      // prop might be hierarchical?
      // getparent Object property chain?

      // get value of property from DOM
      var a = mag.fill.find(element, prop),
        greedy = prop[0] === '$',
        v, // can be an array, object or string
        // for each
        tmp = [];

      a.reverse().forEach(function(item, index) {
        if (item) {
          if (item.value && item.value.length > 0) {
            v = item.value
            if (item.type && (item.type == 'checkbox' || item.type == 'radio')) {
              v = {
                _value: v
              };
              if(item.checked) v._checked = true
              tmp.push(v)
            }
          } else if (item.innerText && item.innerText.length > 0) {
            v = item.innerText
          } else if (item.innerHTML && item.innerHTML.length > 0) {
            v = item.innerHTML
          } else if(!item.value && item.tagName == 'INPUT'){
            v =''
          }
        }
      })
      if (tmp.length > 0 && greedy) return tmp
      return v
    }
  }

  function getController(ctrl, index, id) {
    var controller;
    if (typeof Proxy !== 'undefined') {

      var handler = function(type, index, change) {

        var current = JSON.stringify(change.object);
        var sname = String(change.name);
        if (current === prevs[index+sname]) {
          return;
        }
        prevs[index+sname]  =current;

        if (change.type == 'get' && type != 'props' && !~mag.fill.ignorekeys.indexOf(change.name.toString()) && typeof change.oldValue == 'undefined' && Object.keys(change.object).length === 0) {
          var res = findMissing(change, document.getElementById(mod.getId(index)));
              if(typeof res != 'undefined'){
                  cached[index] = 0;
                  return res;
              }
        } else
        if (change.type == 'set' && change.oldValue && typeof change.oldValue.draw == 'function' && change.object[change.name] && !change.object[change.name].draw) {

          // call unloader for module
          var id = change.oldValue.getId()
          mag.utils.callLCEvent('onunload', mag.mod.getState(id), mag.getNode(mag.mod.getId(id)), id);
          mag.clear(id);
          // remove clones
          change.oldValue.clones().length = 0;
        }

        // call setup handler
        var fun = mod.getFrameId(index);
        if (typeof fun == 'function' && change.type == 'set') {
          //debounce
          cancelAnimationFrame(timers[index]);
          timers[index] = requestAnimationFrame(fun);
        }

      };

      var base = mod.getProps(index);
      var baseP = mag.proxy(base, handler.bind({}, 'props', index));
      mod.setProps(index, baseP);

      var p = mag.proxy({}, handler.bind({}, 'state', index));

      controller = new ctrl(p);
    } else {
      controller = new ctrl({})
    }

    return controller;
  }

  mod.iscached = function(key, data) {
    if (mod.cache[key] && mod.cache[key] === JSON.stringify(data)) {
      return true
    }
    mod.cache[key] = JSON.stringify(data);
  }

  mod.clear = function(key) {
    if (key > -1 && mod.cache[key]) {
      mod.cache.splice(key, 1)
    }
  }

  var cached = []
  mod.callView = function(node, index) {

    var module = mod.getView(index)

    if (!cached[index]) {
      mag.props.attachToArgs(index, mod.getState(index), node)
      cached[index] = 1
    }
    module(mod.getState(index), node)
  }

  mag.mod = mod;

}(window.mag || {}, document));
<|endoftext|>