<commit_before>// Uses AMD or browser globals to create a module.

// Grabbed from https://github.com/umdjs/umd/blob/master/amdWeb.js.
// Check out https://github.com/umdjs/umd for more patterns.

// Defines a module "cart".
// Note that the name of the module is implied by the file name. It is best
// if the file name and the exported global have matching names.

// If you do not want to support the browser global path, then you
// can remove the `root` use and the passing `this` as the first arg to
// the top function.

(function (root, factory) {
  'use strict';
  if (typeof define === 'function' && define.amd) {
    define([], function() {
      throw new Error('FIXME: inject the correct EventEmitter');
      return factory();
    });
  }
  else if (typeof module !== 'undefined' && module.exports && require) {
    module.exports = factory(require('../bower_components/eventemitter2/index.js').EventEmitter2);
  }
  else {
    root.Cart = factory(root.EventEmitter2);
  }
}(this, function (EventEmitter) {
  'use strict';

  var _uid = 0
    , UNSIGNED_PRODUCT = null;

  function toArray(arr, singleArgArray) {
    if (singleArgArray && 1 === arr.length && Array.isArray(arr[0])) { // single item arguments that is array
      return arr[0].slice();
    }
    else if (Array.isArray(arr)) {
      return arr.slice();
    }
    else if (typeof arr === 'object' && !!arr && 'length' in arr) { // duck. object, not null, has length property
      return Array.prototype.slice.call(arr);
    }
    else {
      return [arr];
    }
  }

  // http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
  function hashCode(s) {
    var hash = 0
      , strlen = s.length
      , i, c;
    if (0 === strlen) {
      return hash;
    }
    for (i = 0; i < strlen; i++) {
      c = s.charCodeAt(i);
      hash = ((hash << 5) - hash) + c;
      hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
  }

  function Item(data) {
    data = data || {};

    var id, product, price, signature, properties, quantity;
    id          = 'id' in data ? data.id : ++_uid;
    product     = 'product' in data ? data.product : product;
    price       = 'price' in data ? data.price : Number.MAX_VALUE;
    quantity    = 'quantity' in data ? data.quantity : 1;
    signature   = 'signature' in data ? data.signature : UNSIGNED_PRODUCT;
    properties  = 'properties' in data ? data.properties : {};

    Object.defineProperties(this, {
      id: {
        get: function() {
          return id;
        }
      },

      product: {
        get: function() {
          return product;
        }
      },

      price: {
        get: function() {
          return price;
        },
        set: function(value) {
          if (this.locked) {
            throw new Error('Cannot set price because cart is locked');
          }
          if (signature !== UNSIGNED_PRODUCT) {
            throw new Error('Cannot modify price of signed product');
          }
          price = value;
          this.trigger('price', value);
          this.trigger('total');
          this.trigger('change');
        }
      },

      signature: {
        get: function() {
          return signature;
        }
      },

      quantity: {
        get: function() {
          return quantity;
        },
        set: function(value) {
          if (this.locked) {
            throw new Error('Cannot set quantity because cart is locked');
          }
          quantity = value;
          this.trigger('quantity', value);
          this.trigger('total');
          this.trigger('change');
        }
      },

      properties: {
        get: function() {
          return Object.create(properties);
        }
      },

      property: {
        value: function(key, value) {
          switch (arguments.length) {
            case 1:
              return properties[key];
            case 2:
              if (this.locked) {
                throw new Error('Cannot set property because cart is locked');
              }
              var prev = properties[key];
              properties[key] = value;
              this.trigger('property:change', key, value, prev);
              this.trigger('change');
              return this;
            default:
              throw new Error('Invalid argument length');
          }
        }
      },

      subtotal: {
        get: function() {
          return this.price * this.quantity;
        }
      },
    });

    var _locked = false;
    Object.defineProperty(this, 'locked', {
      get: function() {
        return _locked;
      }
    });
    Object.defineProperty(this, 'lock', {
      value: function(isLocked) {
        if (typeof isLocked === 'boolean') {
          if (_locked !== isLocked) {
            _locked = isLocked;
            this.trigger(_locked ? 'lock' : 'unlock');
          }
        }
        else {
          throw new Error('Invalid lock value');
        }
      }
    });
  }

  Item.prototype = Object.create(EventEmitter.prototype);
  Item.prototype.constructor = Item;

  // delay event emits
  Item.prototype.trigger = function() {
    var _this = this
      , args = arguments;
    setTimeout(function() {
      _this.emit.apply(_this, args);
    }, 0);
  };

  Item.prototype.toJSON = function() {
    return {
        product: this.product
      , price: this.price
      , signature: this.signature
      , subtotal: this.subtotal
      , properties: this.properties
    };
  };

  function Cart(items, options) {
    var _this = this;
    if (!Array.isArray(items)) {
      options = items;
      items = null;
    }

    this.options = {
      // unique ID for the current store
      store: 'store',

      // user ID
      user: 'guest',

      meta: {},

      // create a signature for current cart
      signer: function(cart) {
        var itemsAsStr = _this._items.map(function(item) {
          return [ item.product, item.price, item.signature, item.quantity ].join(':');
        }).join('|');
        return hashCode([ _this.store, _this.user, itemsAsStr ].join(';'));
      },

      // payment processor strategy
      paymentDriver: function(cart, callback) {
        callback(new Error('No payment processor strategy provided'));
      }
    };

    options = options || {};
    for (var k in options) {
      if (k in this.options) {
        this.options[k] = options[k];
      }
      else {
        throw new Error('Invalid Cart option: ' + k);
      }
    }
    Object.freeze(this.options);

    this._items = !Array.isArray(items) ? [] : items.map(function(element) {
      return element instanceof Item ? element : new Item(element);
    });

    Object.defineProperty(this, 'total', {
      get: function() {
        return !this._items.length ? 0 : this._items.reduce(function(prev, cur) {
          return prev + cur.subtotal;
        }, 0);
      }
    });

    Object.defineProperty(this, 'count', {
      get: function() {
        return this._items.length;
      }
    });

    Object.defineProperty(this, 'signature', {
      get: function() {
        try {
          return this.options.signer(this);
        }
        catch (err) {
          this.trigger('error', new Error('Cart signer threw an error'));
          throw err;
        }
      }
    });

    var _locked = false;
    Object.defineProperty(this, 'locked', {
      get: function() {
        return _locked;
      }
    });
    Object.defineProperty(this, 'lock', {
      value: function(isLocked) {
        if (typeof isLocked === 'boolean') {
          if (_locked !== isLocked) {
            _locked = isLocked;
            this._items.forEach(function(item) {
              item.lock(_locked);
            });
            this.trigger(_locked ? 'lock' : 'unlock');
          }
        }
        else {
          throw new Error('Invalid lock value');
        }
      }
    });
  }

  Cart.prototype = Object.create(EventEmitter.prototype);
  Cart.prototype.constructor = Cart;

  // delay event emits
  Cart.prototype.trigger = function() {
    var _this = this
      , args = arguments;
    setTimeout(function() {
      _this.emit.apply(_this, args);
    }, 0);
  };

  Cart.prototype.itemAt = function(index) {
    return this._items[index];
  };

  Cart.prototype._watchItem = function(item) {
    var _this = this;
    item
      .on('error', function(err) {
        _this.trigger('item:error', err, this);
        _this.trigger('error', err);
      })
      .on('change', function() {
        _this.trigger('item:change', this);
        _this.trigger('change');
      })
      .on('total', function() {
        _this.trigger('item:total', this);
        _this.trigger('total');
      });
    return this;
  };

  Cart.prototype.add = function() {
    if (this.locked) {
      throw new Error('Cannot add because cart is locked');
    }
    var additions = toArray(arguments, true)
      , addition
      , item;
    if (additions.length) {
      for (var i=0; i < additions.length; i++) {
        addition = additions[i];
        item = addition instanceof Item ? addition : new Item(addition);
        if (this._items.indexOf(item) < 0) {
          this._items.push(item);
          this._watchItem(item);
          this.trigger('item:add', item);
          this.trigger('change');
        }
        else {
          this.trigger('error', new Error('Attempting to add an item that already exists in cart'), item);
        }
      }
      this.trigger('count');
      this.trigger('total');
    }
    return this;
  };

  Cart.prototype.remove = function() {
    if (this.locked) {
      throw new Error('Cannot remove because cart is locked');
    }
    var removals = toArray(arguments, true)
      , removal
      , item;
    if (removals.length) {
      for (var i=0; i < removals.length; i++) {
        removal = removals[i];
        item = removal instanceof Item ? removal : this.find(removal);
        if (item) {
          this._items.splice(this._items.indexOf(item), 1);
          this.trigger('item:remove', item);
          this.trigger('change');
        }
        else {
          this.trigger('error', new Error('Item "' + removal + '" was not found in cart'));
        }
      }
      this.trigger('count');
      this.trigger('total');
    }
    return this;
  };

  Cart.prototype.removeIndex = function(index) {
    var item = this._items[index];
    if (item) {
      this.remove(item);
    }
    return this;
  };

  Cart.prototype.findBy = function(property, value) {
    for (var i=0; i < this._items.length; i++) {
      if (this._items[i][property] === value) {
        return this._items[i];
      }
    }
    return null;
  };

  Cart.prototype.find = function(id) {
    return this.findBy('id', id);
  };

  Cart.prototype.clear = function() {
    Cart.prototype.remove.apply(this, this._items);
    this.trigger('clear');
    return this;
  };

  Cart.prototype.purchase = function(callback) {
    if (this.locked) {
      throw new Error('Cannot purchase because cart is locked');
    }
    var _this = this
      , wrappedCallback;
    callback = callback || function(){};
    wrappedCallback = function() {
      callback.apply(this, arguments);
      callback = function() {
        _this.trigger('error', new Error('Purchase callback already called'));
      };
    }
    if (this._items.length) {
      this.lock(true);
      this.trigger('purchasing');
      try {
        this.options.paymentDriver(this, function(err, success) {
          _this.lock(false);
          wrappedCallback(err, success);
          if (err) {
            _this.trigger('error', err);
            return;
          }
          _this.trigger('purchase', success);
        });
      }
      catch(err) {
        this.trigger('error', new Error('Payment driver lead to error'));
        this.lock(false);
        wrappedCallback(err);
        throw err;
      }
    }
    else {
      var emptyErr = new Error('Cannot purchase because cart is empty');
      wrappedCallback(emptyErr);
      this.trigger('error', emptyErr);
    }
    return this;
  };

  Cart.prototype.toJSON = function() {
    var opts = {};
    for (var k in this.options) {
      var val = this.options[k];
      if (typeof val !== 'function') {
        opts[k] = val;
      }
    }
    opts.total = this.total;
    opts.signature = this.signature;
    opts.meta = this.options.meta;
    opts.items = this._items.map(Function.prototype.call, Item.prototype.toJSON);
    return opts;
  };

  Cart.from = function(json, signer, paymentDriver) {
    var options = {
      store: json.store,
      user: json.user,
      meta: json.meta
    };
    if (signer) {
      options.signer = signer;
    }
    else if (json.signer) {
      options.signer = json.signer;
    }
    if (paymentDriver) {
      options.paymentDriver = paymentDriver;
    }
    else if (json.paymentDriver) {
      options.paymentDriver = json.paymentDriver;
    }
    return new Cart(json.items, options);
  };

  Cart.Item = Item;

  Cart.utils = {
    toArray: toArray,
  };

  return Cart;
}));
<commit_msg>dupe item mode and fix auto product id<commit_after>// Uses AMD or browser globals to create a module.

// Grabbed from https://github.com/umdjs/umd/blob/master/amdWeb.js.
// Check out https://github.com/umdjs/umd for more patterns.

// Defines a module "cart".
// Note that the name of the module is implied by the file name. It is best
// if the file name and the exported global have matching names.

// If you do not want to support the browser global path, then you
// can remove the `root` use and the passing `this` as the first arg to
// the top function.

(function (root, factory) {
  'use strict';
  if (typeof define === 'function' && define.amd) {
    define([], function() {
      throw new Error('FIXME: inject the correct EventEmitter');
      return factory();
    });
  }
  else if (typeof module !== 'undefined' && module.exports && require) {
    module.exports = factory(require('../bower_components/eventemitter2/index.js').EventEmitter2);
  }
  else {
    root.Cart = factory(root.EventEmitter2);
  }
}(this, function (EventEmitter) {
  'use strict';

  // TODO: handle updating quantity if dupe item type passed.  maybe option to throw/update

  var _uid = 0
    , UNSIGNED_PRODUCT = null;

  function toArray(arr, singleArgArray) {
    if (singleArgArray && 1 === arr.length && Array.isArray(arr[0])) { // single item arguments that is array
      return arr[0].slice();
    }
    else if (Array.isArray(arr)) {
      return arr.slice();
    }
    else if (typeof arr === 'object' && !!arr && 'length' in arr) { // duck. object, not null, has length property
      return Array.prototype.slice.call(arr);
    }
    else {
      return [arr];
    }
  }

  // http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
  function hashCode(s) {
    var hash = 0
      , strlen = s.length
      , i, c;
    if (0 === strlen) {
      return hash;
    }
    for (i = 0; i < strlen; i++) {
      c = s.charCodeAt(i);
      hash = ((hash << 5) - hash) + c;
      hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
  }

  function Item(data) {
    data = data || {};

    var id, product, price, signature, properties, quantity;
    id          = 'id' in data ? data.id : ++_uid;
    product     = 'product' in data ? data.product : id;
    price       = 'price' in data ? data.price : Number.MAX_VALUE;
    quantity    = 'quantity' in data ? data.quantity : 1;
    signature   = 'signature' in data ? data.signature : UNSIGNED_PRODUCT;
    properties  = 'properties' in data ? data.properties : {};

    Object.defineProperties(this, {
      id: {
        get: function() {
          return id;
        }
      },

      product: {
        get: function() {
          return product;
        }
      },

      price: {
        get: function() {
          return price;
        },
        set: function(value) {
          if (this.locked) {
            throw new Error('Cannot set price because cart is locked');
          }
          if (signature !== UNSIGNED_PRODUCT) {
            throw new Error('Cannot modify price of signed product');
          }
          price = value;
          this.trigger('price', value);
          this.trigger('total');
          this.trigger('change');
        }
      },

      signature: {
        get: function() {
          return signature;
        }
      },

      quantity: {
        get: function() {
          return quantity;
        },
        set: function(value) {
          if (this.locked) {
            throw new Error('Cannot set quantity because cart is locked');
          }
          quantity = value;
          this.trigger('quantity', value);
          this.trigger('total');
          this.trigger('change');
        }
      },

      properties: {
        get: function() {
          return Object.create(properties);
        }
      },

      property: {
        value: function(key, value) {
          switch (arguments.length) {
            case 1:
              return properties[key];
            case 2:
              if (this.locked) {
                throw new Error('Cannot set property because cart is locked');
              }
              var prev = properties[key];
              properties[key] = value;
              this.trigger('property:change', key, value, prev);
              this.trigger('change');
              return this;
            default:
              throw new Error('Invalid argument length');
          }
        }
      },

      subtotal: {
        get: function() {
          return this.price * this.quantity;
        }
      },
    });

    var _locked = false;
    Object.defineProperty(this, 'locked', {
      get: function() {
        return _locked;
      }
    });
    Object.defineProperty(this, 'lock', {
      value: function(isLocked) {
        if (typeof isLocked === 'boolean') {
          if (_locked !== isLocked) {
            _locked = isLocked;
            this.trigger(_locked ? 'lock' : 'unlock');
          }
        }
        else {
          throw new Error('Invalid lock value');
        }
      }
    });
  }

  Item.prototype = Object.create(EventEmitter.prototype);
  Item.prototype.constructor = Item;

  // delay event emits
  Item.prototype.trigger = function() {
    var _this = this
      , args = arguments;
    setTimeout(function() {
      _this.emit.apply(_this, args);
    }, 0);
  };

  Item.prototype.toJSON = function() {
    return {
        product: this.product
      , price: this.price
      , quantity: this.quantity
      , signature: this.signature
      , subtotal: this.subtotal
      , properties: this.properties
    };
  };

  function Cart(items, options) {
    var _this = this;
    if (!Array.isArray(items)) {
      options = items;
      items = null;
    }

    this.options = {
      // unique ID for the current store
      store: 'store',

      // user ID
      user: 'guest',

      meta: {},

      // if adding a product that already exists, how should it be handled:
      //  - add: dupe item quantity should be added to current item quantity
      //  - error: do noting and emit an error
      //  - allow: allow dupe items to exist
      dupeItemMode: 'error',

      // create a signature for current cart
      signer: function(cart) {
        var itemsAsStr = _this._items.map(function(item) {
          return [ item.product, item.price, item.signature, item.quantity ].join(':');
        }).join('|');
        return hashCode([ _this.store, _this.user, itemsAsStr ].join(';'));
      },

      // payment processor strategy
      paymentDriver: function(cart, callback) {
        callback(new Error('No payment processor strategy provided'));
      }
    };

    options = options || {};
    for (var k in options) {
      if (k in this.options) {
        this.options[k] = options[k];
      }
      else {
        throw new Error('Invalid Cart option: ' + k);
      }
    }
    Object.freeze(this.options);

    this._items = !Array.isArray(items) ? [] : items.map(function(element) {
      return element instanceof Item ? element : new Item(element);
    });

    Object.defineProperty(this, 'total', {
      get: function() {
        return !this._items.length ? 0 : this._items.reduce(function(prev, cur) {
          return prev + cur.subtotal;
        }, 0);
      }
    });

    Object.defineProperty(this, 'count', {
      get: function() {
        return this._items.length;
      }
    });

    Object.defineProperty(this, 'signature', {
      get: function() {
        try {
          return this.options.signer(this);
        }
        catch (err) {
          this.trigger('error', new Error('Cart signer threw an error'));
          throw err;
        }
      }
    });

    var _locked = false;
    Object.defineProperty(this, 'locked', {
      get: function() {
        return _locked;
      }
    });
    Object.defineProperty(this, 'lock', {
      value: function(isLocked) {
        if (typeof isLocked === 'boolean') {
          if (_locked !== isLocked) {
            _locked = isLocked;
            this._items.forEach(function(item) {
              item.lock(_locked);
            });
            this.trigger(_locked ? 'lock' : 'unlock');
          }
        }
        else {
          throw new Error('Invalid lock value');
        }
      }
    });
  }

  Cart.prototype = Object.create(EventEmitter.prototype);
  Cart.prototype.constructor = Cart;

  // delay event emits
  Cart.prototype.trigger = function() {
    var _this = this
      , args = arguments;
    setTimeout(function() {
      _this.emit.apply(_this, args);
    }, 0);
  };

  Cart.prototype.itemAt = function(index) {
    return this._items[index];
  };

  Cart.prototype._watchItem = function(item) {
    var _this = this;
    item
      .on('error', function(err) {
        _this.trigger('item:error', err, this);
        _this.trigger('error', err);
      })
      .on('change', function() {
        _this.trigger('item:change', this);
        _this.trigger('change');
      })
      .on('total', function() {
        _this.trigger('item:total', this);
        _this.trigger('total');
      });
    return this;
  };

  Cart.prototype.add = function() {
    if (this.locked) {
      throw new Error('Cannot add because cart is locked');
    }
    var additions = toArray(arguments, true)
      , addition
      , item;
    if (additions.length) {
      for (var i=0; i < additions.length; i++) {
        addition = additions[i];
        item = addition instanceof Item ? addition : new Item(addition);
        if (this._items.indexOf(item) < 0) {
          var dupe = this.findBy('product', item.product);
          if (dupe) {
            switch (this.options.dupeItemMode) {
              default:
              case 'error':
                this.trigger('error', new Error('Duplicate product exists and dupeItemMode is set to error'), item, dupe);
                continue;
              case 'add':
                dupe.quantity += item.quantity;
                continue;
              case 'allow':
                // do nothing, let it be added
              break;
            }
          }
          this._items.push(item);
          this._watchItem(item);
          this.trigger('item:add', item);
          this.trigger('change');
        }
        else {
          this.trigger('error', new Error('Attempting to add an item that already exists in cart'), item);
        }
      }
      this.trigger('count');
      this.trigger('total');
    }
    return this;
  };

  Cart.prototype.remove = function() {
    if (this.locked) {
      throw new Error('Cannot remove because cart is locked');
    }
    var removals = toArray(arguments, true)
      , removal
      , item;
    if (removals.length) {
      for (var i=0; i < removals.length; i++) {
        removal = removals[i];
        item = removal instanceof Item ? removal : this.find(removal);
        if (item) {
          this._items.splice(this._items.indexOf(item), 1);
          this.trigger('item:remove', item);
          this.trigger('change');
        }
        else {
          this.trigger('error', new Error('Item "' + removal + '" was not found in cart'));
        }
      }
      this.trigger('count');
      this.trigger('total');
    }
    return this;
  };

  Cart.prototype.removeIndex = function(index) {
    var item = this._items[index];
    if (item) {
      this.remove(item);
    }
    return this;
  };

  Cart.prototype.findBy = function(property, value) {
    for (var i=0; i < this._items.length; i++) {
      if (this._items[i][property] === value) {
        return this._items[i];
      }
    }
    return null;
  };

  Cart.prototype.find = function(id) {
    return this.findBy('id', id);
  };

  Cart.prototype.clear = function() {
    Cart.prototype.remove.apply(this, this._items);
    this.trigger('clear');
    return this;
  };

  Cart.prototype.purchase = function(callback) {
    if (this.locked) {
      throw new Error('Cannot purchase because cart is locked');
    }
    var _this = this
      , wrappedCallback;
    callback = callback || function(){};
    wrappedCallback = function() {
      callback.apply(this, arguments);
      callback = function() {
        _this.trigger('error', new Error('Purchase callback already called'));
      };
    }
    if (this._items.length) {
      this.lock(true);
      this.trigger('purchasing');
      try {
        this.options.paymentDriver(this, function(err, success) {
          _this.lock(false);
          wrappedCallback(err, success);
          if (err) {
            _this.trigger('error', err);
            return;
          }
          _this.trigger('purchase', success);
        });
      }
      catch(err) {
        this.trigger('error', new Error('Payment driver lead to error'));
        this.lock(false);
        wrappedCallback(err);
        throw err;
      }
    }
    else {
      var emptyErr = new Error('Cannot purchase because cart is empty');
      wrappedCallback(emptyErr);
      this.trigger('error', emptyErr);
    }
    return this;
  };

  Cart.prototype.toJSON = function() {
    var opts = {};
    for (var k in this.options) {
      var val = this.options[k];
      if (typeof val !== 'function') {
        opts[k] = val;
      }
    }
    opts.total = this.total;
    opts.signature = this.signature;
    opts.meta = this.options.meta;
    opts.items = this._items.map(Function.prototype.call, Item.prototype.toJSON);
    return opts;
  };

  Cart.from = function(json, signer, paymentDriver) {
    var options = {
      store: json.store,
      user: json.user,
      meta: json.meta
    };
    if (signer) {
      options.signer = signer;
    }
    else if (json.signer) {
      options.signer = json.signer;
    }
    if (paymentDriver) {
      options.paymentDriver = paymentDriver;
    }
    else if (json.paymentDriver) {
      options.paymentDriver = json.paymentDriver;
    }
    return new Cart(json.items, options);
  };

  Cart.Item = Item;

  Cart.utils = {
    toArray: toArray,
  };

  return Cart;
}));
<|endoftext|>


<commit_before>// Use this file to change prototype configuration.

// Note: prototype config can be overridden using environment variables (eg on heroku)

module.exports = {

  // Service name used in header. Eg: 'Renew your passport'
  serviceName: "Service name goes here",

  // Default port that prototype runs on
  port: '3000',

  // Enable or disable password protection on production
  useAuth: 'true'

};
<commit_msg>Service name<commit_after>// Use this file to change prototype configuration.

// Note: prototype config can be overridden using environment variables (eg on heroku)

module.exports = {

  // Service name used in header. Eg: 'Renew your passport'
  serviceName: "Apply for Employment and Support Allowance",

  // Default port that prototype runs on
  port: '3000',

  // Enable or disable password protection on production
  useAuth: 'true'

};
<|endoftext|>


<commit_before>var sanitizer = require('sanitizer');
var db = require('./db');

var rooms = [{
    name: 'Default',
    online: 0,
    permanent: true,
    messages: []
}];

rooms.find = function (name) {
    return this.filter(function(room) {
        return room.name === name;
    })[0];
};

module.exports = function (app, io) {
    io.sockets.on('start', function start(socket) {
        var session = socket.session,
            user = socket.user,
            room = user.room || 'Default',
            currentRoom = rooms.find(room);

        function leaveRoom() {
            io.sockets.emit('room:online', {
                name: room,
                value: --currentRoom.online
            });
            socket.leave(room);

            if (currentRoom.online == 0 && !currentRoom.permanent) {
                io.sockets.emit('rooms:remove', room);
                rooms.splice(rooms.indexOf(currentRoom), 1);
            }
        }

        socket.emit('rooms:list', rooms.map(function (room) {
            return {
                name: room.name,
                online: room.online,
                pass: !!room.pass
            }
        }));

        if (!currentRoom) {
            room = 'Default';
            currentRoom = rooms.find('Default');
        }
        socket.join(room);
        socket.emit('room:current', room, currentRoom.messages);

        io.sockets.emit('room:online', {
            name: room,
            value: ++currentRoom.online
        });

        socket.on('chat', function (message) {
            var date = new Date();
            message = sanitizer.sanitize(message);
            message = {
                user: session.user,
                text: message,
                date: date
            };
            currentRoom.messages.push(message);
            io.sockets.in(room).emit('chat', message);
        });

        socket.on('room:change', function changeRoom(data, cb) {
            var newRoom = rooms.find(data.name);
            if (newRoom.pass && newRoom.pass !== data.pass) {
                return cb('Wrong password');
            }
            leaveRoom();
            room = data.name;
            currentRoom = newRoom;
            socket.join(room);
            io.sockets.emit('room:online', {
                name: room,
                value: ++currentRoom.online
            });
            cb(currentRoom.messages);
        });

        socket.on('room:create', function (newRoom, cb) {
            if (!newRoom.name.trim()) {
                return cb('Name must not be empty!');
            }
            if (rooms.find(newRoom.name)) {
                return cb('This room already exists!');
            }
            newRoom.online = 0;
            newRoom.messages = [];
            rooms.push(newRoom);
            io.sockets.emit('rooms:new', {
                name: newRoom.name,
                online: newRoom.online,
                pass: !!newRoom.pass
            });
            cb('ok');
        });

        socket.on('disconnect', leaveRoom);
    });
};
<commit_msg>Do not allow empty messages<commit_after>var sanitizer = require('sanitizer');
var db = require('./db');

var rooms = [{
    name: 'Default',
    online: 0,
    permanent: true,
    messages: []
}];

rooms.find = function (name) {
    return this.filter(function(room) {
        return room.name === name;
    })[0];
};

module.exports = function (app, io) {
    io.sockets.on('start', function start(socket) {
        var session = socket.session,
            user = socket.user,
            room = user.room || 'Default',
            currentRoom = rooms.find(room);

        function leaveRoom() {
            io.sockets.emit('room:online', {
                name: room,
                value: --currentRoom.online
            });
            socket.leave(room);

            if (currentRoom.online == 0 && !currentRoom.permanent) {
                io.sockets.emit('rooms:remove', room);
                rooms.splice(rooms.indexOf(currentRoom), 1);
            }
        }

        socket.emit('rooms:list', rooms.map(function (room) {
            return {
                name: room.name,
                online: room.online,
                pass: !!room.pass
            }
        }));

        if (!currentRoom) {
            room = 'Default';
            currentRoom = rooms.find('Default');
        }
        socket.join(room);
        socket.emit('room:current', room, currentRoom.messages);

        io.sockets.emit('room:online', {
            name: room,
            value: ++currentRoom.online
        });

        socket.on('chat', function (message) {
            if (!trim(message)) return;

            var date = new Date();
            message = sanitizer.sanitize(message);
            message = {
                user: session.user,
                text: message,
                date: date
            };
            currentRoom.messages.push(message);
            io.sockets.in(room).emit('chat', message);
        });

        socket.on('room:change', function changeRoom(data, cb) {
            var newRoom = rooms.find(data.name);
            if (newRoom.pass && newRoom.pass !== data.pass) {
                return cb('Wrong password');
            }
            leaveRoom();
            room = data.name;
            currentRoom = newRoom;
            socket.join(room);
            io.sockets.emit('room:online', {
                name: room,
                value: ++currentRoom.online
            });
            cb(currentRoom.messages);
        });

        socket.on('room:create', function (newRoom, cb) {
            if (!newRoom.name.trim()) {
                return cb('Name must not be empty!');
            }
            if (rooms.find(newRoom.name)) {
                return cb('This room already exists!');
            }
            newRoom.online = 0;
            newRoom.messages = [];
            rooms.push(newRoom);
            io.sockets.emit('rooms:new', {
                name: newRoom.name,
                online: newRoom.online,
                pass: !!newRoom.pass
            });
            cb('ok');
        });

        socket.on('disconnect', leaveRoom);
    });
};
<|endoftext|>


<commit_before>goog.provide('ol.geom.flat.intersectsextent');

goog.require('ol.extent');
goog.require('ol.geom.flat.contains');
goog.require('ol.geom.flat.segments');

/**
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 * @param {number} offset Offset.
 * @param {number} end End.
 * @param {number} stride Stride.
 * @param {ol.Extent} extent Extent.
 * @return {boolean} True if the geometry and the extent intersect.
 */
ol.geom.flat.intersectsextent.lineString = function(flatCoordinates, offset, end, stride, extent) {
  var coordinatesExtent = ol.extent.extendFlatCoordinates(
      ol.extent.createEmpty(), flatCoordinates, offset, end, stride);
  if (!ol.extent.intersects(extent, coordinatesExtent)) {
    return false;
  }
  if (ol.extent.containsExtent(extent, coordinatesExtent)) {
    return true;
  }
  if (coordinatesExtent[0] >= extent[0] &&
      coordinatesExtent[2] <= extent[2]) {
    return true;
  }
  if (coordinatesExtent[1] >= extent[1] &&
      coordinatesExtent[3] <= extent[3]) {
    return true;
  }
  return ol.geom.flat.segments.forEach(flatCoordinates, offset, end, stride,
      /**
       * @param {ol.Coordinate} point1 Start point.
       * @param {ol.Coordinate} point2 End point.
       * @return {boolean} `true` if the segment and the extent intersect,
       *     `false` otherwise.
       */
      function(point1, point2) {
        return ol.extent.intersectsSegment(extent, point1, point2);
      });
};

/**
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 * @param {number} offset Offset.
 * @param {Array.<number>} ends Ends.
 * @param {number} stride Stride.
 * @param {ol.Extent} extent Extent.
 * @return {boolean} True if the geometry and the extent intersect.
 */
ol.geom.flat.intersectsextent.lineStrings = function(flatCoordinates, offset, ends, stride, extent) {
  var i, ii;
  for (i = 0, ii = ends.length; i < ii; ++i) {
    if (ol.geom.flat.intersectsextent.lineString(
        flatCoordinates, offset, ends[i], stride, extent)) {
      return true;
    }
    offset = ends[i];
  }
  return false;
};

/**
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 * @param {number} offset Offset.
 * @param {number} end End.
 * @param {number} stride Stride.
 * @param {ol.Extent} extent Extent.
 * @return {boolean} True if the geometry and the extent intersect.
 */
ol.geom.flat.intersectsextent.linearRing = function(flatCoordinates, offset, end, stride, extent) {
  if (ol.geom.flat.intersectsextent.lineString(
      flatCoordinates, offset, end, stride, extent)) {
    return true;
  }
  if (ol.geom.flat.contains.linearRingContainsXY(
      flatCoordinates, offset, end, stride, extent[0], extent[1])) {
    return true;
  }
  if (ol.geom.flat.contains.linearRingContainsXY(
      flatCoordinates, offset, end, stride, extent[0], extent[3])) {
    return true;
  }
  if (ol.geom.flat.contains.linearRingContainsXY(
      flatCoordinates, offset, end, stride, extent[2], extent[1])) {
    return true;
  }
  if (ol.geom.flat.contains.linearRingContainsXY(
      flatCoordinates, offset, end, stride, extent[2], extent[3])) {
    return true;
  }
  return false;
};

/**
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 * @param {number} offset Offset.
 * @param {Array.<number>} ends Ends.
 * @param {number} stride Stride.
 * @param {ol.Extent} extent Extent.
 * @return {boolean} True if the geometry and the extent intersect.
 */
ol.geom.flat.intersectsextent.linearRings = function(flatCoordinates, offset, ends, stride, extent) {
  ol.DEBUG && console.assert(ends.length > 0, 'ends should not be an empty array');
  if (!ol.geom.flat.intersectsextent.linearRing(
      flatCoordinates, offset, ends[0], stride, extent)) {
    return false;
  }
  if (ends.length === 1) {
    return true;
  }
  var i, ii;
  for (i = 1, ii = ends.length; i < ii; ++i) {
    if (ol.geom.flat.contains.linearRingContainsExtent(
        flatCoordinates, ends[i - 1], ends[i], stride, extent)) {
      return false;
    }
  }
  return true;
};

/**
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 * @param {number} offset Offset.
 * @param {Array.<Array.<number>>} endss Endss.
 * @param {number} stride Stride.
 * @param {ol.Extent} extent Extent.
 * @return {boolean} True if the geometry and the extent intersect.
 */
ol.geom.flat.intersectsextent.linearRingss = function(flatCoordinates, offset, endss, stride, extent) {
  ol.DEBUG && console.assert(endss.length > 0, 'endss should not be an empty array');
  var i, ii;
  for (i = 0, ii = endss.length; i < ii; ++i) {
    var ends = endss[i];
    if (ol.geom.flat.intersectsextent.linearRings(
        flatCoordinates, offset, ends, stride, extent)) {
      return true;
    }
    offset = ends[ends.length - 1];
  }
  return false;
};
<commit_msg>Require ol in ol.geom.flat.intersectsextent<commit_after>goog.provide('ol.geom.flat.intersectsextent');

goog.require('ol');
goog.require('ol.extent');
goog.require('ol.geom.flat.contains');
goog.require('ol.geom.flat.segments');

/**
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 * @param {number} offset Offset.
 * @param {number} end End.
 * @param {number} stride Stride.
 * @param {ol.Extent} extent Extent.
 * @return {boolean} True if the geometry and the extent intersect.
 */
ol.geom.flat.intersectsextent.lineString = function(flatCoordinates, offset, end, stride, extent) {
  var coordinatesExtent = ol.extent.extendFlatCoordinates(
      ol.extent.createEmpty(), flatCoordinates, offset, end, stride);
  if (!ol.extent.intersects(extent, coordinatesExtent)) {
    return false;
  }
  if (ol.extent.containsExtent(extent, coordinatesExtent)) {
    return true;
  }
  if (coordinatesExtent[0] >= extent[0] &&
      coordinatesExtent[2] <= extent[2]) {
    return true;
  }
  if (coordinatesExtent[1] >= extent[1] &&
      coordinatesExtent[3] <= extent[3]) {
    return true;
  }
  return ol.geom.flat.segments.forEach(flatCoordinates, offset, end, stride,
      /**
       * @param {ol.Coordinate} point1 Start point.
       * @param {ol.Coordinate} point2 End point.
       * @return {boolean} `true` if the segment and the extent intersect,
       *     `false` otherwise.
       */
      function(point1, point2) {
        return ol.extent.intersectsSegment(extent, point1, point2);
      });
};

/**
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 * @param {number} offset Offset.
 * @param {Array.<number>} ends Ends.
 * @param {number} stride Stride.
 * @param {ol.Extent} extent Extent.
 * @return {boolean} True if the geometry and the extent intersect.
 */
ol.geom.flat.intersectsextent.lineStrings = function(flatCoordinates, offset, ends, stride, extent) {
  var i, ii;
  for (i = 0, ii = ends.length; i < ii; ++i) {
    if (ol.geom.flat.intersectsextent.lineString(
        flatCoordinates, offset, ends[i], stride, extent)) {
      return true;
    }
    offset = ends[i];
  }
  return false;
};

/**
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 * @param {number} offset Offset.
 * @param {number} end End.
 * @param {number} stride Stride.
 * @param {ol.Extent} extent Extent.
 * @return {boolean} True if the geometry and the extent intersect.
 */
ol.geom.flat.intersectsextent.linearRing = function(flatCoordinates, offset, end, stride, extent) {
  if (ol.geom.flat.intersectsextent.lineString(
      flatCoordinates, offset, end, stride, extent)) {
    return true;
  }
  if (ol.geom.flat.contains.linearRingContainsXY(
      flatCoordinates, offset, end, stride, extent[0], extent[1])) {
    return true;
  }
  if (ol.geom.flat.contains.linearRingContainsXY(
      flatCoordinates, offset, end, stride, extent[0], extent[3])) {
    return true;
  }
  if (ol.geom.flat.contains.linearRingContainsXY(
      flatCoordinates, offset, end, stride, extent[2], extent[1])) {
    return true;
  }
  if (ol.geom.flat.contains.linearRingContainsXY(
      flatCoordinates, offset, end, stride, extent[2], extent[3])) {
    return true;
  }
  return false;
};

/**
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 * @param {number} offset Offset.
 * @param {Array.<number>} ends Ends.
 * @param {number} stride Stride.
 * @param {ol.Extent} extent Extent.
 * @return {boolean} True if the geometry and the extent intersect.
 */
ol.geom.flat.intersectsextent.linearRings = function(flatCoordinates, offset, ends, stride, extent) {
  ol.DEBUG && console.assert(ends.length > 0, 'ends should not be an empty array');
  if (!ol.geom.flat.intersectsextent.linearRing(
      flatCoordinates, offset, ends[0], stride, extent)) {
    return false;
  }
  if (ends.length === 1) {
    return true;
  }
  var i, ii;
  for (i = 1, ii = ends.length; i < ii; ++i) {
    if (ol.geom.flat.contains.linearRingContainsExtent(
        flatCoordinates, ends[i - 1], ends[i], stride, extent)) {
      return false;
    }
  }
  return true;
};

/**
 * @param {Array.<number>} flatCoordinates Flat coordinates.
 * @param {number} offset Offset.
 * @param {Array.<Array.<number>>} endss Endss.
 * @param {number} stride Stride.
 * @param {ol.Extent} extent Extent.
 * @return {boolean} True if the geometry and the extent intersect.
 */
ol.geom.flat.intersectsextent.linearRingss = function(flatCoordinates, offset, endss, stride, extent) {
  ol.DEBUG && console.assert(endss.length > 0, 'endss should not be an empty array');
  var i, ii;
  for (i = 0, ii = endss.length; i < ii; ++i) {
    var ends = endss[i];
    if (ol.geom.flat.intersectsextent.linearRings(
        flatCoordinates, offset, ends, stride, extent)) {
      return true;
    }
    offset = ends[ends.length - 1];
  }
  return false;
};
<|endoftext|>


<commit_before>'use strict';

angular.module('config', [])
  .constant('config', {
    'endpoint'    : "http://"+window.location.hostname+":8080",
    'provider'    : "basic", // google, github, gitlab, keycloak, pingfederate, saml2 or basic
    'client_id'   : "INSERT-CLIENT-ID-HERE",
    'github_url'  : null,  // replace with your enterprise github server
    'gitlab_url'  : "https://gitlab.com",  // replace with your gitlab server
    'keycloak_url': "https://keycloak.example.org",  // replace with your keycloak server
    'keycloak_realm': "master",  // replace with your keycloak realm
    'pingfederate_url' : "https://pingfederate.example.org" // replace with your pingfederate server
    'colors'      : {}, // use default colors
    'severity'    : {}, // use default severity codes
    'audio'       : {}, // no audio
    'tracking_id' : ""  // Google Analytics tracking ID eg. UA-NNNNNN-N
  });
<commit_msg>Add missing comma and fix alignment<commit_after>'use strict';

angular.module('config', [])
  .constant('config', {
    'endpoint'        : "http://"+window.location.hostname+":8080",
    'provider'        : "basic", // google, github, gitlab, keycloak, pingfederate, saml2 or basic
    'client_id'       : "INSERT-CLIENT-ID-HERE",
    'github_url'      : null,  // replace with your enterprise github server
    'gitlab_url'      : "https://gitlab.com",  // replace with your gitlab server
    'keycloak_url'    : "https://keycloak.example.org",  // replace with your keycloak server
    'keycloak_realm'  : "master",  // replace with your keycloak realm
    'pingfederate_url': "https://pingfederate.example.org", // replace with your pingfederate server
    'colors'          : {}, // use default colors
    'severity'        : {}, // use default severity codes
    'audio'           : {}, // no audio
    'tracking_id'     : ""  // Google Analytics tracking ID eg. UA-NNNNNN-N
  });
<|endoftext|>


<commit_before>// Use this file to change prototype configuration.

// Note: prototype config can be overridden using environment variables (eg on heroku)

module.exports = {
  // Service name used in header. Eg: 'Renew your passport'
  serviceName: 'Prove you can apply',

  // Latest release number
  productName: 'V30.0.0',

  // Default port that prototype runs on
  port: '3000',

  // Enable or disable password protection on production
  useAuth: 'true',

  // Automatically stores form data, and send to all views
  useAutoStoreData: 'true',

  // Enable cookie-based session store (persists on restart)
  // Please note 4KB cookie limit per domain, cookies too large will silently be ignored
  useCookieSessionStore: 'true',

  // Enable or disable built-in docs and examples.
  useDocumentation: 'true',

  // Force HTTP to redirect to HTTPS on production
  useHttps: 'true',

  // Cookie warning - update link to service's cookie page.
  cookieText: 'This is a test site – if you’ve arrived at this page by mistake, go to GOV.UK',

  // Enable or disable Browser Sync
  useBrowserSync: 'true'

}
<commit_msg>updated service name to match main build<commit_after>// Use this file to change prototype configuration.

// Note: prototype config can be overridden using environment variables (eg on heroku)

module.exports = {
  // Service name used in header. Eg: 'Renew your passport'
  serviceName: 'Prove you can apply for benefits in the UK',

  // Latest release number
  productName: 'V30.0.0',

  // Default port that prototype runs on
  port: '3000',

  // Enable or disable password protection on production
  useAuth: 'true',

  // Automatically stores form data, and send to all views
  useAutoStoreData: 'true',

  // Enable cookie-based session store (persists on restart)
  // Please note 4KB cookie limit per domain, cookies too large will silently be ignored
  useCookieSessionStore: 'true',

  // Enable or disable built-in docs and examples.
  useDocumentation: 'true',

  // Force HTTP to redirect to HTTPS on production
  useHttps: 'true',

  // Cookie warning - update link to service's cookie page.
  cookieText: 'This is a test site – if you’ve arrived at this page by mistake, go to GOV.UK',

  // Enable or disable Browser Sync
  useBrowserSync: 'true'

}
<|endoftext|>


<commit_before>import path from 'path'
import os from 'os'
import fs from 'fs'

const app = require('app')

const isProduction = process.env.NODE_ENV === 'production'
const IPFS_PATH_FILE = app.getDataPath() + '/ipfs-electron-app-node-path'

const trayIcon = () => {
  if (os.platform() !== 'darwin') {
    return path.resolve(__dirname, '../node_modules/ipfs-logo/ipfs-logo-256-ice.png')
  }

  return path.resolve(__dirname, '../node_modules/ipfs-logo/platform-icons/osx-menu-bar.png')
}

const menuBar = {
  dir: __dirname,
  width: 300,
  height: 400,
  index: isProduction
    ? `file://${__dirname}/menubar.html`
    : 'http://localhost:3000/menubar.html',
  icon: trayIcon(),
  'always-on-top': !isProduction,
  preloadWindow: true,
  resizable: false,
  'web-preferences': {
    'web-security': false
  }
}

const window = {
  icon: path.resolve(__dirname, '../node_modules/ipfs-logo/ipfs-logo-256-ice.png'),
  'auto-hide-menu-bar': true,
  width: 800,
  height: 600,
  'web-preferences': {
    'web-security': false
  }
}

const ipfsPath = () => {
  let pathIPFS
  try {
    pathIPFS = fs.readFileSync(IPFS_PATH_FILE, 'utf-8')
  } catch (e) {
    pathIPFS = process.env.IPFS_PATH ||
      (process.env.HOME || process.env.USERPROFILE) + '/.ipfs'
  }

  return pathIPFS
}

// -- Window URLs

const fileURL = name => `file://${__dirname}/${name}.html`
const serverURL = name => `http://localhost:3000/${name}.html`

const currentURL = name => isProduction ? fileURL(name) : serverURL(name)

export default {
  menuBar,
  window,
  'tray-icon': trayIcon(),
  'webui-path': '/webui',
  'ipfs-path': ipfsPath(),
  'ipfs-path-file': IPFS_PATH_FILE,
  urls: {
    welcome: currentURL('welcome'),
    help: currentURL('help'),
    settings: currentURL('settings')
  }
}
<commit_msg>Always be on top<commit_after>import path from 'path'
import os from 'os'
import fs from 'fs'

const app = require('app')

const isProduction = process.env.NODE_ENV === 'production'
const IPFS_PATH_FILE = app.getDataPath() + '/ipfs-electron-app-node-path'

const trayIcon = () => {
  if (os.platform() !== 'darwin') {
    return path.resolve(__dirname, '../node_modules/ipfs-logo/ipfs-logo-256-ice.png')
  }

  return path.resolve(__dirname, '../node_modules/ipfs-logo/platform-icons/osx-menu-bar.png')
}

const menuBar = {
  dir: __dirname,
  width: 300,
  height: 400,
  index: isProduction
    ? `file://${__dirname}/menubar.html`
    : 'http://localhost:3000/menubar.html',
  icon: trayIcon(),
  'always-on-top': true,
  preloadWindow: true,
  resizable: false,
  'web-preferences': {
    'web-security': false
  }
}

const window = {
  icon: path.resolve(__dirname, '../node_modules/ipfs-logo/ipfs-logo-256-ice.png'),
  'auto-hide-menu-bar': true,
  width: 800,
  height: 600,
  'web-preferences': {
    'web-security': false
  }
}

const ipfsPath = () => {
  let pathIPFS
  try {
    pathIPFS = fs.readFileSync(IPFS_PATH_FILE, 'utf-8')
  } catch (e) {
    pathIPFS = process.env.IPFS_PATH ||
      (process.env.HOME || process.env.USERPROFILE) + '/.ipfs'
  }

  return pathIPFS
}

// -- Window URLs

const fileURL = name => `file://${__dirname}/${name}.html`
const serverURL = name => `http://localhost:3000/${name}.html`

const currentURL = name => isProduction ? fileURL(name) : serverURL(name)

export default {
  menuBar,
  window,
  'tray-icon': trayIcon(),
  'webui-path': '/webui',
  'ipfs-path': ipfsPath(),
  'ipfs-path-file': IPFS_PATH_FILE,
  urls: {
    welcome: currentURL('welcome'),
    help: currentURL('help'),
    settings: currentURL('settings')
  }
}
<|endoftext|>


<commit_before>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Tileset = require('../../Tileset');
var ImageCollection = require('../../ImageCollection');
var ParseObject = require('./ParseObject');

/**
 * Tilesets and Image Collections
 *
 * @function Phaser.Tilemaps.Parsers.Tiled.ParseTilesets
 * @since 3.0.0
 *
 * @param {object} json - The Tiled JSON data.
 *
 * @return {object} An object containing the tileset and image collection data.
 */
var ParseTilesets = function (json)
{
    var tilesets = [];
    var imageCollections = [];
    var lastSet = null;
    var stringID;

    for (var i = 0; i < json.tilesets.length; i++)
    {
        //  name, firstgid, width, height, margin, spacing, properties
        var set = json.tilesets[i];

        if (set.source)
        {
            console.warn('Phaser can\'t load external tilesets. Use the Embed Tileset button and then export the map again.');
        }
        else if (set.image)
        {
            var newSet = new Tileset(set.name, set.firstgid, set.tilewidth, set.tileheight, set.margin, set.spacing);

            if (json.version > 1)
            {
                // Tiled 1.2+

                if (Array.isArray(set.tiles))
                {
                    var tiles = {};
                    var props = {};

                    for (var t = 0; t < set.tiles.length; t++)
                    {
                        var tile = set.tiles[t];

                        //  Convert tileproperties
                        if (tile.properties)
                        {
                            var newPropData = {};

                            tile.properties.forEach(function (propData)
                            {
                                newPropData[propData['name']] = propData['value'];
                            });

                            props[tile.id] = newPropData;
                        }

                        //  Convert objectgroup
                        if (tile.objectgroup)
                        {
                            tiles[tile.id] = { objectgroup: tile.objectgroup };

                            if (tile.objectgroup.objects)
                            {
                                var parsedObjects2 = tile.objectgroup.objects.map(
                                    function (obj) { return ParseObject(obj); }
                                );

                                tiles[tile.id].objectgroup.objects = parsedObjects2;
                            }
                        }

                        // Copy animation data
                        if (tile.animation)
                        {
                            if (tiles.hasOwnProperty(tile.id))
                            {
                                tiles[tile.id].animation = tile.animation;
                            }
                            else
                            {
                                tiles[tile.id] = { animation: tile.animation };
                            }
                        }
                    }

                    newSet.tileData = tiles;
                    newSet.tileProperties = props;
                }
            }
            else
            {
                // Tiled 1

                // Properties stored per-tile in object with string indexes starting at "0"
                if (set.tileproperties)
                {
                    newSet.tileProperties = set.tileproperties;
                }

                // Object & terrain shapes stored per-tile in object with string indexes starting at "0"
                if (set.tiles)
                {
                    newSet.tileData = set.tiles;

                    // Parse the objects into Phaser format to match handling of other Tiled objects
                    for (stringID in newSet.tileData)
                    {
                        var objectGroup = newSet.tileData[stringID].objectgroup;
                        if (objectGroup && objectGroup.objects)
                        {
                            var parsedObjects1 = objectGroup.objects.map(
                                function (obj) { return ParseObject(obj); }
                            );
                            newSet.tileData[stringID].objectgroup.objects = parsedObjects1;
                        }
                    }
                }
            }

            // For a normal sliced tileset the row/count/size information is computed when updated.
            // This is done (again) after the image is set.
            newSet.updateTileData(set.imagewidth, set.imageheight);

            tilesets.push(newSet);
        }
        else
        {
            var newCollection = new ImageCollection(set.name, set.firstgid, set.tilewidth,
                set.tileheight, set.margin, set.spacing, set.properties);

            for (stringID in set.tiles)
            {
                var image = set.tiles[stringID].image;
                var gid = set.firstgid + parseInt(stringID, 10);
                newCollection.addImage(gid, image);
            }

            imageCollections.push(newCollection);
        }

        //  We've got a new Tileset, so set the lastgid into the previous one
        if (lastSet)
        {
            lastSet.lastgid = set.firstgid - 1;
        }

        lastSet = set;
    }

    return { tilesets: tilesets, imageCollections: imageCollections };
};

module.exports = ParseTilesets;
<commit_msg>`ParseTilesets` will now correctly handle non-consequtive tile IDs. It also now correctly sets the `maxId` property, fixing a bug where tiles wouldn't render if from IDs outside the expected range. Fix #4367<commit_after>/**
 * @author       Richard Davey <rich@photonstorm.com>
 * @copyright    2020 Photon Storm Ltd.
 * @license      {@link https://opensource.org/licenses/MIT|MIT License}
 */

var Tileset = require('../../Tileset');
var ImageCollection = require('../../ImageCollection');
var ParseObject = require('./ParseObject');

/**
 * Tilesets and Image Collections
 *
 * @function Phaser.Tilemaps.Parsers.Tiled.ParseTilesets
 * @since 3.0.0
 *
 * @param {object} json - The Tiled JSON data.
 *
 * @return {object} An object containing the tileset and image collection data.
 */
var ParseTilesets = function (json)
{
    var tilesets = [];
    var imageCollections = [];
    var lastSet = null;
    var stringID;

    for (var i = 0; i < json.tilesets.length; i++)
    {
        //  name, firstgid, width, height, margin, spacing, properties
        var set = json.tilesets[i];

        if (set.source)
        {
            console.warn('External tilesets unsupported. Use Embed Tileset and re-export');
        }
        else if (set.image)
        {
            var newSet = new Tileset(set.name, set.firstgid, set.tilewidth, set.tileheight, set.margin, set.spacing);

            if (json.version > 1)
            {
                // Tiled 1.2+

                if (Array.isArray(set.tiles))
                {
                    var tiles = {};
                    var props = {};

                    for (var t = 0; t < set.tiles.length; t++)
                    {
                        var tile = set.tiles[t];

                        //  Convert tileproperties
                        if (tile.properties)
                        {
                            var newPropData = {};

                            tile.properties.forEach(function (propData)
                            {
                                newPropData[propData['name']] = propData['value'];
                            });

                            props[tile.id] = newPropData;
                        }

                        //  Convert objectgroup
                        if (tile.objectgroup)
                        {
                            tiles[tile.id] = { objectgroup: tile.objectgroup };

                            if (tile.objectgroup.objects)
                            {
                                var parsedObjects2 = tile.objectgroup.objects.map(function (obj)
                                {
                                    return ParseObject(obj);
                                });

                                tiles[tile.id].objectgroup.objects = parsedObjects2;
                            }
                        }

                        // Copy animation data
                        if (tile.animation)
                        {
                            if (tiles.hasOwnProperty(tile.id))
                            {
                                tiles[tile.id].animation = tile.animation;
                            }
                            else
                            {
                                tiles[tile.id] = { animation: tile.animation };
                            }
                        }
                    }

                    newSet.tileData = tiles;
                    newSet.tileProperties = props;
                }
            }
            else
            {
                // Tiled 1

                // Properties stored per-tile in object with string indexes starting at "0"
                if (set.tileproperties)
                {
                    newSet.tileProperties = set.tileproperties;
                }

                // Object & terrain shapes stored per-tile in object with string indexes starting at "0"
                if (set.tiles)
                {
                    newSet.tileData = set.tiles;

                    // Parse the objects into Phaser format to match handling of other Tiled objects
                    for (stringID in newSet.tileData)
                    {
                        var objectGroup = newSet.tileData[stringID].objectgroup;

                        if (objectGroup && objectGroup.objects)
                        {
                            var parsedObjects1 = objectGroup.objects.map(function (obj)
                            {
                                return ParseObject(obj);
                            });

                            newSet.tileData[stringID].objectgroup.objects = parsedObjects1;
                        }
                    }
                }
            }

            // For a normal sliced tileset the row/count/size information is computed when updated.
            // This is done (again) after the image is set.
            newSet.updateTileData(set.imagewidth, set.imageheight);

            tilesets.push(newSet);
        }
        else
        {
            var newCollection = new ImageCollection(set.name, set.firstgid, set.tilewidth, set.tileheight, set.margin, set.spacing, set.properties);

            var maxId = 0;

            for (t = 0; t < set.tiles.length; t++)
            {
                tile = set.tiles[t];

                var image = tile.image;
                var tileId = parseInt(tile.id, 10);
                var gid = set.firstgid + tileId;
                newCollection.addImage(gid, image);

                maxId = Math.max(tileId, maxId);
            }

            newCollection.maxId = maxId;

            imageCollections.push(newCollection);
        }

        //  We've got a new Tileset, so set the lastgid into the previous one
        if (lastSet)
        {
            lastSet.lastgid = set.firstgid - 1;
        }

        lastSet = set;
    }

    return { tilesets: tilesets, imageCollections: imageCollections };
};

module.exports = ParseTilesets;
<|endoftext|>


<commit_before>'use strict';

var _typeof2 = require('babel-runtime/helpers/typeof');

var _typeof3 = _interopRequireDefault(_typeof2);

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _lodash = require('lodash.map');

var _lodash2 = _interopRequireDefault(_lodash);

var _lodash3 = require('lodash.mapvalues');

var _lodash4 = _interopRequireDefault(_lodash3);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var screenDeep = function screenDeep(user, data) {
  // check if the user can even see the doc
  if (data && data.authorized && !data.authorized(user, 'read')) {
    return;
  }
  // single instance w/ lens
  if (data && data.lens) {
    return data.lens(user, 'read');
  }

  // array of instances w/ lens
  if (Array.isArray(data)) {
    return (0, _lodash2.default)(data, screenDeep.bind(null, user));
  }

  if ((typeof data === 'undefined' ? 'undefined' : (0, _typeof3.default)(data)) === 'object') {
    return (0, _lodash4.default)(data, screenDeep.bind(null, user));
  }

  return data;
};

exports.default = screenDeep;
module.exports = exports['default'];<commit_msg>build<commit_after>'use strict';

var _typeof2 = require('babel-runtime/helpers/typeof');

var _typeof3 = _interopRequireDefault(_typeof2);

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _lodash = require('lodash.reduce');

var _lodash2 = _interopRequireDefault(_lodash);

var _lodash3 = require('lodash.mapvalues');

var _lodash4 = _interopRequireDefault(_lodash3);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var screenDeep = function screenDeep(user, data, returnEmpty) {
  if ((typeof data === 'undefined' ? 'undefined' : (0, _typeof3.default)(data)) !== 'object') return data;

  // check if the user can even see the doc
  if (data.authorized && !data.authorized('read', user)) {
    if (returnEmpty) return;
    return Array.isArray(data) ? [] : {};
  }
  // single instance w/ lens
  if (data.screen) {
    return data.screen('read', user);
  }

  // array of instances w/ lens
  if (Array.isArray(data)) {
    return (0, _lodash2.default)(data, function (p, v) {
      var nv = screenDeep(user, v, true);
      if (nv != null) p.push(nv);
      return p;
    }, []);
  }

  return (0, _lodash4.default)(data, function (v) {
    return screenDeep(user, v, true);
  });
};

exports.default = screenDeep;
module.exports = exports['default'];<|endoftext|>


<commit_before>var Nano = function(device) {
	this.device = device;
	this._in_buffer = [];
	this._out_buffer = [];
	this._send_queue = 0;
	this._BUFFER_SIZE = 32;
};

Nano.prototype.push_data = function(data) {
	if (this._out_buffer.length >= this._BUFFER_SIZE)
		return false;
	var pkgs = [];
	var cnt = Math.ceil(data.byteLength / 33);
	for (var idx = 1; idx < cnt + 1; idx++) {
		pkgs.push(mm_encode(
			P_WORK, idx, cnt, data.slice((idx - 1) * 32, idx * 32)
		));
	}
	this._out_buffer.push(pkgs);
	return true;
};

Nano.prototype.detect = function(callback) {
	var nano = this;
	this._send(mm_encode(
		P_DETECT, 0x01, 0x01,
		new ArrayBuffer(32)
	));
	this._receive(function(pkg) {
		var data = mm_decode(pkg);

		// TODO: what if it is not a P_ACKDETECT package?
		if (data.type === P_ACKDETECT) {
			nano.log("log1", "Version: %s", data.version);
			nano.version = data.version;
			callback();
		}
	});
};

Nano.prototype.run = function(queue_size) {
	var nano = this;
	this.detect(function() {
		if (check_version(nano.version)) {
			nano._stop = false;
			nano._receive_loop();
			nano._decode_loop();
			nano._send_loop(queue_size);
		}
	});
};

Nano.prototype.stop = function() {
	this._stop = true;
	this.log("info", "Stopped.");
};

Nano.prototype.connect = function() {
	var nano = this;
	chrome.hid.connect(this.device.deviceId, function(connection) {
		if (chrome.runtime.lastError) {
			nano.log("error", chrome.runtime.lastError.message);
			return;
		}
		nano.connection = connection;
	});
};

Nano.prototype.disconnect = function() {
	var nano = this;
	chrome.hid.disconnect(nano.connection.connectionId, function() {
		nano.log("info", "Disconnected.");
	});
};

Nano.prototype.log = function(level) {
	var args = Array.prototype.slice.call(arguments);
	var i;
	switch (level) {
		case 'error':
			args[0] = "[NANO %d] " + arguments[1];
			args[1] = this.device.deviceId;
			console.error.apply(console, args);
			break;
		case 'warn':
			args[0] = "[NANO %d] " + arguments[1];
			args[1] = this.device.deviceId;
			console.warn.apply(console, args);
			break;
		case 'info':
			args[0] = "[NANO %d] " + arguments[1];
			args[1] = this.device.deviceId;
			console.info.apply(console, args);
			break;
		case 'log1':
			args.unshift("%c[NANO %d] " + arguments[1]);
			args[1] = LOG1_STYLE;
			args[2] = this.device.deviceId;
			console.log.apply(console, args);
			break;
		case 'log2':
			args.unshift("%c[NANO %d] " + arguments[1]);
			args[1] = LOG2_STYLE;
			args[2] = this.device.deviceId;
			console.log.apply(console, args);
			break;
		case 'debug':
			args.unshift("%c[NANO %d] " + arguments[1]);
			args[1] = DEBUG_STYLE;
			args[2] = this.device.deviceId;
			console.debug.apply(console, args);
			break;
		default:
			break;
	}
};

Nano.prototype._decode_loop = function() {
	var nano = this;
	var decode = setInterval(function() {
		var pkg = nano._in_buffer.shift();
		if (nano._stop && pkg === undefined)
			clearInterval(decode);
		else if (pkg !== undefined) {
			var data = mm_decode(pkg);

			// TODO: what if it is not a P_NONCE package?
			if (data.type === P_NONCE)
				nano.log("log2", "Nonce:   0x%s", data.nonce.toString(16));
		}
	}, 50);
};

Nano.prototype._send_loop = function(queue_size) {
	var nano = this;
	var loop = setInterval(function() {
		if (nano._stop)
			clearInterval(loop);
		else
			while (nano._send_queue < queue_size) {
				var pkgs = nano._out_buffer.shift();
				if (pkgs === undefined)
					break;
				for (var pkg of pkgs)
					nano._send(pkg);
			}
	}, 50);
};

Nano.prototype._receive_loop = function() {
	var nano = this;
	var callback = function(pkg) {
		nano._in_buffer.push(pkg);
		nano._receive(callback);
	};
	this._receive(callback);
};

Nano.prototype._send = function(pkg) {
	var nano = this;
	this._send_queue += 1;
	chrome.hid.send(this.connection.connectionId, 0, pkg, function() {
		if (chrome.runtime.lastError) {
			nano.error(chrome.runtime.lastError.message);
			return;
		}
		nano.log("debug", "Send:    0x%s", ab2str(pkg));
		nano._send_queue -= 1;
	});
};

Nano.prototype._receive = function(callback) {
	var nano = this;
	chrome.hid.receive(this.connection.connectionId, function(reportId, pkg) {
		if (chrome.runtime.lastError) {
			nano.error(chrome.runtime.lastError.message);
			return;
		}
		nano.log("debug", "Receive: 0x%s", ab2str(pkg));
		callback(pkg);
	});
};
<commit_msg>APP: Fix TypeError<commit_after>var Nano = function(device) {
	this.device = device;
	this._in_buffer = [];
	this._out_buffer = [];
	this._send_queue = 0;
	this._BUFFER_SIZE = 32;
};

Nano.prototype.push_data = function(data) {
	if (this._out_buffer.length >= this._BUFFER_SIZE)
		return false;
	var pkgs = [];
	var cnt = Math.ceil(data.byteLength / 33);
	for (var idx = 1; idx < cnt + 1; idx++) {
		pkgs.push(mm_encode(
			P_WORK, idx, cnt, data.slice((idx - 1) * 32, idx * 32)
		));
	}
	this._out_buffer.push(pkgs);
	return true;
};

Nano.prototype.detect = function(callback) {
	var nano = this;
	this._send(mm_encode(
		P_DETECT, 0x01, 0x01,
		new ArrayBuffer(32)
	));
	this._receive(function(pkg) {
		var data = mm_decode(pkg);

		// TODO: what if it is not a P_ACKDETECT package?
		if (data.type === P_ACKDETECT) {
			nano.log("log1", "Version: %s", data.version);
			nano.version = data.version;
			callback();
		}
	});
};

Nano.prototype.run = function(queue_size) {
	var nano = this;
	this.detect(function() {
		if (check_version(nano.version)) {
			nano._stop = false;
			nano._receive_loop();
			nano._decode_loop();
			nano._send_loop(queue_size);
		}
	});
};

Nano.prototype.stop = function() {
	this._stop = true;
	this.log("info", "Stopped.");
};

Nano.prototype.connect = function() {
	var nano = this;
	chrome.hid.connect(this.device.deviceId, function(connection) {
		if (chrome.runtime.lastError) {
			nano.log("error", chrome.runtime.lastError.message);
			return;
		}
		nano.connection = connection;
	});
};

Nano.prototype.disconnect = function() {
	var nano = this;
	chrome.hid.disconnect(nano.connection.connectionId, function() {
		nano.log("info", "Disconnected.");
	});
};

Nano.prototype.log = function(level) {
	var args = Array.prototype.slice.call(arguments);
	var i;
	switch (level) {
		case 'error':
			args[0] = "[NANO %d] " + arguments[1];
			args[1] = this.device.deviceId;
			console.error.apply(console, args);
			break;
		case 'warn':
			args[0] = "[NANO %d] " + arguments[1];
			args[1] = this.device.deviceId;
			console.warn.apply(console, args);
			break;
		case 'info':
			args[0] = "[NANO %d] " + arguments[1];
			args[1] = this.device.deviceId;
			console.info.apply(console, args);
			break;
		case 'log1':
			args.unshift("%c[NANO %d] " + arguments[1]);
			args[1] = LOG1_STYLE;
			args[2] = this.device.deviceId;
			console.log.apply(console, args);
			break;
		case 'log2':
			args.unshift("%c[NANO %d] " + arguments[1]);
			args[1] = LOG2_STYLE;
			args[2] = this.device.deviceId;
			console.log.apply(console, args);
			break;
		case 'debug':
			args.unshift("%c[NANO %d] " + arguments[1]);
			args[1] = DEBUG_STYLE;
			args[2] = this.device.deviceId;
			console.debug.apply(console, args);
			break;
		default:
			break;
	}
};

Nano.prototype._decode_loop = function() {
	var nano = this;
	var decode = setInterval(function() {
		var pkg = nano._in_buffer.shift();
		if (nano._stop && pkg === undefined)
			clearInterval(decode);
		else if (pkg !== undefined) {
			var data = mm_decode(pkg);

			// TODO: what if it is not a P_NONCE package?
			if (data.type === P_NONCE)
				nano.log("log2", "Nonce:   0x%s", data.nonce.toString(16));
		}
	}, 50);
};

Nano.prototype._send_loop = function(queue_size) {
	var nano = this;
	var loop = setInterval(function() {
		if (nano._stop)
			clearInterval(loop);
		else
			while (nano._send_queue < queue_size) {
				var pkgs = nano._out_buffer.shift();
				if (pkgs === undefined)
					break;
				for (var pkg of pkgs)
					nano._send(pkg);
			}
	}, 50);
};

Nano.prototype._receive_loop = function() {
	var nano = this;
	var callback = function(pkg) {
		nano._in_buffer.push(pkg);
		nano._receive(callback);
	};
	this._receive(callback);
};

Nano.prototype._send = function(pkg) {
	var nano = this;
	this._send_queue += 1;
	chrome.hid.send(this.connection.connectionId, 0, pkg, function() {
		if (chrome.runtime.lastError) {
			nano.log("error", chrome.runtime.lastError.message);
			return;
		}
		nano.log("debug", "Send:    0x%s", ab2str(pkg));
		nano._send_queue -= 1;
	});
};

Nano.prototype._receive = function(callback) {
	var nano = this;
	chrome.hid.receive(this.connection.connectionId, function(reportId, pkg) {
		if (chrome.runtime.lastError) {
			nano.log("error", chrome.runtime.lastError.message);
			return;
		}
		nano.log("debug", "Receive: 0x%s", ab2str(pkg));
		callback(pkg);
	});
};
<|endoftext|>


<commit_before>/*global describe,it,element,by,takeScreenshot,expect*/

describe("sap.m.App", function () {
	"use strict";

	var fnClickThenCompare = function (sId, sImageName, sTestMessage) {
		it(sTestMessage, function () {
			element(by.id(sId)).click();
			expect(takeScreenshot()).toLookAs(sImageName);
		});
	};

	it("should load test page", function () {
		expect(takeScreenshot()).toLookAs("initial");
	});

	fnClickThenCompare("hide-footer-btn", "app-without-footer", "should show a footer");
	fnClickThenCompare("show-footer-btn", "app-with-footer", "should not show a footer");
	fnClickThenCompare("show-nav-btn", "app-with-navbtn", "should show navigation button in the header");
	fnClickThenCompare("hide-nav-btn", "app-without-navbtn", "should not show navigation button in the header");
});
<commit_msg>[INTERNAL][TEST] Made sap.m.App visual test mobile compliant<commit_after>/*global describe,it,element,by,takeScreenshot,expect*/

describe("sap.m.App", function () {
	"use strict";

	var fnClickThenCompare = function (sId, sImageName, sTestMessage) {
		it(sTestMessage, function () {
			element(by.id(sId)).click();
			expect(takeScreenshot()).toLookAs(sImageName);
		});
	};

	it("should load test page", function () {
		element(by.id("page1-title-inner")).click();
		expect(takeScreenshot()).toLookAs("initial");
	});

	fnClickThenCompare("hide-footer-btn", "app-without-footer", "should show a footer");
	fnClickThenCompare("show-footer-btn", "app-with-footer", "should not show a footer");
	fnClickThenCompare("show-nav-btn", "app-with-navbtn", "should show navigation button in the header");
	fnClickThenCompare("hide-nav-btn", "app-without-navbtn", "should not show navigation button in the header");
});
<|endoftext|>


<commit_before>'use strict';

const fs            = require('fs');
const path          = require('path');
const streamBuffers = require('stream-buffers');
const AWS           = require('aws-sdk');
const archiver      = require('archiver');
const waterfall     = require('steppin');
const async         = require('async');
const arn           = require('../../common/arn.js');
const roles         = require('../../common/roles.js');
const policies      = require('../../common/policies.js');
const createHandler = require('../lib/handler.js');

exports.command = 'update';
exports.desc    = 'Uploads the contents of dist to lambda as a new function version';
exports.builder = {
  test: {
    describe:       'Output bundled code to build directory and does not contact AWS',
    boolean:        true,
    default:        false,
  },
  'skip-role': {
    describe:       'Do not attempt to create a role for this function. Useful for unprivileged users or if you did not make any changes',
    boolean:        true,
    default:        false,
  },
};

function createEnvironmentVars(obj, extend) {
  let env = Object.assign({}, obj, extend || {});
  let newObj = {};
  Object.keys(env).forEach(key => {
    let value = env[key];
    if (null !== value && undefined !== value) {
      newObj[key] = value;
    }
  });
  return newObj;
}

function isArn(arn) {
  return 0 === absOrPartialArn.indexOf('arn:');
}

function expandDeadLetterQueueName(arnOrQueueName) {
  if (isArn(arnOrQueueName)) {
    return arnOrQueueName;
  }
  else {
    return arn.format({
      service:      'sqs',
      region:       global.betty.aws.region,
      account:      global.betty.aws.accountId,
      resource:     arnOrQueueName,
    });
  }
}

function createCodeBundle(dist, next) {
  let output = new streamBuffers.WritableStreamBuffer();
  let archive = archiver('zip', {
    store: true,
  });
  output.on('finish', () => next(null, output.getContents()));
  archive.on('error', next);
  archive.pipe(output);
  archive.directory(dist + '/', '.');
  archive.finalize();
}

function addCodeParams(params, bufferCode) {
  Object.assign(params, {
    Publish:        true,
  });
}

function addConfigParams(params, role, config, settings) {
  config = config || {};
  let VpcConfig = !config.vpc ? null : {
    SubnetIds:          config.subnetIds,
    SecurityGroupIds:   config.securityGroupIds,
  };
  Object.assign(params, {
    FunctionName:       config.name,
    Description:        config.description || '',
    Handler:            settings.entry || 'index.handler',
    MemorySize:         settings.memory || 128,
    Role:               role,
    Runtime:            settings.runtime || 'nodejs6.10',
    Timeout:            settings.timeout || 15,
    DeadLetterConfig:   config.deadLetterQueue ? { TargetArn: expandDeadLetterQueueName(config.deadLetterQueue) } : null,
    Environment:        settings.environment ? { Variables: createEnvironmentVars(settings.environment, { betty_env: global.betty.env }) } : null,
    VpcConfig,
  });
}

function createFunction(lambda, role, config, bufferCode, next) {
  let params = {};
  addConfigParams(params, role, config, config.configuration);
  global.log.debug({ params }, 'config params');
  addCodeParams(params, bufferCode);
  params.Code = {
    ZipFile:        bufferCode,
  };
  lambda.createFunction(params, next);
}

function updateFunction(lambda, role, config, bufferCode, next) {
  let configParams = {};
  addConfigParams(configParams, role, config, config.configuration);
  global.log.debug({ params: configParams }, 'config params');
  lambda.updateFunctionConfiguration(configParams, (err, data) => {
    if (err) return next(err);
    let codeParams = { FunctionName: configParams.FunctionName };
    addCodeParams(codeParams, bufferCode);
    codeParams.ZipFile = bufferCode;
    let awsRequest = lambda.updateFunctionCode(codeParams, next);
    global.log.info({ bytes: bufferCode.length, mb: (bufferCode.length / 1024 / 1024).toFixed(2) }, 'bundle size');
    awsRequest.on('httpUploadProgress', (progress, response) => {
      global.log.info(progress, 'upload progress');
    });
  });
}

function getExistingFunction(lambda, FunctionName, next) {
  let params = { FunctionName };
  lambda.getFunctionConfiguration(params, (err, data) => next(null, err ? false : data));
}

exports.handler = createHandler((argv, done) => {
  global.log.info({ region: global.betty.aws.region }, 'update started');
  global.log.debug({ argv, config: global.config }, 'settings');
  let dist = path.join(process.cwd(), argv.main ? path.dirname(argv.main) : 'dist');
  try {
    let filesInDist = fs.readdirSync(dist);
    if (0 === filesInDist.length) {
      let err = new Error('no files in dist');
      global.log.error({ err, dist }, 'dist not found');
      return done(err);
    }
  }
  catch (err) {
    global.log.warn({ err, dist }, 'error reading dist - did you forget to run betty build first?');
    return done(err);
  }
  if (argv.test) {
    createCodeBundle(dist, (err, bufferCode) => {
      if (err) {
        global.log.error({ err }, 'output code bundle failed');
        return done(err);
      }
      let bundleZip = path.join(dist, 'bundle.zip');
      fs.writeFileSync(bundleZip, bufferCode);
      global.log.info({ destination: bundleZip }, 'test bundle created');
    });
    return;
  }
  let lambda = new AWS.Lambda({ region: global.betty.aws.region });
  waterfall({
    role: (state, next) => {
      if (config['skip-role']) {
        global.log.info('role creation was skipped');
        return next(null, null);
      }
      global.log.debug('starting role');
      roles.createLambdaRole(global.config.name, (err, data, justCreated) => {
        if (err) return next(err);
        global.log.debug({ role: data.Role }, 'got role');
        // HACK: if role was just created it can take a few seconds to become
        //       available to assign to the function.
        //       easier than using the aws api to poll.
        let delay = justCreated ? 5000 : 0;
        setTimeout(next, delay, null, data.Role.Arn);
      });
    },
    attachPolicies: function(state, next) {
      global.log.debug({ assets: global.config.assets, resources: Object.keys(global.config.resources) }, 'attaching policies');
      let inlineAssetPolicies = (global.config.assets || []).map(asset => {
        return (done) => {
          let policyName      = policies.nameFromAsset('asset', asset);
          let policyDocument  = policies.documentFromAsset(asset);
          global.log.trace({ name: policyName, document: policyDocument }, 'attaching inline policy');
          roles.attachInlinePolicy(global.config.name, policyName, policyDocument, done);
        };
      });
      let dependentResourcePolicies = Object.keys(global.config.resources || {}).map(resourceName => {
        return (done) => {
          let policyArn = policies.createManagedPolicyArnForResource(resourceName);
          global.log.trace({ arn: policyArn }, 'attaching managed policy');
          roles.attachManagedPolicy(global.config.name, policyArn, done);
        };
      });
      async.parallel([
        (done) => {
          global.log.trace('attaching default lambda policy');
          roles.attachAwsLambdaBasicExecutionRole(global.config.name, done);
        },
      ].concat(inlineAssetPolicies, dependentResourcePolicies), next);
    },
    publishManagedPolicy: function(state, next) {
      if (!global.config.policy) {
        global.log.warn('no policy exists for resource. skipping');
        return next(null, null);
      }
      let policyDocument = policies.documentFromAssets(global.config.policy || []);
      global.log.debug({ document: policyDocument }, 'publishing managed policy for downstream');
      policies.createManagedPolicy(global.config.name, policyDocument, next);
    },
    bundle: (state, next) => {
      global.log.debug('starting bundle');
      createCodeBundle(dist, (err, bufferCode) => {
        if (err) {
          global.log.error({ err }, 'code bundle failed');
          return next(err);
        }
        global.log.debug({ size: bufferCode.byteLength }, 'bundle created');
        next(null, bufferCode);
      });
    },
    exists: (state, next) => {
      global.log.debug('checking if function exists');
      getExistingFunction(lambda, global.config.name, next);
    },
    update: (state, next) => {
      if (state.exists) {
        global.log.info('updating existing function');
        updateFunction(lambda, state.role, global.config, state.bundle, next);
      }
      else {
        global.log.info('creating new function');
        createFunction(lambda, state.role, global.config, state.bundle, next);
      }
    },
  }, (err, state) => {
    if (err) {
      global.log.error(err);
      return done(err);
    }
    global.log.info('update complete');
    global.log.debug(Object.assign({}, state, { bundle: '[redacted]' }), 'final state');
    done(null);
  });
});
<commit_msg>closes #62<commit_after>'use strict';

const fs            = require('fs');
const path          = require('path');
const streamBuffers = require('stream-buffers');
const AWS           = require('aws-sdk');
const archiver      = require('archiver');
const waterfall     = require('steppin');
const async         = require('async');
const arn           = require('../../common/arn.js');
const roles         = require('../../common/roles.js');
const policies      = require('../../common/policies.js');
const createHandler = require('../lib/handler.js');

exports.command = 'update';
exports.desc    = 'Uploads the contents of dist to lambda as a new function version';
exports.builder = {
  test: {
    describe:       'Output bundled code to build directory and does not contact AWS',
    boolean:        true,
    default:        false,
  },
  'skip-role': {
    describe:       'Do not attempt to create a role for this function. Useful for unprivileged users or if you did not make any changes',
    boolean:        true,
    default:        false,
  },
  compress: {
    describe:       'If compression should be used.  Otherwise zip created with no compression for best performance.',
    boolean:        true,
  }
};

function createEnvironmentVars(obj, extend) {
  let env = Object.assign({}, obj, extend || {});
  let newObj = {};
  Object.keys(env).forEach(key => {
    let value = env[key];
    if (null !== value && undefined !== value) {
      newObj[key] = value;
    }
  });
  return newObj;
}

function isArn(arn) {
  return 0 === absOrPartialArn.indexOf('arn:');
}

function expandDeadLetterQueueName(arnOrQueueName) {
  if (isArn(arnOrQueueName)) {
    return arnOrQueueName;
  }
  else {
    return arn.format({
      service:      'sqs',
      region:       global.betty.aws.region,
      account:      global.betty.aws.accountId,
      resource:     arnOrQueueName,
    });
  }
}

function createCodeBundle(dist, options, next) {
  let output = new streamBuffers.WritableStreamBuffer();
  let archive = archiver('zip', options);
  output.on('finish', () => next(null, output.getContents()));
  archive.on('error', next);
  archive.pipe(output);
  archive.directory(dist + '/', '.');
  archive.finalize();
}

function addCodeParams(params, bufferCode) {
  Object.assign(params, {
    Publish:        true,
  });
}

function addConfigParams(params, role, config, settings) {
  config = config || {};
  let VpcConfig = !config.vpc ? null : {
    SubnetIds:          config.subnetIds,
    SecurityGroupIds:   config.securityGroupIds,
  };
  Object.assign(params, {
    FunctionName:       config.name,
    Description:        config.description || '',
    Handler:            settings.entry || 'index.handler',
    MemorySize:         settings.memory || 128,
    Role:               role,
    Runtime:            settings.runtime || 'nodejs6.10',
    Timeout:            settings.timeout || 15,
    DeadLetterConfig:   config.deadLetterQueue ? { TargetArn: expandDeadLetterQueueName(config.deadLetterQueue) } : null,
    Environment:        settings.environment ? { Variables: createEnvironmentVars(settings.environment, { betty_env: global.betty.env }) } : null,
    VpcConfig,
  });
}

function createFunction(lambda, role, config, bufferCode, next) {
  let params = {};
  addConfigParams(params, role, config, config.configuration);
  global.log.debug({ params }, 'config params');
  addCodeParams(params, bufferCode);
  params.Code = {
    ZipFile:        bufferCode,
  };
  lambda.createFunction(params, next);
}

function updateFunction(lambda, role, config, bufferCode, next) {
  let configParams = {};
  addConfigParams(configParams, role, config, config.configuration);
  global.log.debug({ params: configParams }, 'config params');
  lambda.updateFunctionConfiguration(configParams, (err, data) => {
    if (err) return next(err);
    let codeParams = { FunctionName: configParams.FunctionName };
    addCodeParams(codeParams, bufferCode);
    codeParams.ZipFile = bufferCode;
    let awsRequest = lambda.updateFunctionCode(codeParams, next);
    global.log.info({ bytes: bufferCode.length, mb: (bufferCode.length / 1024 / 1024).toFixed(2) }, 'bundle size');
    awsRequest.on('httpUploadProgress', (progress, response) => {
      global.log.info(progress, 'upload progress');
    });
  });
}

function getExistingFunction(lambda, FunctionName, next) {
  let params = { FunctionName };
  lambda.getFunctionConfiguration(params, (err, data) => next(null, err ? false : data));
}

exports.handler = createHandler((argv, done) => {
  global.log.info({ region: global.betty.aws.region }, 'update started');
  global.log.debug({ argv, config: global.config }, 'settings');
  let dist = path.join(process.cwd(), argv.main ? path.dirname(argv.main) : 'dist');
  try {
    let filesInDist = fs.readdirSync(dist);
    if (0 === filesInDist.length) {
      let err = new Error('no files in dist');
      global.log.error({ err, dist }, 'dist not found');
      return done(err);
    }
  }
  catch (err) {
    global.log.warn({ err, dist }, 'error reading dist - did you forget to run betty build first?');
    return done(err);
  }
  const codeBundleOptions = {
    // if compress passed disable store
    store: argv.compress ? false : true,
  };
  if (argv.test) {
    createCodeBundle(dist, codeBundleOptions, (err, bufferCode) => {
      if (err) {
        global.log.error({ err }, 'output code bundle failed');
        return done(err);
      }
      let bundleZip = path.join(dist, 'bundle.zip');
      fs.writeFileSync(bundleZip, bufferCode);
      global.log.info({ destination: bundleZip }, 'test bundle created');
    });
    return;
  }
  let lambda = new AWS.Lambda({ region: global.betty.aws.region });
  waterfall({
    role: (state, next) => {
      if (config['skip-role']) {
        global.log.info('role creation was skipped');
        return next(null, null);
      }
      global.log.debug('starting role');
      roles.createLambdaRole(global.config.name, (err, data, justCreated) => {
        if (err) return next(err);
        global.log.debug({ role: data.Role }, 'got role');
        // HACK: if role was just created it can take a few seconds to become
        //       available to assign to the function.
        //       easier than using the aws api to poll.
        let delay = justCreated ? 5000 : 0;
        setTimeout(next, delay, null, data.Role.Arn);
      });
    },
    attachPolicies: function(state, next) {
      global.log.debug({ assets: global.config.assets, resources: Object.keys(global.config.resources) }, 'attaching policies');
      let inlineAssetPolicies = (global.config.assets || []).map(asset => {
        return (done) => {
          let policyName      = policies.nameFromAsset('asset', asset);
          let policyDocument  = policies.documentFromAsset(asset);
          global.log.trace({ name: policyName, document: policyDocument }, 'attaching inline policy');
          roles.attachInlinePolicy(global.config.name, policyName, policyDocument, done);
        };
      });
      let dependentResourcePolicies = Object.keys(global.config.resources || {}).map(resourceName => {
        return (done) => {
          let policyArn = policies.createManagedPolicyArnForResource(resourceName);
          global.log.trace({ arn: policyArn }, 'attaching managed policy');
          roles.attachManagedPolicy(global.config.name, policyArn, done);
        };
      });
      async.parallel([
        (done) => {
          global.log.trace('attaching default lambda policy');
          roles.attachAwsLambdaBasicExecutionRole(global.config.name, done);
        },
      ].concat(inlineAssetPolicies, dependentResourcePolicies), next);
    },
    publishManagedPolicy: function(state, next) {
      if (!global.config.policy) {
        global.log.warn('no policy exists for resource. skipping');
        return next(null, null);
      }
      let policyDocument = policies.documentFromAssets(global.config.policy || []);
      global.log.debug({ document: policyDocument }, 'publishing managed policy for downstream');
      policies.createManagedPolicy(global.config.name, policyDocument, next);
    },
    bundle: (state, next) => {
      global.log.debug('starting bundle');
      createCodeBundle(dist, codeBundleOptions, (err, bufferCode) => {
        if (err) {
          global.log.error({ err }, 'code bundle failed');
          return next(err);
        }
        global.log.debug({ size: bufferCode.byteLength }, 'bundle created');
        next(null, bufferCode);
      });
    },
    exists: (state, next) => {
      global.log.debug('checking if function exists');
      getExistingFunction(lambda, global.config.name, next);
    },
    update: (state, next) => {
      if (state.exists) {
        global.log.info('updating existing function');
        updateFunction(lambda, state.role, global.config, state.bundle, next);
      }
      else {
        global.log.info('creating new function');
        createFunction(lambda, state.role, global.config, state.bundle, next);
      }
    },
  }, (err, state) => {
    if (err) {
      global.log.error(err);
      return done(err);
    }
    global.log.info('update complete');
    global.log.debug(Object.assign({}, state, { bundle: '[redacted]' }), 'final state');
    done(null);
  });
});
<|endoftext|>