<commit_before>/**
 * @fileOverview The Mongoose CRUD implementation.
 */
var __ = require('lodash');
var mschema = require('mschema');
var Promise = require('bluebird');

var AdaptorBase = require('./base.adp');

function noop() {}

/**
 * The Mongoose CRUD implementation.
 *
 * @param {?Object} optUdo Optionally define the current handling user.
 * @param {mongoose.Model} Model the model that this entity relates to.
 * @constructor
 * @extends {MongooseAdapter.AdaptorBase}
 */
var MongooseAdapter = module.exports = AdaptorBase.extend(function(/* optUdo */) {

  // Mongoose uses dot notation for paths
  this._schemaOpts.expandPaths = true;

  // stub internal methods, all should be private to instance
  this._mongRemove = noop;
});

/**
 * Set the Mongoose Model.
 *
 * @param {mongoose.Model} Model The mongoose model.
 */
MongooseAdapter.prototype.setModel = function(Model) {
  // perform some heuristics on Model identity cause instanceof will not work
  if (
    !Model ||
    Model.name !== 'model' ||
    !Model.db ||
    !Model.model ||
    !Model.schema
  ) {
    throw new TypeError('Model provided not a Mongoose.Model instance');
  }
  this.Model = Model;

  this._defineMethods();
  this._readSchema();
};

MongooseAdapter.prototype._defineMethods = function() {
  this._mongRemove = Promise.promisify(this.Model.remove, this.Model);
};

/**
 * Create an entity item.
 *
 * @param {Object} itemData The data to use for creating.
 * @return {Promise(mongoose.Document)} A promise with the mongoose doc.
 * @override
 */
MongooseAdapter.prototype._create = function(itemData) {
  return new Promise(function(resolve, reject) {
    var item = new this.Model(itemData);
    item.save(function(err, document) {
      if (err) { return reject(err); }
      resolve(document);
    });
  }.bind(this));
};

/**
 * Read one entity item.
 *
 * @param {string|Object} id the item id or an Object to query against.
 * @return {Promise(mongoose.Document)} A promise with the mongoose doc.
 * @override
 */
MongooseAdapter.prototype._readOne = function(id) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }

  var self = this;
  return new Promise(function(resolve, reject) {
    var query;
    if (__.isObject(id)) {
      query = self.Model.findOne(id);
    } else {
      query = self.Model.findById(id);
    }

    query = self._checkEagerLoad(query);

    // intercept "Cast to ID" error types and return null instead
    return query.exec(function(err, res) {
      if (err) {
        if (err.name === 'CastError' && err.type === 'ObjectId') {
          resolve(null);
        } else {
          reject(err);
        }
        return;
      }
      resolve(res);
    });
  });
};

/**
 * Read items based on query or if not defined, read all items.
 * Do practice common sense!
 *
 * @param {Object=} optQuery Limit the results.
 * @return {Promise(mongoose.Document)} A promise with the mongoose doc.
 * @override
 */
MongooseAdapter.prototype._read = function(optQuery) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }

  var self = this;
  return new Promise(function(resolve, reject) {
    var query = optQuery || {};
    self.parseQuery(query)
      .exec(function(err, result) {
        if (err) {
          reject(err);
          return;
        }
        resolve(result);
      });
  });
};

/**
 * Read a limited set of items.
 *
 * @param {?Object} query Narrow down the set, set to null for all.
 * @param {number} skip starting position.
 * @param {number} limit how many records to fetch.
 * @return {Promise(mongoose.Document)} A promise with the mongoose doc.
 * @override
 */
MongooseAdapter.prototype._readLimit = function(query, skip, limit) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }

  var self = this;
  return new Promise(function(resolve, reject) {
    self.parseQuery(query, self.Model.find)
      .skip(skip)
      .limit(limit)
      .exec(function(err, result) {
        // there's no escaping that
        if (err) {
          return reject(err);
        }
        resolve(result);
      });
  });
};

/**
 * Get the count of items.
 *
 * @param {?Object} query Narrow down the set, null for all.
 * @return {Promise(number)} A promise with the result.
 * @override
 */
MongooseAdapter.prototype._count = function(query) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }
  return new Promise(function(resolve, reject) {
    this.Model.count(query, function(err, num) {
      if (err) {
        reject(err);
      } else {
        resolve(num);
      }
    });
  }.bind(this));
};

/**
 * Update an entity item.
 *
 * @param {string|Object} id the item id or query for item.
 * @param {Object} itemData The data to use for creating.
 * @return {Promise(mongoose.Document)} A promise with the mongoose doc.
 * @override
 */
MongooseAdapter.prototype._update = function(id, itemData) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }
  return new Promise(function(resolve, reject) {
    this.readOne(id).then(function(doc) {
      if (!__.isObject(doc)) {
        return reject(new Error('record not found'));
      }
      __.forOwn(itemData, function(value, key) {
        doc[key] = value;
      }, this);

      doc.save(function(err, document) {
        if (err) { return reject(err); }
        resolve(document);
      });

    }.bind(this), reject);
  }.bind(this));
};

/**
 * Remove an entity item.
 *
 * @param {string|Object} id the item id or query for item.
 * @return {Promise(Object=)} A promise.
 * @protected
 */
MongooseAdapter.prototype._delete = function(id) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }

  var query = this._getQuery(id);
  return this._mongRemove(query);
};

/**
 * Get and store the normalized schema of this MongooseAdapter.
 *
 * @return {mschema} An mschema struct.
 * @private
 */
MongooseAdapter.prototype._readSchema = function() {
  var mongooseSchema = this.Model.schema.paths;

  __.forIn(mongooseSchema, function(mongSchemaItem, path) {
    var typeMongoose = mongSchemaItem.options.type;
    var type;
    if (typeof typeMongoose === 'function' && typeMongoose.name) {
      type = typeMongoose.name.toLowerCase();
      if (!(type in mschema.types)) {
        if (type === 'objectid' || type === 'date') {
          type = 'string';
        } else {
          type = 'any';
        }
      }
    } else if (Array.isArray(typeMongoose)) {
      type = ['string'];
    } else {
      type = 'string';
    }

    this.addSchema(path, type);
  }, this);
};

/**
 * Parse an entity type query and translate to mongoose.
 *
 * @param {?Object} query The query
 * @return {Object} The mongoose return value of find().
 */
MongooseAdapter.prototype.parseQuery = function(query) {
  if (!query) {
    return this.Model.find();
  }

  if (!__.isObject(query)) {
    return this.Model.find(query);
  }

  var fullQuery = this._separateSelectors(query);

  var findMethod = this.Model.find(fullQuery.cleanQuery);

  findMethod = this._checkEagerLoad(findMethod);

  return this._buildQuery(findMethod, fullQuery.selectors);
};

/**
 * Separates selectors (lt, gt, etc) and clean attribute queries.
 *
 * Returns an object with two constant keys "selectors" and "cleanQuery"
 *
 * @param {Object} query The raw query.
 * @return {Object} contains two constant keys "selectors" and "cleanQuery".
 */
MongooseAdapter.prototype._separateSelectors = function(query) {
  var result = {
    selectors: {},
    cleanQuery: {},
  };
  __.forIn(query, function(value, key) {
    if (__.isObject(value)) {
      result.selectors[key] = value;
    } else {
      result.cleanQuery[key] = value;
    }
  });

  return result;
};

/**
 * Transpile a sequelize type extended query with selectors like "lt, lte, gt"
 * to mongoose type.
 *
 * @param {mongoose.Query} findMethod A mongoose query builder instance.
 * @param {Object} selectors Selectors.
 * @return {mongoose.Query} The mongoose query builder to perform an .exec() on.
 * @see http://sequelizejs.com/docs/1.7.8/models#finders
 * @see https://github.com/sequelize/sequelize/wiki/API-Reference-Model#findalloptions-queryoptions----promisearrayinstance
 * @see http://mongoosejs.com/docs/queries.html
 */
MongooseAdapter.prototype._buildQuery = function(findMethod, selectors) {
  __.forIn(selectors, function(item, key) {
    var pair = __.pairs(item);
    var selector = pair[0][0];
    var value = pair[0][1];

    switch(selector) {
    case 'between':
      findMethod = findMethod.where(key).gt(value[0]).lt(value[1]);
      break;
    default:
      findMethod = findMethod.where(key)[selector](value);
      break;
    }
  });
  return findMethod;
};

/**
 * Checks if eager loading exists for any attribute and applies it.
 *
 * @param {mongoose.Query} query The query object.
 * @return {mongoose.Query} The query object.
 * @private
 */
MongooseAdapter.prototype._checkEagerLoad = function(query) {
  if (!this._hasEagerLoad) {
    return query;
  }
  this._eagerLoad.forEach(function(attr) {
    query = query.populate(attr);
  });

  return query;
};
<commit_msg>optimizations and fixes on eager loading for mongoose<commit_after>/**
 * @fileOverview The Mongoose CRUD implementation.
 */
var __ = require('lodash');
var mschema = require('mschema');
var Promise = require('bluebird');

var AdaptorBase = require('./base.adp');

function noop() {}

/**
 * The Mongoose CRUD implementation.
 *
 * @param {?Object} optUdo Optionally define the current handling user.
 * @param {mongoose.Model} Model the model that this entity relates to.
 * @constructor
 * @extends {MongooseAdapter.AdaptorBase}
 */
var MongooseAdapter = module.exports = AdaptorBase.extend(function(/* optUdo */) {

  // Mongoose uses dot notation for paths
  this._schemaOpts.expandPaths = true;

  // stub internal methods, all should be private to instance
  this._mongRemove = noop;
});

/**
 * Set the Mongoose Model.
 *
 * @param {mongoose.Model} Model The mongoose model.
 */
MongooseAdapter.prototype.setModel = function(Model) {
  // perform some heuristics on Model identity cause instanceof will not work
  if (
    !Model ||
    Model.name !== 'model' ||
    !Model.db ||
    !Model.model ||
    !Model.schema
  ) {
    throw new TypeError('Model provided not a Mongoose.Model instance');
  }
  this.Model = Model;

  this._defineMethods();
  this._readSchema();
};

MongooseAdapter.prototype._defineMethods = function() {
  this._mongRemove = Promise.promisify(this.Model.remove, this.Model);
};

/**
 * Create an entity item.
 *
 * @param {Object} itemData The data to use for creating.
 * @return {Promise(mongoose.Document)} A promise with the mongoose doc.
 * @override
 */
MongooseAdapter.prototype._create = function(itemData) {
  var self = this;
  return new Promise(function(resolve, reject) {
    var item = new self.Model(itemData);
    item.save(function(err, document) {
      if (err) { return reject(err); }

      if (self._hasEagerLoad) {
        self._readOne(document._id).then(resolve, reject);
      } else {
        resolve(document);
      }
    });
  });
};

/**
 * Read one entity item.
 *
 * @param {string|Object} id the item id or an Object to query against.
 * @return {Promise(mongoose.Document)} A promise with the mongoose doc.
 * @override
 */
MongooseAdapter.prototype._readOne = function(id) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }

  var self = this;
  return new Promise(function(resolve, reject) {
    var query;
    if (__.isObject(id)) {
      query = self.Model.findOne(id);
    } else {
      query = self.Model.findById(id);
    }

    query = self._checkEagerLoad(query);

    // intercept "Cast to ID" error types and return null instead
    return query.exec(function(err, res) {
      if (err) {
        if (err.name === 'CastError' && err.type === 'ObjectId') {
          resolve(null);
        } else {
          reject(err);
        }
        return;
      }
      resolve(res);
    });
  });
};

/**
 * Read items based on query or if not defined, read all items.
 * Do practice common sense!
 *
 * @param {Object=} optQuery Limit the results.
 * @return {Promise(mongoose.Document)} A promise with the mongoose doc.
 * @override
 */
MongooseAdapter.prototype._read = function(optQuery) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }

  var self = this;
  return new Promise(function(resolve, reject) {
    var query = optQuery || {};
    self.parseQuery(query)
      .exec(function(err, result) {
        if (err) {
          reject(err);
          return;
        }
        resolve(result);
      });
  });
};

/**
 * Read a limited set of items.
 *
 * @param {?Object} query Narrow down the set, set to null for all.
 * @param {number} skip starting position.
 * @param {number} limit how many records to fetch.
 * @return {Promise(mongoose.Document)} A promise with the mongoose doc.
 * @override
 */
MongooseAdapter.prototype._readLimit = function(query, skip, limit) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }

  var self = this;
  return new Promise(function(resolve, reject) {
    self.parseQuery(query, self.Model.find)
      .skip(skip)
      .limit(limit)
      .exec(function(err, result) {
        // there's no escaping that
        if (err) {
          return reject(err);
        }
        resolve(result);
      });
  });
};

/**
 * Get the count of items.
 *
 * @param {?Object} query Narrow down the set, null for all.
 * @return {Promise(number)} A promise with the result.
 * @override
 */
MongooseAdapter.prototype._count = function(query) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }
  return new Promise(function(resolve, reject) {
    this.Model.count(query, function(err, num) {
      if (err) {
        reject(err);
      } else {
        resolve(num);
      }
    });
  }.bind(this));
};

/**
 * Update an entity item.
 *
 * @param {string|Object} id the item id or query for item.
 * @param {Object} itemData The data to use for creating.
 * @return {Promise(mongoose.Document)} A promise with the mongoose doc.
 * @override
 */
MongooseAdapter.prototype._update = function(id, itemData) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }
  var self = this;
  return new Promise(function(resolve, reject) {
    self.readOne(id).then(function(doc) {
      if (!__.isObject(doc)) {
        return reject(new Error('record not found'));
      }
      __.forOwn(itemData, function(value, key) {
        doc[key] = value;
      });

      doc.save(function(err) {
        if (err) { return reject(err); }
        resolve(doc);
      });

    }, reject);
  });
};

/**
 * Remove an entity item.
 *
 * @param {string|Object} id the item id or query for item.
 * @return {Promise(Object=)} A promise.
 * @protected
 */
MongooseAdapter.prototype._delete = function(id) {
  if (!this.Model) { throw new Error('No Mongoose.Model defined, use setModel()'); }

  var query = this._getQuery(id);
  return this._mongRemove(query);
};

/**
 * Get and store the normalized schema of this MongooseAdapter.
 *
 * @return {mschema} An mschema struct.
 * @private
 */
MongooseAdapter.prototype._readSchema = function() {
  var mongooseSchema = this.Model.schema.paths;

  __.forIn(mongooseSchema, function(mongSchemaItem, path) {
    var typeMongoose = mongSchemaItem.options.type;
    var type;
    if (typeof typeMongoose === 'function' && typeMongoose.name) {
      type = typeMongoose.name.toLowerCase();
      if (!(type in mschema.types)) {
        if (type === 'objectid' || type === 'date') {
          type = 'string';
        } else {
          type = 'any';
        }
      }
    } else if (Array.isArray(typeMongoose)) {
      type = ['string'];
    } else {
      type = 'string';
    }

    this.addSchema(path, type);
  }, this);
};

/**
 * Parse an entity type query and translate to mongoose.
 *
 * @param {?Object} query The query
 * @return {Object} The mongoose return value of find().
 */
MongooseAdapter.prototype.parseQuery = function(query) {
  if (!query) {
    return this.Model.find();
  }

  if (!__.isObject(query)) {
    return this.Model.find(query);
  }

  var fullQuery = this._separateSelectors(query);

  var findMethod = this.Model.find(fullQuery.cleanQuery);

  findMethod = this._checkEagerLoad(findMethod);

  return this._buildQuery(findMethod, fullQuery.selectors);
};

/**
 * Separates selectors (lt, gt, etc) and clean attribute queries.
 *
 * Returns an object with two constant keys "selectors" and "cleanQuery"
 *
 * @param {Object} query The raw query.
 * @return {Object} contains two constant keys "selectors" and "cleanQuery".
 */
MongooseAdapter.prototype._separateSelectors = function(query) {
  var result = {
    selectors: {},
    cleanQuery: {},
  };
  __.forIn(query, function(value, key) {
    if (__.isObject(value)) {
      result.selectors[key] = value;
    } else {
      result.cleanQuery[key] = value;
    }
  });

  return result;
};

/**
 * Transpile a sequelize type extended query with selectors like "lt, lte, gt"
 * to mongoose type.
 *
 * @param {mongoose.Query} findMethod A mongoose query builder instance.
 * @param {Object} selectors Selectors.
 * @return {mongoose.Query} The mongoose query builder to perform an .exec() on.
 * @see http://sequelizejs.com/docs/1.7.8/models#finders
 * @see https://github.com/sequelize/sequelize/wiki/API-Reference-Model#findalloptions-queryoptions----promisearrayinstance
 * @see http://mongoosejs.com/docs/queries.html
 */
MongooseAdapter.prototype._buildQuery = function(findMethod, selectors) {
  __.forIn(selectors, function(item, key) {
    var pair = __.pairs(item);
    var selector = pair[0][0];
    var value = pair[0][1];

    switch(selector) {
    case 'between':
      findMethod = findMethod.where(key).gt(value[0]).lt(value[1]);
      break;
    default:
      findMethod = findMethod.where(key)[selector](value);
      break;
    }
  });
  return findMethod;
};

/**
 * Checks if eager loading exists for any attribute and applies it.
 *
 * @param {mongoose.Query} query The query object.
 * @return {mongoose.Query} The query object.
 * @private
 */
MongooseAdapter.prototype._checkEagerLoad = function(query) {
  if (!this._hasEagerLoad) {
    return query;
  }
  this._eagerLoad.forEach(function(attr) {
    query = query.populate(attr);
  });

  return query;
};
<|endoftext|>


<commit_before>Package.describe({
    summary: "Accounts Templates styled for Ionic.",
    version: "0.0.1",
    name: "splendido:accounts-templates-ionic",
    git: "https://github.com/splendido/accounts-templates-ionic.git",
});

Package.on_use(function(api, where) {
    api.versionsFrom("METEOR@0.9.2.2");

    api.use([
        "less",
        "templating",
    ], "client");

    api.use([
        "splendido:accounts-templates-core",
    ], ["client", "server"]);

    api.imply([
        "splendido:accounts-templates-core@0.9.2",
    ], ["client", "server"]);

    api.add_files([
        'lib/at_error.html',
        'lib/at_error.js',
        'lib/at_form.html',
        'lib/at_form.js',
        'lib/at_input.html',
        'lib/at_input.js',
        'lib/at_oauth.html',
        'lib/at_oauth.js',
        'lib/at_pwd_form.html',
        'lib/at_pwd_form.js',
        'lib/at_pwd_form_btn.html',
        'lib/at_pwd_form_btn.js',
        'lib/at_pwd_link.html',
        'lib/at_pwd_link.js',
        'lib/at_result.html',
        'lib/at_result.js',
        'lib/at_sep.html',
        'lib/at_sep.js',
        'lib/at_signin_link.html',
        'lib/at_signin_link.js',
        'lib/at_signup_link.html',
        'lib/at_signup_link.js',
        'lib/at_social.html',
        'lib/at_social.js',
        'lib/at_terms_link.html',
        'lib/at_terms_link.js',
        'lib/at_title.html',
        'lib/at_title.js',
        'lib/full_page_at_form.html',
        'lib/at_ionic.less'
    ], ['client']);
});

Package.on_test(function(api) {
    api.use([
        'splendido:accounts-templates-ionic',
        'splendido:accounts-templates-core@0.9.2',
    ]);

    api.use([
        'accounts-password',
        'tinytest',
        'test-helpers'
    ], ['client', 'server']);

    api.add_files([
        'tests/tests.js'
    ], ['client', 'server']);
});<commit_msg>cleanup<commit_after>Package.describe({
    summary: "Accounts Templates styled for Ionic.",
    version: "0.0.1",
    name: "splendido:accounts-templates-ionic",
    git: "https://github.com/splendido/accounts-templates-ionic.git",
});

Package.on_use(function(api, where) {
    api.versionsFrom("METEOR@0.9.2.2");

    api.use([
        "less",
        "templating",
    ], "client");

    api.use([
        "splendido:accounts-templates-core",
    ], ["client", "server"]);

    api.imply([
        "splendido:accounts-templates-core@0.9.4",
    ], ["client", "server"]);

    api.add_files([
        "lib/at_error.html",
        "lib/at_error.js",
        "lib/at_form.html",
        "lib/at_form.js",
        "lib/at_input.html",
        "lib/at_input.js",
        "lib/at_oauth.html",
        "lib/at_oauth.js",
        "lib/at_pwd_form.html",
        "lib/at_pwd_form.js",
        "lib/at_pwd_form_btn.html",
        "lib/at_pwd_form_btn.js",
        "lib/at_pwd_link.html",
        "lib/at_pwd_link.js",
        "lib/at_result.html",
        "lib/at_result.js",
        "lib/at_sep.html",
        "lib/at_sep.js",
        "lib/at_signin_link.html",
        "lib/at_signin_link.js",
        "lib/at_signup_link.html",
        "lib/at_signup_link.js",
        "lib/at_social.html",
        "lib/at_social.js",
        "lib/at_terms_link.html",
        "lib/at_terms_link.js",
        "lib/at_title.html",
        "lib/at_title.js",
        "lib/full_page_at_form.html",
        "lib/at_ionic.less"
    ], ["client"]);
});

Package.on_test(function(api) {
    api.use([
        "splendido:accounts-templates-ionic",
        "splendido:accounts-templates-core@0.9.4",
    ]);

    api.use([
        "accounts-password",
        "tinytest",
        "test-helpers"
    ], ["client", "server"]);

    api.add_files([
        "tests/tests.js"
    ], ["client", "server"]);
});<|endoftext|>


<commit_before>var isCcSubmitted = false;
$(document).ready(function () {
    $('form[name="checkout_payment"]').submit(function () {
        if (!isCcSubmitted) {
            if ($("input[name=\'payment\'][value=\'paymill_cc\']").prop("checked")) {
                if (!paymill.validateExpiry($("#card-expiry-month option:selected").val(), $("#card-expiry-year option:selected").val())) {
                    alert(cc_expiery_invalid);
                    return false;
                }

                if (!paymill.validateCardNumber($("#card-number").val())) {
                    alert(cc_card_number_invalid);
                    return false;
                }

                if (!paymill.validateCvc($("#card-cvc").val())) {
                    alert(cc_cvc_number_invalid);
                    return false;
                }

                paymill.createToken({
                    number: $("#card-number").val(),
                    exp_month: $("#card-expiry-month option:selected").val(),
                    exp_year: $("#card-expiry-year option:selected").val(),
                    cvc: $("#card-cvc").val(),
                    amount_int: $("#amount").val(),
                    currency: $("#currency").val()
                }, PaymillCcResponseHandler);

                return false;
            }
        }
    });

    function PaymillCcResponseHandler(error, result)
    {
        isCcSubmitted = true;
        if (error) {
            console.log("An API error occured: " + error.apierror);
            return false;
        } else {
            console.log(result.token);
            $('form[name="checkout_payment"]').append("<input type='hidden' name='paymill_token' value='" + result.token + "'/>");
            $('form[name="checkout_payment"]').submit();
            return false;
        }
    }

});<commit_msg>PIB-28 fix missing 3ds dialog after a canceled 3d dialog<commit_after>var isCcSubmitted = false;
$(document).ready(function () {
    $('form[name="checkout_payment"]').submit(function () {
        if (!isCcSubmitted) {
            if ($("input[name=\'payment\'][value=\'paymill_cc\']").prop("checked")) {
                if (!paymill.validateExpiry($("#card-expiry-month option:selected").val(), $("#card-expiry-year option:selected").val())) {
                    alert(cc_expiery_invalid);
                    return false;
                }

                if (!paymill.validateCardNumber($("#card-number").val())) {
                    alert(cc_card_number_invalid);
                    return false;
                }

                if (!paymill.validateCvc($("#card-cvc").val())) {
                    alert(cc_cvc_number_invalid);
                    return false;
                }

                paymill.createToken({
                    number: $("#card-number").val(),
                    exp_month: $("#card-expiry-month option:selected").val(),
                    exp_year: $("#card-expiry-year option:selected").val(),
                    cvc: $("#card-cvc").val(),
                    amount_int: $("#amount").val(),
                    currency: $("#currency").val()
                }, PaymillCcResponseHandler);

                return false;
            }
        }
    });

    function PaymillCcResponseHandler(error, result)
    {
        isCcSubmitted = true;
        if (error) {
            isCcSubmitted = false;
            console.log("An API error occured: " + error.apierror);
            return false;
        } else {
            console.log(result.token);
            $('form[name="checkout_payment"]').append("<input type='hidden' name='paymill_token' value='" + result.token + "'/>");
            $('form[name="checkout_payment"]').submit();
            return false;
        }
    }

});<|endoftext|>


<commit_before>Package.describe({
  name: 'packaging:autopublish-test',
  summary: 'Dummy package to test auto-publish with TravisCI. DO NOT USE!',
  version: '0.0.11',
  git: 'https://github.com/MeteorPackaging/autopublish-test.git'
});

Package.onUse(function(api) {
  "use strict";

  api.versionsFrom('1.0.1');
  api.addFiles('lib/main.js');
});

Package.onTest(function(api) {
  "use strict";

  api.use('tinytest');
  api.use('packaging:autopublish-test');
  api.addFiles('tests/main.js');
});
<commit_msg>Bump to version 0.0.12<commit_after>Package.describe({
  name: 'packaging:autopublish-test',
  summary: 'Dummy package to test auto-publish with TravisCI. DO NOT USE!',
  version: '0.0.12',
  git: 'https://github.com/MeteorPackaging/autopublish-test.git'
});

Package.onUse(function(api) {
  "use strict";

  api.versionsFrom('1.0.1');
  api.addFiles('lib/main.js');
});

Package.onTest(function(api) {
  "use strict";

  api.use('tinytest');
  api.use('packaging:autopublish-test');
  api.addFiles('tests/main.js');
});
<|endoftext|>


<commit_before>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2014, Joyent, Inc.
 */

/*
 * net-agent.js
 */

var async = require('async');
var backoff = require('backoff');

var VM = require('./vm');
var NAPI = require('./napi-client');

var _versionCache = null;
function getNetAgentVersion() {
    if (_versionCache === null) {
        _versionCache = require('../package.json').version;
    }
    return _versionCache;
}

function NetAgent(options) {
    this.options = options;
    this.log = options.log;
    this.sample = null;
    this.lastFullSample = null;
    this.uuid = options.uuid;
    this.version = getNetAgentVersion();

    var userAgent = 'net-agent/' + this.version +
        ' (' + 'node/' + process.versions.node + ')' +
        ' server/' + this.uuid;

    this.napiClient = new NAPI({
        url: options.url,
        log: options.log,
        userAgent: userAgent,
        uuid: options.uuid
    });

    this.eventWatcher = VM.createEventWatcher({
        log: options.log
    });

    // Hash that gets built by doing vmadm.lookup
    this.sample = {};
    // Serial queues for sending VM updates serially
    this.queues = {};
}

NetAgent.prototype.start = function () {
    var self = this;
    var log = this.log;

    this.initializeEventWatcher();

    // Wrap our initial full sample in a retry-backoff
    var opts = { uuid: this.uuid };
    var fn = this.sendFullSample.bind(this, opts);
    this.retryUpdate(fn, opts, onRetry);

    function onRetry(err) {
        if (err) {
            log.error(err, 'Failed retry-backoff for initial sendFullSample');
            return;
        }

        log.info('Initial NICs state was successfully sent. Good to go');
        self.eventWatcher.updateState(self.sample);
        self.eventWatcher.lastCfgEvent = self.lastFullSample;
        self.eventWatcher.start();
    }
};

/*
 * Initializes the EventWatcher event listeners
 */
NetAgent.prototype.initializeEventWatcher = function () {
    var self = this;
    var log = this.log;
    var eventWatcher = this.eventWatcher;

    eventWatcher.on('state', function (uuid, state) {
        log.debug('state event for %s state: %s', uuid, state);
        self.pushSample({
            uuid: uuid,
            cachedVm: self.sample[uuid]
        });
    });

    eventWatcher.on('zone_state', function (uuid, zone_state) {
        log.debug('zone_state event for %s newstate: %s', uuid, zone_state);
        self.pushSample({
            uuid: uuid,
            cachedVm: self.sample[uuid]
        });
    });

    eventWatcher.on('zone_xml', function (uuid) {
        log.debug('fs.watch event on /etc/zones for %s', uuid);
        self.pushSample({
            uuid: uuid,
            cachedVm: self.sample[uuid]
        });
    });

    eventWatcher.on('destroyed', function (uuid) {
        var vm = self.sample[uuid];
        if (!vm) {
            log.warn('VM %s appears to have gone away but ' +
                'self.sample doesn\'t have it', uuid);
            return;
        }

        log.info('Found a destroyed VM %s', uuid);
        vm.state = 'destroyed';
        self.pushSample({ uuid: uuid, cachedVm: vm });
    });

    eventWatcher.on('err', function (err) {
        log.error(err, 'eventWatcher saw en error');
    });
};

NetAgent.prototype.setSample = function (sample) {
    var self = this;

    Object.keys(sample).forEach(function (key) {
        self.sample[key] = sample[key];
    });
};

/*
 * On startup, sendFullSample updates all NICs for all VMs on the server. This
 * will be a blocking call before we turn on the event listeners so we allow
 * net-agent to report the full state of the server first
 */
NetAgent.prototype.sendFullSample = function (opts, callback) {
    var self = this;
    var log = this.log;

    this.updateSample({}, function (err, sample) {
        if (err) {
            log.error(err, 'updateSample failed, cannot sendFullSample');
            callback(err);
            return;

        } else if (Object.keys(sample).length === 0) {
            log.warn('empty sample returned by vmadm lookup');
            callback();
            return;
        }

        self.setSample(sample);

        async.forEachSeries(Object.keys(sample), function (uuid, cb) {
            var options = {
                uuid: uuid,
                vm: sample[uuid]
            };

            self._updateVmNics(options, cb);
        },
        function (asyncErr) {
            if (asyncErr) {
                log.error(asyncErr, 'Could not sendFullSample');
                return callback(asyncErr);
            }

            return callback();
        });
    });
};

/*
 * sendSample accepts options.server to indicate this is a full server sample
 */
NetAgent.prototype.sendSample = function (options, callback) {
    var self = this;
    var log = this.log;

    // if vm was destroyed else vmadm lookup
    if (options.cachedVm && options.cachedVm.state === 'destroyed') {
        var destSample = {};
        destSample[options.uuid] = options.cachedVm;
        this.setSample(destSample);
        this.eventWatcher.removeState(options.uuid);

        self._updateVmNics(options, callback);

    } else {
        this.updateSample(options, function (err, sample) {
            if (err) {
                log.error(err, 'updateSample failed, cannot sendSample');
                callback(err);

            } else if (Object.keys(sample).length === 0) {
                log.warn('empty sample returned by vmadm lookup');
                 callback();
            } else {
                self.eventWatcher.updateState(sample);
                self.setSample(sample);
                options.vm = sample[options.uuid];
                self._updateVmNics(options, callback);
            }
        });
    }
};

/*
 * Updates each of the VM NICs
 *
 * - options.cachedVm: what net-agent currently knows about the VM
 * - options.vm: what net-agent has loaded from vmadm
 *
 * When options.vm is undefined, it means that the VM has been destroyed because
 * options.vm gets populated from the vmadm lookup results. We always store the
 * last VM object known to net-agent as options.cachedVm
 *
 * When options.cachedVm is undefined, then this is the first time we see that
 * VM (or our net-agent has just started)
 */
NetAgent.prototype._updateVmNics = function (options, callback) {
    var log = this.log;
    var allNics = [];

    if (options.vm) {
        options.vm.nics.forEach(function (nic) {
            // When VM is failed just mark all NICs are destroyed
            if (options.vm.state === 'failed') {
                nic.destroyed = true;
            }
            allNics.push(nic);
        });
    }

    // First time net-agent runs its cache will be empty
    if (options.cachedVm) {
        options.cachedVm.nics.forEach(function (cachedNic) {
            // When VM is destroyed just mark all NICs are destroyed
            if (options.cachedVm.state === 'destroyed') {
                cachedNic.destroyed = true;
                allNics.push(cachedNic);
                return;
            }

            // If a cached NIC cannot be found on the sampled VM object then
            // we can assume it has been deleted from the VM
            var filtered = options.vm && options.vm.nics.filter(function (nic) {
                return nic.mac === cachedNic.mac;
            });

            if (!filtered.length) {
                cachedNic.destroyed = true;
                allNics.push(cachedNic);
            }
        });
    }

    if (!allNics.length) {
        log.info('VM %s has no NICs to update', options.uuid);
        callback();
        return;
    }

    var vm = options.vm || options.cachedVm;

    this.napiClient.updateNics(vm, allNics, callback);
};

/*
 * Initializes the serial queue for a single uuid and pushes the item to be
 * processed.
 */
NetAgent.prototype.pushSample = function (options) {
    var uuid = options.uuid || this.uuid;

    if (this.queues[uuid] === undefined) {
        this.queues[uuid] = this.createQueue(uuid);
    }

    this.queues[uuid].push(options);
};

/*
 * Retries an update operation.
 */
NetAgent.prototype.retryUpdate = function (fn, options, callback) {
    var log = this.log;
    var retryOpts = { initialDelay: 2000, maxDelay: 64000 };

    function logAttempt(aLog, host) {
        function _log(number, delay, err) {
            var level;
            if (number === 0) {
                level = 'info';
            } else if (number < 5) {
                level = 'warn';
            } else {
                level = 'error';
            }

            aLog.error(err, 'retry error for %s', options.uuid);
            aLog[level]({
                ip: host,
                attempt: number,
                delay: delay
            }, 'retry attempt for %s', options.uuid);
        }

        return (_log);
    }

    var retry = backoff.call(fn, function (err) {
        retry.removeAllListeners('backoff');

        var attempts = retry.getResults().length;

        if (err) {
            log.error({ uuid: options.uuid },
                'Could not retry operation after %d attempts', attempts);
            return callback(err);
        }

        return callback();
    });

    retry.setStrategy(new backoff.ExponentialStrategy({
        initialDelay: retryOpts.initialDelay,
        maxDelay: retryOpts.maxDelay
    }));

    retry.failAfter(retryOpts.retries || Infinity);
    retry.on('backoff', logAttempt(log));

    retry.start();
};

/*
 * Initializes a serial queue for a uuid
 */
NetAgent.prototype.createQueue = function (uuid) {
    var self = this;
    var log = this.log;

    var queue = async.queue(function (opts, callback) {
        var fn = self.sendSample.bind(self, opts);
        self.retryUpdate(fn, opts, function (err) {
            if (err) {
                log.error(err, 'Error updating NICs %', uuid);
                return callback(err);
            }

            return callback();
        });
    }, 1);

    queue.drain = function () {
        log.trace('serial queue for %s has been drained', uuid);
    };

    queue.saturated = function () {
        log.trace('serial queue for % has been saturated', uuid);
    };

    return queue;
};

/*
 *
 *  Sample format that gets loaded from vmadm.lookup:
 *
 *    {
 *    '70ac24a6-962a-4711-92f6-6dc6a53ea59e':
 *    { uuid: '70ac24a6-962a-4711-92f6-6dc6a53ea59e',
 *       owner_uuid: '930896af-bf8c-48d4-885c-6573a94b1853',
 *       quota: 25,
 *       max_physical_memory: 128,
 *       zone_state: 'running',
 *       state: 'running',
 *       brand: 'joyent-minimal',
 *       cpu_cap: 100,
 *       last_modified: '2014-04-29T23:30:17.000Z' },
 *    '9181f298-a867-49c6-9f34-d57584e7047e':
 *     { uuid: '9181f298-a867-49c6-9f34-d57584e7047e',
 *       owner_uuid: '930896af-bf8c-48d4-885c-6573a94b1853',
 *       quota: 25,
 *       max_physical_memory: 1024,
 *       zone_state: 'running',
 *       state: 'running',
 *       brand: 'joyent-minimal',
 *       cpu_cap: 300,
 *       last_modified: '2014-04-29T23:36:33.000Z' } },
 *       ...
 *       ...
 *   }
 */

NetAgent.prototype.updateSample = function (options, callback) {
    var self = this;
    var log = this.log;
    var uuid = options.uuid;

    var newSample;

    function lookup(cb) {
        // If we fail a lookup, newSample gets reset on every retry
        newSample = {};
        var searchOpts = {};
        var query;

        if (uuid) {
            searchOpts.uuid = uuid;
            query = 'uuid=' + uuid;
        } else {
            query = 'uuid=*';
        }

        log.debug('Starting updateSample ' + query);

        VM.list(searchOpts, function (err, vmobjs) {
            var vmobj;
            var running = 0;
            var notRunning = 0;
            var nonInventory = 0;

            if (err) {
                log.error(err, 'ERROR: unable update VM list');
                return cb(err);

            } else {
                for (vmobj in vmobjs) {
                    vmobj = vmobjs[vmobj];
                    if (!vmobj.do_not_inventory) {
                        newSample[vmobj.uuid] = vmobj;
                        if (vmobj.zone_state === 'running') {
                            running++;
                        } else {
                            notRunning++;
                        }
                    } else {
                        nonInventory++;
                    }
                }

                var lookupResults = {
                    running: running,
                    notRunning: notRunning,
                    nonInventory: nonInventory
                };
                log.trace(lookupResults, 'Lookup query results');

                return cb(null);
            }
        });
    }

    function logAttempt(aLog, host) {
        function _log(number, delay) {
            var level;
            if (number === 0) {
                level = 'info';
            } else if (number < 5) {
                level = 'warn';
            } else {
                level = 'error';
            }
            aLog[level]({
                ip: host,
                attempt: number,
                delay: delay
            }, 'updateSample retry attempt');
        }

        return (_log);
    }

    var retry = backoff.call(lookup, function (err) {
        retry.removeAllListeners('backoff');

        var attempts = retry.getResults().length;
        if (err) {
            log.error('Could not updateSample after %d attempts', attempts);
            return callback(err);
        }

        self.lastFullSample = (new Date()).getTime() / 1000;

        return callback(null, newSample);
    });

    var retryOpts = { initialDelay: 200, maxDelay: 2000 };
    retry.setStrategy(new backoff.ExponentialStrategy({
        initialDelay: retryOpts.initialDelay,
        maxDelay: retryOpts.maxDelay
    }));

    retry.failAfter(5);
    retry.on('backoff', logAttempt(log));
    retry.start();
};

module.exports = NetAgent;
<commit_msg>Limit number of concurrent updateSamples to 8<commit_after>/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

/*
 * Copyright (c) 2014, Joyent, Inc.
 */

/*
 * net-agent.js
 */

var async = require('async');
var backoff = require('backoff');

var VM = require('./vm');
var NAPI = require('./napi-client');

var _versionCache = null;
function getNetAgentVersion() {
    if (_versionCache === null) {
        _versionCache = require('../package.json').version;
    }
    return _versionCache;
}

function NetAgent(options) {
    this.options = options;
    this.log = options.log;
    this.sample = null;
    this.lastFullSample = null;
    this.uuid = options.uuid;
    this.version = getNetAgentVersion();

    var userAgent = 'net-agent/' + this.version +
        ' (' + 'node/' + process.versions.node + ')' +
        ' server/' + this.uuid;

    this.napiClient = new NAPI({
        url: options.url,
        log: options.log,
        userAgent: userAgent,
        uuid: options.uuid
    });

    this.eventWatcher = VM.createEventWatcher({
        log: options.log
    });

    // Hash that gets built by doing vmadm.lookup
    this.sample = {};
    // Serial queues for sending VM updates serially
    this.queues = {};
}

NetAgent.prototype.start = function () {
    var self = this;
    var log = this.log;

    this.initializeEventWatcher();

    // Wrap our initial full sample in a retry-backoff
    var opts = { uuid: this.uuid };
    var fn = this.sendFullSample.bind(this, opts);
    this.retryUpdate(fn, opts, onRetry);

    function onRetry(err) {
        if (err) {
            log.error(err, 'Failed retry-backoff for initial sendFullSample');
            return;
        }

        log.info('Initial NICs state was successfully sent. Good to go');
        self.eventWatcher.updateState(self.sample);
        self.eventWatcher.lastCfgEvent = self.lastFullSample;
        self.eventWatcher.start();
    }
};

/*
 * Initializes the EventWatcher event listeners
 */
NetAgent.prototype.initializeEventWatcher = function () {
    var self = this;
    var log = this.log;
    var eventWatcher = this.eventWatcher;

    eventWatcher.on('state', function (uuid, state) {
        log.debug('state event for %s state: %s', uuid, state);
        self.pushSample({
            uuid: uuid,
            cachedVm: self.sample[uuid]
        });
    });

    eventWatcher.on('zone_state', function (uuid, zone_state) {
        log.debug('zone_state event for %s newstate: %s', uuid, zone_state);
        self.pushSample({
            uuid: uuid,
            cachedVm: self.sample[uuid]
        });
    });

    eventWatcher.on('zone_xml', function (uuid) {
        log.debug('fs.watch event on /etc/zones for %s', uuid);
        self.pushSample({
            uuid: uuid,
            cachedVm: self.sample[uuid]
        });
    });

    eventWatcher.on('destroyed', function (uuid) {
        var vm = self.sample[uuid];
        if (!vm) {
            log.warn('VM %s appears to have gone away but ' +
                'self.sample doesn\'t have it', uuid);
            return;
        }

        log.info('Found a destroyed VM %s', uuid);
        vm.state = 'destroyed';
        self.pushSample({ uuid: uuid, cachedVm: vm });
    });

    eventWatcher.on('err', function (err) {
        log.error(err, 'eventWatcher saw en error');
    });
};

NetAgent.prototype.setSample = function (sample) {
    var self = this;

    Object.keys(sample).forEach(function (key) {
        self.sample[key] = sample[key];
    });
};

/*
 * On startup, sendFullSample updates all NICs for all VMs on the server. This
 * will be a blocking call before we turn on the event listeners so we allow
 * net-agent to report the full state of the server first
 */
NetAgent.prototype.sendFullSample = function (opts, callback) {
    var self = this;
    var log = this.log;

    this.updateSample({}, function (err, sample) {
        if (err) {
            log.error(err, 'updateSample failed, cannot sendFullSample');
            callback(err);
            return;

        } else if (Object.keys(sample).length === 0) {
            log.warn('empty sample returned by vmadm lookup');
            callback();
            return;
        }

        self.setSample(sample);

        async.forEachSeries(Object.keys(sample), function (uuid, cb) {
            var options = {
                uuid: uuid,
                vm: sample[uuid]
            };

            self._updateVmNics(options, cb);
        },
        function (asyncErr) {
            if (asyncErr) {
                log.error(asyncErr, 'Could not sendFullSample');
                return callback(asyncErr);
            }

            return callback();
        });
    });
};

/*
 * sendSample accepts options.server to indicate this is a full server sample
 */
NetAgent.prototype.sendSample = function (options, callback) {
    var self = this;
    var log = this.log;

    // if vm was destroyed else vmadm lookup
    if (options.cachedVm && options.cachedVm.state === 'destroyed') {
        var destSample = {};
        destSample[options.uuid] = options.cachedVm;
        this.setSample(destSample);
        this.eventWatcher.removeState(options.uuid);

        self._updateVmNics(options, callback);

    } else {
        this.updateSample(options, function (err, sample) {
            if (err) {
                log.error(err, 'updateSample failed, cannot sendSample');
                callback(err);

            } else if (Object.keys(sample).length === 0) {
                log.warn('empty sample returned by vmadm lookup');
                 callback();
            } else {
                self.eventWatcher.updateState(sample);
                self.setSample(sample);
                options.vm = sample[options.uuid];
                self._updateVmNics(options, callback);
            }
        });
    }
};

/*
 * Updates each of the VM NICs
 *
 * - options.cachedVm: what net-agent currently knows about the VM
 * - options.vm: what net-agent has loaded from vmadm
 *
 * When options.vm is undefined, it means that the VM has been destroyed because
 * options.vm gets populated from the vmadm lookup results. We always store the
 * last VM object known to net-agent as options.cachedVm
 *
 * When options.cachedVm is undefined, then this is the first time we see that
 * VM (or our net-agent has just started)
 */
NetAgent.prototype._updateVmNics = function (options, callback) {
    var log = this.log;
    var allNics = [];

    if (options.vm) {
        options.vm.nics.forEach(function (nic) {
            // When VM is failed just mark all NICs are destroyed
            if (options.vm.state === 'failed') {
                nic.destroyed = true;
            }
            allNics.push(nic);
        });
    }

    // First time net-agent runs its cache will be empty
    if (options.cachedVm) {
        options.cachedVm.nics.forEach(function (cachedNic) {
            // When VM is destroyed just mark all NICs are destroyed
            if (options.cachedVm.state === 'destroyed') {
                cachedNic.destroyed = true;
                allNics.push(cachedNic);
                return;
            }

            // If a cached NIC cannot be found on the sampled VM object then
            // we can assume it has been deleted from the VM
            var filtered = options.vm && options.vm.nics.filter(function (nic) {
                return nic.mac === cachedNic.mac;
            });

            if (!filtered.length) {
                cachedNic.destroyed = true;
                allNics.push(cachedNic);
            }
        });
    }

    if (!allNics.length) {
        log.info('VM %s has no NICs to update', options.uuid);
        callback();
        return;
    }

    var vm = options.vm || options.cachedVm;

    this.napiClient.updateNics(vm, allNics, callback);
};

/*
 * Initializes the serial queue for a single uuid and pushes the item to be
 * processed.
 */
NetAgent.prototype.pushSample = function (options) {
    var uuid = options.uuid || this.uuid;

    if (this.queues[uuid] === undefined) {
        this.queues[uuid] = this.createQueue(uuid);
    }

    this.queues[uuid].push(options);
};

/*
 * Retries an update operation.
 */
NetAgent.prototype.retryUpdate = function (fn, options, callback) {
    var log = this.log;
    var retryOpts = { initialDelay: 2000, maxDelay: 64000 };

    function logAttempt(aLog, host) {
        function _log(number, delay, err) {
            var level;
            if (number === 0) {
                level = 'info';
            } else if (number < 5) {
                level = 'warn';
            } else {
                level = 'error';
            }

            aLog.error(err, 'retry error for %s', options.uuid);
            aLog[level]({
                ip: host,
                attempt: number,
                delay: delay
            }, 'retry attempt for %s', options.uuid);
        }

        return (_log);
    }

    var retry = backoff.call(fn, function (err) {
        retry.removeAllListeners('backoff');

        var attempts = retry.getResults().length;

        if (err) {
            log.error({ uuid: options.uuid },
                'Could not retry operation after %d attempts', attempts);
            return callback(err);
        }

        return callback();
    });

    retry.setStrategy(new backoff.ExponentialStrategy({
        initialDelay: retryOpts.initialDelay,
        maxDelay: retryOpts.maxDelay
    }));

    retry.failAfter(retryOpts.retries || Infinity);
    retry.on('backoff', logAttempt(log));

    retry.start();
};

/*
 * Initializes a serial queue for a uuid
 */
NetAgent.prototype.createQueue = function (uuid) {
    var self = this;
    var log = this.log;

    var queue = async.queue(function (opts, callback) {
        var fn = self.sendSample.bind(self, opts);
        self.retryUpdate(fn, opts, function (err) {
            if (err) {
                log.error(err, 'Error updating NICs %', uuid);
                return callback(err);
            }

            return callback();
        });
    }, 1);

    queue.drain = function () {
        log.trace('serial queue for %s has been drained', uuid);
    };

    queue.saturated = function () {
        log.trace('serial queue for % has been saturated', uuid);
    };

    return queue;
};

/*
 *
 *  Sample format that gets loaded from vmadm.lookup:
 *
 *    {
 *    '70ac24a6-962a-4711-92f6-6dc6a53ea59e':
 *    { uuid: '70ac24a6-962a-4711-92f6-6dc6a53ea59e',
 *       owner_uuid: '930896af-bf8c-48d4-885c-6573a94b1853',
 *       quota: 25,
 *       max_physical_memory: 128,
 *       zone_state: 'running',
 *       state: 'running',
 *       brand: 'joyent-minimal',
 *       cpu_cap: 100,
 *       last_modified: '2014-04-29T23:30:17.000Z' },
 *    '9181f298-a867-49c6-9f34-d57584e7047e':
 *     { uuid: '9181f298-a867-49c6-9f34-d57584e7047e',
 *       owner_uuid: '930896af-bf8c-48d4-885c-6573a94b1853',
 *       quota: 25,
 *       max_physical_memory: 1024,
 *       zone_state: 'running',
 *       state: 'running',
 *       brand: 'joyent-minimal',
 *       cpu_cap: 300,
 *       last_modified: '2014-04-29T23:36:33.000Z' } },
 *       ...
 *       ...
 *   }
 */

NetAgent.prototype.updateSample = function (options, callback) {
    if (!this._sampleQueue)
        this._sampleQueue = async.queue(updateSample.bind(this), 8);
    this._sampleQueue.push(options, callback);
}

function updateSample(options, callback) {
    var self = this;
    var log = this.log;
    var uuid = options.uuid;

    var newSample;

    function lookup(cb) {
        // If we fail a lookup, newSample gets reset on every retry
        newSample = {};
        var searchOpts = {};
        var query;

        if (uuid) {
            searchOpts.uuid = uuid;
            query = 'uuid=' + uuid;
        } else {
            query = 'uuid=*';
        }

        log.debug('Starting updateSample ' + query);

        VM.list(searchOpts, function (err, vmobjs) {
            var vmobj;
            var running = 0;
            var notRunning = 0;
            var nonInventory = 0;

            if (err) {
                log.error(err, 'ERROR: unable update VM list');
                return cb(err);

            } else {
                for (vmobj in vmobjs) {
                    vmobj = vmobjs[vmobj];
                    if (!vmobj.do_not_inventory) {
                        newSample[vmobj.uuid] = vmobj;
                        if (vmobj.zone_state === 'running') {
                            running++;
                        } else {
                            notRunning++;
                        }
                    } else {
                        nonInventory++;
                    }
                }

                var lookupResults = {
                    running: running,
                    notRunning: notRunning,
                    nonInventory: nonInventory
                };
                log.trace(lookupResults, 'Lookup query results');

                return cb(null);
            }
        });
    }

    function logAttempt(aLog, host) {
        function _log(number, delay) {
            var level;
            if (number === 0) {
                level = 'info';
            } else if (number < 5) {
                level = 'warn';
            } else {
                level = 'error';
            }
            aLog[level]({
                ip: host,
                attempt: number,
                delay: delay
            }, 'updateSample retry attempt');
        }

        return (_log);
    }

    var retry = backoff.call(lookup, function (err) {
        retry.removeAllListeners('backoff');

        var attempts = retry.getResults().length;
        if (err) {
            log.error('Could not updateSample after %d attempts', attempts);
            return callback(err);
        }

        self.lastFullSample = (new Date()).getTime() / 1000;

        return callback(null, newSample);
    });

    var retryOpts = { initialDelay: 200, maxDelay: 2000 };
    retry.setStrategy(new backoff.ExponentialStrategy({
        initialDelay: retryOpts.initialDelay,
        maxDelay: retryOpts.maxDelay
    }));

    retry.failAfter(5);
    retry.on('backoff', logAttempt(log));
    retry.start();
};

module.exports = NetAgent;
<|endoftext|>


<commit_before>/**
 * Javascript for autocomplete/suggest/search-as-you-type.
 *
 * @author Mark Guinn
 * @date 10.18.13
 * @package shop_search
 * @subpackage javascript
 */
(function ($, window, document, undefined) {
	'use strict';
	if (typeof window.ShopSearch == 'undefined') window.ShopSearch = {};

	window.ShopSearch.Suggest = {
		init:function(){
			var searchField = $('#ShopSearchForm_SearchForm_q'),
				suggestURL  = document.location.protocol + "//" + document.location.host + ':8983/solr/ShopSearchSolr/select'
					+ '?facet=true&sort=score+desc&start=0&facet.limit=5&json.nl=map&facet.field=_autocomplete'
					+ '&wt=json&fq=%2B(_versionedstage:"Live"+(*:*+-_versionedstage:[*+TO+*]))&rows=5',
//					+ '&q=jan+jan*'
//					+ '&facet.prefix=jan'
				cache       = {};

			if (suggestURL && searchField.length > 0) {
				searchField.autocomplete({
					minLength:  2,
					source:function(request, response){
						var cacheKey;
						var term = request.term;
						var select = searchField.closest('form').find('select');
						if (select.length > 0) {
							request[select.attr('name')] = select.val();
							cacheKey = 'CAT' + select.val() + '_' + term;
						} else {
							cacheKey = 'CAT0_' + term;
						}

						// Need to factor category in if present
						if (cacheKey in cache) {
							response(cache[cacheKey]);
							return;
						}

						$.getJSON(suggestURL, request, function(data, status, xhr) {
							// Result comes back with 2 arrays, transform them into something we can render more easily
							// This is slightly more cumbersome, but it allows the frontend dev to use a different
							// autocomplete (or whatever) javascript.
							var out = [];
							//var sug = data.
							if (data.suggestions.length > 0) {
								for (var i = 0; i < data.suggestions.length; i++) {
									out.push({
										label:      data.suggestions[i],
										category:   'Search Suggestions'
									});
								}
							}

							if (data.products.length > 0) {
								for (var i = 0; i < data.products.length; i++) {
									data.products[i].category = 'Products';
									out.push(data.products[i]);
								}
							}

							cache[cacheKey] = out;
							response(out);
						});
					}
				});

				searchField.data( "ui-autocomplete" )._renderMenu = function( ul, items ) {
					var self = this,
						currentCategory = "";

					ul.addClass('shop-search');
					$.each( items, function( index, item ) {
						if ( item.category != currentCategory ) {
							ul.append( "
" + item.category + "
" );
							currentCategory = item.category;
						}
						self._renderItemData( ul, item );
					});
				};

				searchField.data( "ui-autocomplete" )._renderItem = function(ul, item) {
					var li = $('
');

					if (item.title) {
						var a = $('').addClass('product').attr('href', item.link);

						if (item.thumb) {
							$('').attr('src', item.thumb).appendTo(a);
							a.addClass('thumb');
						}

						$('').addClass('title').html(item.title).appendTo(a);

						if (item.desc) $('').addClass('desc').html(item.desc).appendTo(a);
						var price = $('').addClass('price').html(item.price).appendTo(a);
						if (item.original_price) price.prepend(''+item.original_price+' ');

						a.appendTo(li);
					} else {
						$('').html(item.label).appendTo(li);
					}

					return li.appendTo(ul);
				};
			}
		}
	};

}(jQuery, this, this.document));<commit_msg>Search suggest dropdown can now talk to solr directly for a much faster suggestion<commit_after>/**
 * Javascript for autocomplete/suggest/search-as-you-type.
 *
 * @author Mark Guinn
 * @date 10.18.13
 * @package shop_search
 * @subpackage javascript
 */
(function ($, window, document, undefined) {
	'use strict';
	if (typeof window.ShopSearch == 'undefined') window.ShopSearch = {};

	window.ShopSearch.Suggest = {
		init:function(){
			var searchField = $('#ShopSearchForm_SearchForm_q'),
				suggestURL  = document.location.protocol + "//" + document.location.host + ':8983/solr/ShopSearchSolr/select'
					+ '?facet=true&sort=score+desc&start=0&facet.limit=5&json.nl=map&facet.field=_autocomplete'
					+ '&wt=json&fq=%2B(_versionedstage:"Live"+(*:*+-_versionedstage:[*+TO+*]))&rows=5',
//					+ '&q=jan+jan*'
//					+ '&facet.prefix=jan',
				cache       = {};

			if (suggestURL && searchField.length > 0) {
				searchField.autocomplete({
					minLength:  2,
					source:function(request, response){
						console.log('request', request);
						var cacheKey;
						var term = request.term;
						var select = searchField.closest('form').find('select');
						if (select.length > 0) {
							request[select.attr('name')] = select.val();
							cacheKey = 'CAT' + select.val() + '_' + term;
						} else {
							cacheKey = 'CAT0_' + term;
						}

						// Need to factor category in if present
						if (cacheKey in cache) {
							response(cache[cacheKey]);
							return;
						}

						// Format the search terms for solr
						var terms    = request.term.toLowerCase().split(/\s+/);
						var lastTerm = terms.length > 0 ? terms.pop() : '';
						var prefix   = terms.length > 0 ? terms.join(' ')+' ' : '';
						terms.push(lastTerm);
						terms.push(lastTerm+'*'); // this allows for partial words to still match

						var url = suggestURL + '&q=' + encodeURIComponent(terms.join(' '))
							+ '&facet.prefix=' + encodeURIComponent(lastTerm);

						// TODO: add category filter if present

						// Make the call
						$.ajax({
							url:        url,
							//data:       request,
							dataType:   'jsonp',
							jsonp:      'json.wrf',
							success:function(data, status, xhr) {
								// Result comes back with 2 arrays, transform them into something we can render more easily
								// This is slightly more cumbersome, but it allows the frontend dev to use a different
								// autocomplete (or whatever) javascript.
								var out = [];
								var suggestions = data.facet_counts.facet_fields._autocomplete;
								var products = data.response.docs;

								for (var k in suggestions) {
									var str = prefix + k;
									out.push({
										label:      str.replace(lastTerm, ''+lastTerm+''),
										category:   'Search Suggestions'
									});
								}

								if (products.length > 0) {
									for (var i = 0; i < products.length; i++) {
										var prod = {
											category:   'Products',
											link:       products[i].Product_Link,
											title:      products[i].SiteTree_Title,
											thumb:      products[i].Product_ThumbURL,
											price:      products[i].Product_VFI_Price,
											original_price: products[i].Product_BasePrice
										};
										out.push(prod);
									}
								}

								cache[cacheKey] = out;
								response(out);
							}
						});
					}
				});

				searchField.data( "ui-autocomplete" )._renderMenu = function( ul, items ) {
					var self = this,
						currentCategory = "";

					ul.addClass('shop-search');
					$.each( items, function( index, item ) {
						if ( item.category != currentCategory ) {
							ul.append( "
" + item.category + "
" );
							currentCategory = item.category;
						}
						self._renderItemData( ul, item );
					});
				};

				searchField.data( "ui-autocomplete" )._renderItem = function(ul, item) {
					var li = $('
');

					if (item.title) {
						var a = $('').addClass('product').attr('href', item.link);

						if (item.thumb) {
							$('').attr('src', item.thumb).appendTo(a);
							a.addClass('thumb');
						}

						$('').addClass('title').html(item.title).appendTo(a);

						if (item.desc) $('').addClass('desc').html(item.desc).appendTo(a);
						var price = $('').addClass('price').html(item.price).appendTo(a);
						if (item.original_price) price.prepend(''+item.original_price+' ');

						a.appendTo(li);
					} else {
						$('').html(item.label).appendTo(li);
					}

					return li.appendTo(ul);
				};
			}
		}
	};

}(jQuery, this, this.document));<|endoftext|>


<commit_before>
Package.describe({
  name: 'space:accounts',
  summary: 'Accounts module for Space applications',
  version: '0.1.2',
  git: 'https://github.com/meteor-space/accounts.git',
  documentation: 'README.md'
});

Package.onUse(function(api) {

  api.versionsFrom('METEOR@1.0');

  api.use([
    'coffeescript',
    'mongo',
    'accounts-base',
    'accounts-password',
    'check',
    'space:vo-user@0.2.0',
    'space:event-sourcing@2.1.0',
  ]);

  api.addFiles([
    'source/server/module.coffee',
    'source/server/commands.coffee',
    'source/server/events.coffee',
    // USERS
    'source/server/users/user.coffee',
    'source/server/users/users-router.coffee'
  ], 'server');

});

Package.onTest(function(api) {

  api.use([
    'coffeescript',
    'mongo',
    'space:accounts',
    'space:vo-user@0.2.0',
    'practicalmeteor:munit@2.1.4',
    'space:testing@1.5.0',
  ]);

  api.addFiles([
    'tests/users/users.unit.coffee'
  ], 'server');

});
<commit_msg>Bump space:vo-user<commit_after>
Package.describe({
  name: 'space:accounts',
  summary: 'Accounts module for Space applications',
  version: '0.1.2',
  git: 'https://github.com/meteor-space/accounts.git',
  documentation: 'README.md'
});

Package.onUse(function(api) {

  api.versionsFrom('METEOR@1.0');

  api.use([
    'coffeescript',
    'mongo',
    'accounts-base',
    'accounts-password',
    'check',
    'space:vo-user@0.2.1',
    'space:event-sourcing@2.1.0',
  ]);

  api.addFiles([
    'source/server/module.coffee',
    'source/server/commands.coffee',
    'source/server/events.coffee',
    // USERS
    'source/server/users/user.coffee',
    'source/server/users/users-router.coffee'
  ], 'server');

});

Package.onTest(function(api) {

  api.use([
    'coffeescript',
    'mongo',
    'space:accounts',
    'space:vo-user@0.2.0',
    'practicalmeteor:munit@2.1.4',
    'space:testing@1.5.0',
  ]);

  api.addFiles([
    'tests/users/users.unit.coffee'
  ], 'server');

});
<|endoftext|>


<commit_before>'use strict';

/**
 * Update the app
 *
 * Afert downloading the RELEASE metadata it
 * checks if there is an update ready.
 *
 * (c) 2015 Matthias Hannig
 */

// == Libraries
var sym = require('log-symbols');

// == Modules
var currentRelease = require('../release/current-release');

var parseRelease    = require('../release/parse-release');
var needsUpdate     = require('../release/needs-update');

var downloadMeta    = require('../downloader/download-release-meta');
var downloadRelease = require('../downloader/download-release');
var unpack          = require('../archiver/unpack');
var verify          = require('../verifier/verify');
var install         = require('../installer/install');

// == Update application (if needed)
var cli_update = function(argv) {
  var _release = currentRelease();
  var repositoryUrl = _release.updates.repository;

  // Start (and verify) download
  downloadMeta(repositoryUrl)
    .then(needsUpdate(_release.version))
    .then(downloadRelease(repositoryUrl))
    .then(unpack())
    .then(verify())
    .then(install())
    .then(function(release){
      console.log(sym.success +
        ' ' + _release.app.name + ' successfully updated: ' +
        _release.version + ' -> ' + release.version
      );
    },
    function(err) {
      if(err == 'release_is_up_to_date') {
        console.log(sym.success +
          ' ' + _release.app.name + '(' + _release.version + ') ' +
          'is up to date.'
        );
      }
      else {
        console.log(sym.error + ' ' + err);
      }
    });

};

// == Export
module.exports = cli_update;

<commit_msg>less verbose log.<commit_after>'use strict';

/**
 * Update the app
 *
 * Afert downloading the RELEASE metadata it
 * checks if there is an update ready.
 *
 * (c) 2015 Matthias Hannig
 */

// == Libraries
var sym = require('log-symbols');

// == Modules
var currentRelease = require('../release/current-release');

var parseRelease    = require('../release/parse-release');
var needsUpdate     = require('../release/needs-update');

var downloadMeta    = require('../downloader/download-release-meta');
var downloadRelease = require('../downloader/download-release');
var unpack          = require('../archiver/unpack');
var verify          = require('../verifier/verify');
var install         = require('../installer/install');

// == Update application (if needed)
var cli_update = function(argv) {
  var _release = currentRelease();
  var repositoryUrl = _release.updates.repository;

  console.log( sym.info + ' Checking for updates at: ' + new Date() );

  // Start (and verify) download
  downloadMeta(repositoryUrl)
    .then(needsUpdate(_release.version))
    .then(downloadRelease(repositoryUrl))
    .then(unpack())
    .then(verify())
    .then(install())
    .then(function(release){
      console.log(sym.success +
        ' ' + _release.app.name + ' successfully updated: ' +
        _release.version + ' -> ' + release.version
      );
    },
    function(err) {
      if(err == 'release_is_up_to_date') {
        // Ignore this. Everything is up to date.
        // Don't spam logfile.
      }
      else {
        console.log(sym.error + ' ' + err);
      }
    });

};

// == Export
module.exports = cli_update;

<|endoftext|>


<commit_before>'use strict';

var github = require('./github');
var npm = require('./npm');
var db = require('./db');
var email = require('./email');

var semver = require('semver');

var cache = {};

db.readSubscriptions(function(error, subscriptions) {
    if (error) {
        console.error(error);
        return;
    }

    cache = {};
    for(var i = 0, n = subscriptions.length; i < n; i++) {
        var subscription = subscriptions[i];

        var user = github.getUserFromUrl(subscription.repourl);
        var repo = github.getRepoFromUrl(subscription.repourl);

        github.getPackageJson(user, repo, function(error, json) {
            if (error) {
                console.error(error);
                return;
            }

            for (var packageName in json.dependencies) {
                checkPackage(subscription.email, subscription.repourl, packageName, json.dependencies[packageName]);
            }
            for (var packageName in json.devDependencies) {
                checkPackage(subscription.email, subscription.repourl, packageName, json.devDependencies[packageName]);
            }
        });
    }
});

function cacheIt(packageName, version, timeStamp, isNewRelease, callback) {
    cache[packageName] = {
        version: version,
        timeStamp: timeStamp,
        isNewRelease: isNewRelease
    };
    callback(null, version, isNewRelease);
}

function checkPackage(email, repourl, packageName, currentVersion) {
    getLatestVersion(packageName, function(error, latestVersion, isNew) {
        if (error) {
            console.error(error);
            return;
        }

        if (isNew) {// && semver.gt(latestVersion, currentVersion)) {
            email.queue(email, repourl, packageName, currentVersion, latestVersion);
        }
    });
}

function isStillValid(timeStamp) {
    return new Date(timeStamp) >= new Date().setDate(-1);
}

function getLatestVersion(packageName, callback) {
    var cached = cache[packageName];
    if (cached) {
        callback(null, cached.version, cached.isNewRelease);
        return;
    }

    db.getPackageByName(packageName, function(error, packages) {
        if (error) {
            console.error(error);
            callback(error);
            return;
        }

        if (packages.length === 0) {
            npm.getLatestVersion(packageName, function(error, version) {
                var timeStamp = new Date().toUTCString();
                db.createPackage(packageName, version, timeStamp);
                cacheIt(packageName, version, timeStamp, false, callback);
            });
            return;
        }

        // TODO: is this needed, when there's a cache?
        var pack = packages[0];
        if (isStillValid(pack.timestamp)) {
            cacheIt(packageName, pack.version, pack.timeStamp, false, callback);
            return;
        }

        npm.getLatestVersion(packageName, function(error, version) {
            var timeStamp = new Date().toUTCString();
            db.updatePackageByName(packageName, version, timeStamp);
            var isNewRelease = semver.gt(version, pack.version);
            cacheIt(packageName, version, timeStamp, isNewRelease, callback);
        });
    });
}
<commit_msg>Add trace statements in cron job.<commit_after>'use strict';

var github = require('./github');
var npm = require('./npm');
var db = require('./db');
var email = require('./email');

var semver = require('semver');

var cache = {};

db.readSubscriptions(function(error, subscriptions) {
    if (error) {
        console.error(error);
        return;
    }

    cache = {};
    for(var i = 0, n = subscriptions.length; i < n; i++) {
        var subscription = subscriptions[i];

        var user = github.getUserFromUrl(subscription.repourl);
        var repo = github.getRepoFromUrl(subscription.repourl);

        github.getPackageJson(user, repo, function(error, json) {
            if (error) {
                console.error(error);
                return;
            }
console.log('Got package ' + json);
            for (var packageName in json.dependencies) {
                checkPackage(subscription.email, subscription.repourl, packageName, json.dependencies[packageName]);
            }
            for (var packageName in json.devDependencies) {
                checkPackage(subscription.email, subscription.repourl, packageName, json.devDependencies[packageName]);
            }
        });
    }
});

function cacheIt(packageName, version, timeStamp, isNewRelease, callback) {
    cache[packageName] = {
        version: version,
        timeStamp: timeStamp,
        isNewRelease: isNewRelease
    };
    callback(null, version, isNewRelease);
}

function checkPackage(email, repourl, packageName, currentVersion) {
console.log('Checking package ' + packageName);
    getLatestVersion(packageName, function(error, latestVersion, isNew) {
        if (error) {
            console.error(error);
            return;
        }
console.log('Latest version for ' + packageName + ' is ' + latestVersion + ' and its new: ' + isNew);
        if (isNew) {// && semver.gt(latestVersion, currentVersion)) {
            email.queue(email, repourl, packageName, currentVersion, latestVersion);
        }
    });
}

function isStillValid(timeStamp) {
    return new Date(timeStamp) >= new Date().setDate(-1);
}

function getLatestVersion(packageName, callback) {
    var cached = cache[packageName];
    if (cached) {
        callback(null, cached.version, cached.isNewRelease);
        return;
    }

    db.getPackageByName(packageName, function(error, packages) {
        if (error) {
            console.error(error);
            callback(error);
            return;
        }

        if (packages.length === 0) {
            npm.getLatestVersion(packageName, function(error, version) {
                var timeStamp = new Date().toUTCString();
                db.createPackage(packageName, version, timeStamp);
                cacheIt(packageName, version, timeStamp, false, callback);
            });
            return;
        }

        // TODO: is this needed, when there's a cache?
        var pack = packages[0];
        if (isStillValid(pack.timestamp)) {
            cacheIt(packageName, pack.version, pack.timeStamp, false, callback);
            return;
        }

        npm.getLatestVersion(packageName, function(error, version) {
            var timeStamp = new Date().toUTCString();
            db.updatePackageByName(packageName, version, timeStamp);
            var isNewRelease = semver.gt(version, pack.version);
            cacheIt(packageName, version, timeStamp, isNewRelease, callback);
        });
    });
}
<|endoftext|>


<commit_before>
;(function(window) {
  function Painter(el) {
    if (!(this instanceof Painter)) return new Painter(el);
    if (!el) throw new Error('A HTML Canvas element is required to operate on');
    this.el = el;
    this.ctx = el.getContext('2d');
    this.inProgress = false;
    this.eventManager = EventManager(this.el, this);
    this.attachEvents();
  }

  Painter.prototype.attachEvents = function() {
    this.eventManager.bind('touchstart', this.start);
    this.eventManager.bind('touchmove', this.paint);
    this.eventManager.bind('touchend', this.stop);
    this.eventManager.bind('mousedown', this.start);
    this.eventManager.bind('mousemove', this.paint);
    this.eventManager.bind('mouseup', this.stop);
    return this;
  };

  Painter.prototype.start = function(e) {
    e.preventDefault();
    var x = e.x || e.touches[0].pageX
      , y = e.y || e.touches[0].pageY;

    this.ctx.strokeStyle = "rgb(200,0,0)";
    this.inProgress = true;
    this.ctx.beginPath();
    this.ctx.moveTo(x, y);
    return this;
  };

  Painter.prototype.paint = function(e) {
    e.preventDefault();
    var x = e.x || e.touches[0].pageX
      , y = e.y || e.touches[0].pageY;

    if (this.inProgress) {
      this.ctx.lineTo(x, y);
      this.ctx.stroke();
    }

    return this;
  };

  Painter.prototype.stop = function() {
    this.ctx.closePath();
    this.inProgress = false;
    return this;
  };

  Painter.prototype.save = function() {
    this.ctx.save();
    return this;
  };

  Painter.prototype.restore = function() {
    this.ctx.restore();
    return this;
  };

  Painter.prototype.finish = function() {
    this.eventManager.unbind('mousedown', this.start);
    this.eventManager.unbind('mousemove', this.paint);
    this.eventManager.unbind('mouseup', this.stop);
    this.eventManager.unbind('touchstart', this.start);
    this.eventManager.unbind('touchmove', this.paint);
    this.eventManager.unbind('touchend', this.stop);
    return this;
  };

  window.Painter = Painter;
})(window);
<commit_msg>Add pub sub to painter<commit_after>
;(function(window) {
  function Painter(el, node) {
    if (!(this instanceof Painter)) return new Painter(el);
    if (!el) throw new Error('A HTML Canvas element is required to operate on');
    this.el = el;
    this.ctx = el.getContext('2d');
    this.inProgress = false;
    this.eventManager = EventManager(this.el, this);
    this.node = node;
    this.attachEvents();
    this.subscribe();
  }

  Painter.prototype.attachEvents = function() {
    this.eventManager.bind('touchstart', this.start);
    this.eventManager.bind('mousedown', this.start);
    this.eventManager.bind('touchmove', this.paint);
    this.eventManager.bind('mousemove', this.paint);
    this.eventManager.bind('touchend', this.stop);
    this.eventManager.bind('mouseup', this.stop);
    return this;
  };

  Painter.prototype.start = function(e, x, y) {
    var x = x || e.x || e.touches[0].pageX
      , y = y || e.y || e.touches[0].pageY;

    e && e.preventDefault();

    this.ctx.strokeStyle = "rgb(200,0,0)";
    this.inProgress = true;
    this.ctx.beginPath();
    this.ctx.moveTo(x, y);
    this.publish('start', x, y);
    return this;
  };

  Painter.prototype.paint = function(e, x, y) {
    var x = x || e.x || e.touches[0].pageX
      , y = y || e.y || e.touches[0].pageY;

    e && e.preventDefault();

    if (this.inProgress) {
      this.ctx.lineTo(x, y);
      this.ctx.stroke();
      this.publish('paint', x, y);
    }

    return this;
  };

  Painter.prototype.stop = function() {
    this.ctx.closePath();
    this.inProgress = false;
    this.publish('stop', null, null);
    return this;
  };

  Painter.prototype.save = function() {
    this.ctx.save();
    return this;
  };

  Painter.prototype.restore = function() {
    this.ctx.restore();
    return this;
  };

  Painter.prototype.finish = function() {
    this.eventManager.unbind('mousedown', this.start);
    this.eventManager.unbind('mousemove', this.paint);
    this.eventManager.unbind('mouseup', this.stop);
    this.eventManager.unbind('touchstart', this.start);
    this.eventManager.unbind('touchmove', this.paint);
    this.eventManager.unbind('touchend', this.stop);
    return this;
  };

  Painter.prototype.publish = function(action, x, y) {
    this.node && this.node.set({ action: action, x: x, y: y });
  };

  Painter.prototype.subscribe = function() {
    var self = this;

    this.node && this.node.on('value', function(snapshot) {
      var data = snapshot.val();

      if ('start' == data.action) {
        self.start(null, data.x, data.y);
      } else if ('paint' == data.action) {
        self.paint(null, data.x, data.y);
      } else {
        self.stop();
      }
    });
  };

  window.Painter = Painter;
})(window);
<|endoftext|>


<commit_before>'use strict';

// package module for different environments
function packageModule(global, name, api) {
  if (global.define && global.define.amd) {
    define([], api);
  } else if (typeof exports !== "undefined") {
    module.exports = api;
  } else {
    global[name] = api;
  }
}

// Storage constructor
function Storage(namespace, storage){
  this._ns = namespace;
  this._nsRegex = new RegExp(''+namespace+'_');
  this._storage = storage;
  this._keyCache = null;
  this.length = this._keys().length;
}

// Generate an namespaced key
Storage.prototype._genKey = function(key){
  return this._ns + '_' + key;
};

// Check if key is in namespace
Storage.prototype._inNamespace = function(key){
  return key && (key.indexOf(this._ns) === 0);
};

// Check if key exists
Storage.prototype._exists = function(key){
  return !!this.getItem(key);
};

// Get all keys in this namespace
Storage.prototype._keys = function(){
  if(this._keyCache){
    return this._keyCache;
  }else{
    var keys = [];
    for(var i=0, len=this._storage.length; i<len; i++) {
      var key = this._storage.key(i);
      if(this._inNamespace(key)) keys.push(key.replace(this._nsRegex, ''));
    }
    this._keyCache = keys;
    return keys;
  }
};

Storage.prototype._invalidateCache = function(){
  this._keyCache = null;
};

//
// STORAGE API
// Spec here: http://dev.w3.org/html5/webstorage/#storage-0
//

// Get the key of index idx
Storage.prototype.key = function(idx){
  return this._keys()[idx] || null;
};

// Get item for key
Storage.prototype.getItem = function(key){
  return this._storage.getItem(this._genKey(key));
};

// Set value of key to val
Storage.prototype.setItem = function(key, val){
  if(!this._exists(key)){
    this.length++;
    this._invalidateCache();
  }
  this._storage.setItem(this._genKey(key), val);
};

// Remove item from storage
Storage.prototype.removeItem = function(key){
  if(this._exists(key)){
    this.length--;
    this._invalidateCache();
  }
  this._storage.removeItem(this._genKey(key));
};

// Clear storage
Storage.prototype.clear = function(){
  var _this = this;
  this._keys().forEach(function(key){
    _this.removeItem(key);
  });
  this._invalidateCache();
};

//
// API
//
var API = {
  createNamespace: function(namespace, storage){
    return new Storage(namespace, storage);
  }
};

// Module packaging
packageModule(this, 'NSStorage', API);
<commit_msg>Added angular module system support<commit_after>(function(global){
  'use strict';
  var NAMESPACE = 'arokor';

  // package module for different environments
  function packageModule(name, api) {
    if (global.define && global.define.amd) {
      define([], api);
    } else if (typeof exports !== "undefined" && typeof module !== "undefined") {
      module.exports = api;
    } else if (global.angular) {
      var ngName = [NAMESPACE, name].join('.');
      angular.module(ngName, [])
        .service(ngName, [
          function () {
              return api;
          }
      ]);
    } else {
      global[name] = api;
    }
  }

  // Storage constructor
  function Storage(namespace, storage){
    this._ns = namespace;
    this._nsRegex = new RegExp(''+namespace+'_');
    this._storage = storage;
    this._keyCache = null;
    this.length = this._keys().length;
  }

  // Generate an namespaced key
  Storage.prototype._genKey = function(key){
    return this._ns + '_' + key;
  };

  // Check if key is in namespace
  Storage.prototype._inNamespace = function(key){
    return key && (key.indexOf(this._ns) === 0);
  };

  // Check if key exists
  Storage.prototype._exists = function(key){
    return !!this.getItem(key);
  };

  // Get all keys in this namespace
  Storage.prototype._keys = function(){
    if(this._keyCache){
      return this._keyCache;
    }else{
      var keys = [];
      for(var i=0, len=this._storage.length; i<len; i++) {
        var key = this._storage.key(i);
        if(this._inNamespace(key)) keys.push(key.replace(this._nsRegex, ''));
      }
      this._keyCache = keys;
      return keys;
    }
  };

  Storage.prototype._invalidateCache = function(){
    this._keyCache = null;
  };

  //
  // STORAGE API
  // Spec here: http://dev.w3.org/html5/webstorage/#storage-0
  //

  // Get the key of index idx
  Storage.prototype.key = function(idx){
    return this._keys()[idx] || null;
  };

  // Get item for key
  Storage.prototype.getItem = function(key){
    return this._storage.getItem(this._genKey(key));
  };

  // Set value of key to val
  Storage.prototype.setItem = function(key, val){
    if(!this._exists(key)){
      this.length++;
      this._invalidateCache();
    }
    this._storage.setItem(this._genKey(key), val);
  };

  // Remove item from storage
  Storage.prototype.removeItem = function(key){
    if(this._exists(key)){
      this.length--;
      this._invalidateCache();
    }
    this._storage.removeItem(this._genKey(key));
  };

  // Clear storage
  Storage.prototype.clear = function(){
    var _this = this;
    this._keys().forEach(function(key){
      _this.removeItem(key);
    });
    this._invalidateCache();
  };

  //
  // API
  //
  var API = {
    createNamespace: function(namespace, storage){
      return new Storage(namespace, storage);
    }
  };

  // Module packaging
  packageModule('NSStorage', API);
})(this);
<|endoftext|>