<commit_before>/** This is `mask`, a tiny MIT-licensed library providing collision masks
 * and thus pixel-perfect collision detection in JavaScript. Collision
 * masks are read from [PBM][] files. Check the [github][] page for more
 * information.
 * [github]: https://github.com/startling/mask
 * [PBM]: http://netpbm.sourceforge.net/doc/pbm.html
 */
/*!*/
var Mask = (function () {
  /** Construct a `Mask`.
   *
   * Examples:
   *
   *     new Mask()
   *
   * @constructor
   * @api public
   */
  function Mask () {
    this.x = this.y = this.w = this.h = 0;
  }
  /** Make a clone of a `Mask`.
   *
   * @this {Mask}
   * @api public
   */
  Mask.prototype.clone = function () {
    var other = new Mask();
    other.x = this.x;
    other.y = this.y;
    other.w = this.w;
    other.h = this.h;
    return other;
  };
  /** Translate this `Mask` in two dimensions.
   *
   * @this {Mask}
   * @param {Number} x x-distance
   * @param {Number} y y-distancex
   * @api public
   */
  Mask.prototype.translate = function (x, y) {
    this.x += x;
    this.y += y;
  };
  /** Make a copy of this `Mask` translated to the coordinates given.
   *
   * @this {Mask}
   * @param {Number} x x-coordinate
   * @param {Number} y y-coordinate
   * @return {Mask}
   * @api public
   */
  Mask.prototype.at = function (x, y) {
    var other = this.clone();
    other.x = x;
    other.y = y;
    return other;
  };
  /** Mask a copy of this `Mask` translated in two dimensions.
   * @this {Mask}
   * @param {Number} x x-distance
   * @param {Number} y y-distance
   * @return {Mask}
   * @api public
   */
  Mask.prototype.translated = function (x, y) {
    var other = this.clone();
    other.translate(x, y);
    return other;
  };
  /** Test whether a Mask is completely contained within another.
   *
   * @this {Mask}
   * @param {Mask} b The containing Mask.
   * @api public
   */
  Mask.prototype.within = function (b) {
    var intersect = intersection(this, b);
    for (var x = intersect.x; x < intersect.w; x++) {
      for (var y = intersect.y; y < intersect.h; y++) {
        if (this.collidesAt(x, y) &&
            !b.collidesAt(x, y)) {
          return false;
        }
      }
    }
    return true;
  };
  /** Test whether this mask collides at the given location.
   *
   * @this {Mask}
   * @param {Number} x x-coordinate
   * @param {Number} y y-coordinate
   * @return {Mask}
   * @api public
   */
  Mask.prototype.collidesAt = function (x, y) {
    return false;
  };
  /** Some callbacks expect a `Mask`.
   * @callback MaskCallback
   * @param {Mask} the collision map
   * @api private
   */
  /** Create a `Mask` object from an `ArrayBuffer` taken as a PBM image.
   *
   * N.B. do not use the newly-constructed `Mask` directly until
   * the callback is called.
   *
   * @constructor
   * @param {ArrayBuffer} array image data
   * @param {MaskCallback} callback
   * @api public
   */
  Mask.PBM = function (array, callback) {
    Mask.bind(this)();
    this.data = null;
    var bytes = new Uint8Array(array);
    if (bytes.byteLength > 2) {
      if (bytes[0] === 'P'.charCodeAt(0)) {
        if (bytes[1] === '4'.charCodeAt(0)) {
          // This is a PBM binary file...
          return fromBinaryPBM(this, bytes, callback);
        } else if (bytes[1] == "1".charCodeAt(0)) {
          // This is a PBM ASCII file...
          return fromASCIIPBM(this, bytes, callback);
        } else {
          // Unknown signature.
          return callback(null, new Error("Unknown PBM signature."));
        }
      } else {
        // Unknown signature.
        return callback(null, new Error("Unknown PBM signature."));
      }
    } else {
      // File too short.
      return callback(null, Error("Invalid PBM image."));
    }
  };
  Mask.PBM.prototype = new Mask();
  Mask.PBM.prototype.clone = function () {
    var other = this.__proto__.clone();
    other.data = this.data;
    return other;
  };
  Mask.PBM.prototype.collidesAt = function (x, y) {
    return !!this.data[x - this.x] &&
      !!this.data[x - this.x][y - this.y];
  };
  /** Skip every byte matching a regular expression.
   *
   * @api private
   * @param {RegExp} regex regular expression
   * @param {Uint8Buffer} bytes character data
   * @param {object} state parser state
   */
  function skipRegex (regex, bytes, state) {
    for (; state.index < bytes.byteLength; state.index++) {
      var here = String.fromCharCode(bytes[state.index]);
      if (!here.match(regex)) {
        break;
      }
    }
  }
  /** Find all the leading characters matching a regular expression and
   * stick them in an array.
   *
   * @api private
   * @param {RegExp} regex regular expression
   * @param {Uint8Buffer} bytes character data
   * @param {object} state parser state
   * @return {Array}
   */
  function accumulateRegex (regex, bytes, state) {
    var accumulator = [];
    for (; state.index < bytes.byteLength; state.index++) {
      var here = String.fromCharCode(bytes[state.index]);
      if (here.match(regex)) {
        accumulator.push(here);
      } else {
        break;
      }
    }
    return accumulator;
  }
  /** Skip the parts that come after a PBM signature -- whitespace and any
   * number of comments.
   *
   * @api private
   * @param {Uint8Buffer} bytes character data
   * @param {object} state parser state
   */
  function skipPostSignature (bytes, state) {
    skipRegex(/\s/, bytes, state);
    var here = String.fromCharCode(bytes[state.index]);
    while (here === '#') {
      state.index++;
      skipRegex(/[^\n]/, bytes, state);
      skipRegex(/\s/, bytes, state);
      here = String.fromCharCode(bytes[state.index]);
    }
  }
  /** Create a `Mask` from an Uint8Array taken semantically as an ASCII PBM image.
   *
   * @param {Uint8Buffer} bytes PBM image data.
   * @param {MaskCallback} callback
   * @api private
   */
  fromASCIIPBM = function (m, bytes, callback) {
    var bits = [];
    var state = {index: 2};
    // Skip the spaces and comments post-signature.
    skipPostSignature(bytes, state);
    var width = accumulateRegex(/\d/, bytes, state).join("");
    skipRegex(/\s/, bytes, state);
    // Read numbers and stick them into 'height' until whitespace.
    var height = accumulateRegex(/\d/, bytes, state).join("");
    skipRegex(/\s/, bytes, state);
    // Initialize the mask.
    m.w = parseInt(width, 10);
    m.h = parseInt(height, 10);
    // Read 0 and 1 until the end of the file, skipping everything else.
    for (; state.index < bytes.byteLength; state.index++) {
      function add (x) {
        if (!bits.length || bits[bits.length - 1].length === m.w) {
          bits.push([]);
        }
        bits[bits.length - 1].push(x);
      }
      switch (bytes[state.index]) {
      case '0'.charCodeAt(0):
        add(false);
        break;
      case '1'.charCodeAt(0):
        add(true);
        break;
      default:
        break;
      }
    }
    m.data = bits;
    return callback(m);
  };
  /** Create a `Mask` from an Uint8Array taken semantically as an binary
   * PBM image.
   *
   * @param {Uint8Buffer} bytes PBM image data.
   * @param {MaskCallback} callback
   * @api private
   */
  fromBinaryPBM = function (m, bytes, callback) {
    var bits = [];
    var state = {index: 2};
    // Skip the spaces and comments post-signature.
    skipPostSignature(bytes, state);
    // Read numbers and stick them into 'width' until whitespace.
    var width = accumulateRegex(/\d/, bytes, state).join("");
    skipRegex(/\s/, bytes, state);
    // Read numbers and stick them into 'height' until whitespace.
    var height = accumulateRegex(/\d/, bytes, state).join("");
    skipRegex(/\s/, bytes, state);
    // Initialize the mask.
    m.w = parseInt(width, 10);
    m.h = parseInt(height, 10);
    // Read each byte, in sequence.
    for (; state.index < bytes.byteLength; state.index++) {
      if (bits.length === m.h - 1 &&
          bits[bits.length - 1].length === m.w - 1) {
        break;
      }
      else if (!bits.length || bits[bits.length - 1].length >= m.w) {
        bits.push([]);
      }
      for (var b = 0; b < 8; b++) {
        if (bits[bits.length - 1].length < m.w) {
          var bit = Boolean((bytes[state.index] >> (7 - b)) & 0x01);
          bits[bits.length - 1].push(bit);
        }
      }
    }
    m.data = bits;
    callback(m);
  };
  /** Create a `Mask` from a PBM image at some URL.
   *
   * @param {String} url A URL pointing to a PBM image.
   * @param {MaskCallback} callback
   * @api public
   */
  Mask.PBM.url = function (url, callback) {
    var req = new XMLHttpRequest();
    req.responseType = "arraybuffer";
    req.onload = function (ev) {
      if (req.response) {
        return Mask.fromPBM(req.response, callback);
      } else {
        // No response.
        return callback(null, new Error("No response."));
      }
    };
    req.onerror = function (e) {
      return callback(null, e);
    };
    req.open("GET", url, true);
    req.send();
  };
  /** Create an object representing the intersection of the bounding
   * boxes of two objects.
   *
   * @api private
   */
  function intersection (a, b) {
    var a_2 = {x: a.x + a.w, y: a.y + a.h};
    var b_2 = {x: b.x + b.w, y: b.y + b.h};
    var overlap = {x: a.x > b.x ? a.x : b.x,
                   y: a.y > b.y ? a.y : b.y};
    overlap.w = (a_2.x < b_2.x ? a_2.x : b_2.x) - overlap.x;
    overlap.h = (a_2.y < b_2.y ? a_2.y : b_2.y) - overlap.y;
    return overlap;
  }
  /** Test whether two Masks collide.
   *
   * @param {Mask} a
   * @param {Mask} b
   * @api public
   */
  Mask.collision = function (a, b) {
    var intersect = intersection(a, b);
    for (var x = intersect.x; x < intersect.x + intersect.w; x++) {
      for (var y = intersect.y; y < intersect.y + intersect.h; y++) {
        if (a.collidesAt(x, y) &&
            b.collidesAt(x, y)) {
          return true;
        }
      }
    }
    return false;
  };
  /** Create a mask as an inversion of another.
   *
   * @constructor
   * @param {Mask} other
   * @api public
   */
  Mask.Invert = function (other) {
    this.x = other.x;
    this.y = other.y;
    this.w = other.w;
    this.h = other.h;
    this.inversion = other;
  };
  Mask.Invert.prototype = new Mask();
  Mask.Invert.prototype.collidesAt = function (x, y) {
    return !this.inversion.collidesAt(x, y);
  };
  /** Create a vector box mask.
   *
   * @constructor
   * @param {Number} w width
   * @param {Number} h height
   * @api public
   */
  Mask.Box = function (w, h) {
    this.x = 0;
    this.y = 0;
    this.w = w;
    this.h = h;
  };
  Mask.Box.prototype = new Mask();
  Mask.Box.prototype.clone = function () {
    var other = new Mask.Box(this.w, this.h);
    other.translate(this.x, this.y);
    return other;
  };
  Mask.Box.prototype.collidesAt = function (x, y) {
    return x >= this.x && y >= this.y &&
      x <= (this.x + this.w) && y <= (this.y + this.h);
  };
  /*!*/
  if (typeof module !== "undefined") {
    module.exports = { Mask: Mask };
  }
  return Mask;
})();
<commit_msg>Mask.Invert#clone<commit_after>/** This is `mask`, a tiny MIT-licensed library providing collision masks
 * and thus pixel-perfect collision detection in JavaScript. Collision
 * masks are read from [PBM][] files. Check the [github][] page for more
 * information.
 * [github]: https://github.com/startling/mask
 * [PBM]: http://netpbm.sourceforge.net/doc/pbm.html
 */
/*!*/
var Mask = (function () {
  /** Construct a `Mask`.
   *
   * Examples:
   *
   *     new Mask()
   *
   * @constructor
   * @api public
   */
  function Mask () {
    this.x = this.y = this.w = this.h = 0;
  }
  /** Make a clone of a `Mask`.
   *
   * @this {Mask}
   * @api public
   */
  Mask.prototype.clone = function () {
    var other = new Mask();
    other.x = this.x;
    other.y = this.y;
    other.w = this.w;
    other.h = this.h;
    return other;
  };
  /** Translate this `Mask` in two dimensions.
   *
   * @this {Mask}
   * @param {Number} x x-distance
   * @param {Number} y y-distancex
   * @api public
   */
  Mask.prototype.translate = function (x, y) {
    this.x += x;
    this.y += y;
  };
  /** Make a copy of this `Mask` translated to the coordinates given.
   *
   * @this {Mask}
   * @param {Number} x x-coordinate
   * @param {Number} y y-coordinate
   * @return {Mask}
   * @api public
   */
  Mask.prototype.at = function (x, y) {
    var other = this.clone();
    other.x = x;
    other.y = y;
    return other;
  };
  /** Mask a copy of this `Mask` translated in two dimensions.
   * @this {Mask}
   * @param {Number} x x-distance
   * @param {Number} y y-distance
   * @return {Mask}
   * @api public
   */
  Mask.prototype.translated = function (x, y) {
    var other = this.clone();
    other.translate(x, y);
    return other;
  };
  /** Test whether a Mask is completely contained within another.
   *
   * @this {Mask}
   * @param {Mask} b The containing Mask.
   * @api public
   */
  Mask.prototype.within = function (b) {
    var intersect = intersection(this, b);
    for (var x = intersect.x; x < intersect.w; x++) {
      for (var y = intersect.y; y < intersect.h; y++) {
        if (this.collidesAt(x, y) &&
            !b.collidesAt(x, y)) {
          return false;
        }
      }
    }
    return true;
  };
  /** Test whether this mask collides at the given location.
   *
   * @this {Mask}
   * @param {Number} x x-coordinate
   * @param {Number} y y-coordinate
   * @return {Mask}
   * @api public
   */
  Mask.prototype.collidesAt = function (x, y) {
    return false;
  };
  /** Some callbacks expect a `Mask`.
   * @callback MaskCallback
   * @param {Mask} the collision map
   * @api private
   */
  /** Create a `Mask` object from an `ArrayBuffer` taken as a PBM image.
   *
   * N.B. do not use the newly-constructed `Mask` directly until
   * the callback is called.
   *
   * @constructor
   * @param {ArrayBuffer} array image data
   * @param {MaskCallback} callback
   * @api public
   */
  Mask.PBM = function (array, callback) {
    Mask.bind(this)();
    this.data = null;
    var bytes = new Uint8Array(array);
    if (bytes.byteLength > 2) {
      if (bytes[0] === 'P'.charCodeAt(0)) {
        if (bytes[1] === '4'.charCodeAt(0)) {
          // This is a PBM binary file...
          return fromBinaryPBM(this, bytes, callback);
        } else if (bytes[1] == "1".charCodeAt(0)) {
          // This is a PBM ASCII file...
          return fromASCIIPBM(this, bytes, callback);
        } else {
          // Unknown signature.
          return callback(null, new Error("Unknown PBM signature."));
        }
      } else {
        // Unknown signature.
        return callback(null, new Error("Unknown PBM signature."));
      }
    } else {
      // File too short.
      return callback(null, Error("Invalid PBM image."));
    }
  };
  Mask.PBM.prototype = new Mask();
  Mask.PBM.prototype.clone = function () {
    var other = this.__proto__.clone();
    other.data = this.data;
    return other;
  };
  Mask.PBM.prototype.collidesAt = function (x, y) {
    return !!this.data[x - this.x] &&
      !!this.data[x - this.x][y - this.y];
  };
  /** Skip every byte matching a regular expression.
   *
   * @api private
   * @param {RegExp} regex regular expression
   * @param {Uint8Buffer} bytes character data
   * @param {object} state parser state
   */
  function skipRegex (regex, bytes, state) {
    for (; state.index < bytes.byteLength; state.index++) {
      var here = String.fromCharCode(bytes[state.index]);
      if (!here.match(regex)) {
        break;
      }
    }
  }
  /** Find all the leading characters matching a regular expression and
   * stick them in an array.
   *
   * @api private
   * @param {RegExp} regex regular expression
   * @param {Uint8Buffer} bytes character data
   * @param {object} state parser state
   * @return {Array}
   */
  function accumulateRegex (regex, bytes, state) {
    var accumulator = [];
    for (; state.index < bytes.byteLength; state.index++) {
      var here = String.fromCharCode(bytes[state.index]);
      if (here.match(regex)) {
        accumulator.push(here);
      } else {
        break;
      }
    }
    return accumulator;
  }
  /** Skip the parts that come after a PBM signature -- whitespace and any
   * number of comments.
   *
   * @api private
   * @param {Uint8Buffer} bytes character data
   * @param {object} state parser state
   */
  function skipPostSignature (bytes, state) {
    skipRegex(/\s/, bytes, state);
    var here = String.fromCharCode(bytes[state.index]);
    while (here === '#') {
      state.index++;
      skipRegex(/[^\n]/, bytes, state);
      skipRegex(/\s/, bytes, state);
      here = String.fromCharCode(bytes[state.index]);
    }
  }
  /** Create a `Mask` from an Uint8Array taken semantically as an ASCII PBM image.
   *
   * @param {Uint8Buffer} bytes PBM image data.
   * @param {MaskCallback} callback
   * @api private
   */
  fromASCIIPBM = function (m, bytes, callback) {
    var bits = [];
    var state = {index: 2};
    // Skip the spaces and comments post-signature.
    skipPostSignature(bytes, state);
    var width = accumulateRegex(/\d/, bytes, state).join("");
    skipRegex(/\s/, bytes, state);
    // Read numbers and stick them into 'height' until whitespace.
    var height = accumulateRegex(/\d/, bytes, state).join("");
    skipRegex(/\s/, bytes, state);
    // Initialize the mask.
    m.w = parseInt(width, 10);
    m.h = parseInt(height, 10);
    // Read 0 and 1 until the end of the file, skipping everything else.
    for (; state.index < bytes.byteLength; state.index++) {
      function add (x) {
        if (!bits.length || bits[bits.length - 1].length === m.w) {
          bits.push([]);
        }
        bits[bits.length - 1].push(x);
      }
      switch (bytes[state.index]) {
      case '0'.charCodeAt(0):
        add(false);
        break;
      case '1'.charCodeAt(0):
        add(true);
        break;
      default:
        break;
      }
    }
    m.data = bits;
    return callback(m);
  };
  /** Create a `Mask` from an Uint8Array taken semantically as an binary
   * PBM image.
   *
   * @param {Uint8Buffer} bytes PBM image data.
   * @param {MaskCallback} callback
   * @api private
   */
  fromBinaryPBM = function (m, bytes, callback) {
    var bits = [];
    var state = {index: 2};
    // Skip the spaces and comments post-signature.
    skipPostSignature(bytes, state);
    // Read numbers and stick them into 'width' until whitespace.
    var width = accumulateRegex(/\d/, bytes, state).join("");
    skipRegex(/\s/, bytes, state);
    // Read numbers and stick them into 'height' until whitespace.
    var height = accumulateRegex(/\d/, bytes, state).join("");
    skipRegex(/\s/, bytes, state);
    // Initialize the mask.
    m.w = parseInt(width, 10);
    m.h = parseInt(height, 10);
    // Read each byte, in sequence.
    for (; state.index < bytes.byteLength; state.index++) {
      if (bits.length === m.h - 1 &&
          bits[bits.length - 1].length === m.w - 1) {
        break;
      }
      else if (!bits.length || bits[bits.length - 1].length >= m.w) {
        bits.push([]);
      }
      for (var b = 0; b < 8; b++) {
        if (bits[bits.length - 1].length < m.w) {
          var bit = Boolean((bytes[state.index] >> (7 - b)) & 0x01);
          bits[bits.length - 1].push(bit);
        }
      }
    }
    m.data = bits;
    callback(m);
  };
  /** Create a `Mask` from a PBM image at some URL.
   *
   * @param {String} url A URL pointing to a PBM image.
   * @param {MaskCallback} callback
   * @api public
   */
  Mask.PBM.url = function (url, callback) {
    var req = new XMLHttpRequest();
    req.responseType = "arraybuffer";
    req.onload = function (ev) {
      if (req.response) {
        return Mask.fromPBM(req.response, callback);
      } else {
        // No response.
        return callback(null, new Error("No response."));
      }
    };
    req.onerror = function (e) {
      return callback(null, e);
    };
    req.open("GET", url, true);
    req.send();
  };
  /** Create an object representing the intersection of the bounding
   * boxes of two objects.
   *
   * @api private
   */
  function intersection (a, b) {
    var a_2 = {x: a.x + a.w, y: a.y + a.h};
    var b_2 = {x: b.x + b.w, y: b.y + b.h};
    var overlap = {x: a.x > b.x ? a.x : b.x,
                   y: a.y > b.y ? a.y : b.y};
    overlap.w = (a_2.x < b_2.x ? a_2.x : b_2.x) - overlap.x;
    overlap.h = (a_2.y < b_2.y ? a_2.y : b_2.y) - overlap.y;
    return overlap;
  }
  /** Test whether two Masks collide.
   *
   * @param {Mask} a
   * @param {Mask} b
   * @api public
   */
  Mask.collision = function (a, b) {
    var intersect = intersection(a, b);
    for (var x = intersect.x; x < intersect.x + intersect.w; x++) {
      for (var y = intersect.y; y < intersect.y + intersect.h; y++) {
        if (a.collidesAt(x, y) &&
            b.collidesAt(x, y)) {
          return true;
        }
      }
    }
    return false;
  };
  /** Create a mask as an inversion of another.
   *
   * @constructor
   * @param {Mask} other
   * @api public
   */
  Mask.Invert = function (other) {
    this.x = other.x;
    this.y = other.y;
    this.w = other.w;
    this.h = other.h;
    this.inversion = other;
  };
  Mask.Invert.prototype = new Mask();
  Mask.Invert.prototype.clone = function () {
    var other = new Mask.Invert(this.inversion);
    other.translate(this.x, this.y);
    return other;
  }
  Mask.Invert.prototype.collidesAt = function (x, y) {
    return !this.inversion.collidesAt(x, y);
  };
  /** Create a vector box mask.
   *
   * @constructor
   * @param {Number} w width
   * @param {Number} h height
   * @api public
   */
  Mask.Box = function (w, h) {
    this.x = 0;
    this.y = 0;
    this.w = w;
    this.h = h;
  };
  Mask.Box.prototype = new Mask();
  Mask.Box.prototype.clone = function () {
    var other = new Mask.Box(this.w, this.h);
    other.translate(this.x, this.y);
    return other;
  };
  Mask.Box.prototype.collidesAt = function (x, y) {
    return x >= this.x && y >= this.y &&
      x <= (this.x + this.w) && y <= (this.y + this.h);
  };
  /*!*/
  if (typeof module !== "undefined") {
    module.exports = { Mask: Mask };
  }
  return Mask;
})();
<|endoftext|>


<commit_before>Mat4 = {};

Mat4.create = function() { // Creates a identity 64-bit float array
	var m = new Float64Array(16);
	m[0] = 1; m[5] = 1; m[10] = 1; m[15] = 1;
	return m;
}

Mat4.create32 = function() { // Creates a identity 32-bit float array, for use in webgl calls
	var m = new Float32Array(16);
	m[0] = 1; m[5] = 1; m[10] = 1; m[15] = 1;
	return m;
}

Mat4.copy = function(out, m) {
	out[0] = m[0]; out[4] = m[4]; out[8]  = m[8];  out[12] = m[12];
	out[1] = m[1]; out[5] = m[5]; out[9]  = m[8];  out[13] = m[13];
	out[2] = m[2]; out[6] = m[6]; out[10] = m[10]; out[14] = m[14];
	out[3] = m[3]; out[7] = m[7]; out[11] = m[11]; out[15] = m[15];
}

Mat4.setZero = function(out) {
	out[0] = 0; out[4] = 0; out[8]  = 0; out[12] = 0;
	out[1] = 0; out[5] = 0; out[9]  = 0; out[13] = 0;
	out[2] = 0; out[6] = 0; out[10] = 0; out[14] = 0;
	out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 0;
}

Mat4.setIdentity = function(out) {
	out[0] = 1; out[4] = 0; out[8]  = 0; out[12] = 0;
	out[1] = 0; out[5] = 1; out[9]  = 0; out[13] = 0;
	out[2] = 0; out[6] = 0; out[10] = 1; out[14] = 0;
	out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 1;
}

Mat4.setTR = function(out, v, q) { // rotate then translate matrix
	out[0]  = 1 - 2 * (q.v[1] * q.v[1] + q.v[2] * q.v[2]);
	out[1]  = 2 * (q.v[0] * q.v[1] + q.w * q.v[2]);
	out[2]  = 2 * (q.v[2] * q.v[0] - q.w * q.v[1]);
	out[3]  = 0;
	out[4]  = 2 * (q.v[0] * q.v[1] - q.w * q.v[2]);
	out[5]  = 1 - 2 * (q.v[2] * q.v[2] + q.v[0] * q.v[0]);
	out[6]  = 2 * (q.v[1] * q.v[2] + q.w * q.v[0]);
	out[7]  = 0;
	out[8]  = 2 * (q.v[2] * q.v[0] + q.w * q.v[1]);
	out[9]  = 2 * (q.v[1] * q.v[2] - q.w * q.v[0]);
	out[10] = 1 - 2 * (q.v[0] * q.v[0] + q.v[1] * q.v[1]);
	out[11] = 0;
	out[12] = v[0];
	out[13] = v[1];
	out[14] = v[2];
	out[15] = 1;
}

Mat4.setTRInv = function(out, v, q) { // rotate then translate matrix
	out[0]  = 1 - 2 * (q.v[1] * q.v[1] + q.v[2] * q.v[2]);
	out[1]  = 2 * (q.v[0] * q.v[1] - q.w * q.v[2]);
	out[2]  = 2 * (q.v[2] * q.v[0] + q.w * q.v[1]);
	out[3]  = 0;
	out[4]  = 2 * (q.v[0] * q.v[1] + q.w * q.v[2]);
	out[5]  = 1 - 2 * (q.v[2] * q.v[2] + q.v[0] * q.v[0]);
	out[6]  = 2 * (q.v[1] * q.v[2] - q.w * q.v[0]);
	out[7]  = 0;
	out[8]  = 2 * (q.v[2] * q.v[0] - q.w * q.v[1]);
	out[9]  = 2 * (q.v[1] * q.v[2] + q.w * q.v[0]);
	out[10] = 1 - 2 * (q.v[0] * q.v[0] + q.v[1] * q.v[1]);
	out[11] = 0;
	out[12] = -out[0] * v[0] - out[4] * v[1] - out[8] * v[2];
	out[13] = -out[1] * v[0] - out[5] * v[1] - out[9] * v[2];
	out[14] = -out[2] * v[0] - out[6] * v[1] - out[10] * v[2];
	out[15] = 1;
}

Mat4.setTRS = function(out, v, q, s) { // scale then rotate then translate matrix
	Mat4.setTR(out, v, q);
	out[0]  *= s[0];
	out[1]  *= s[0];
	out[2]  *= s[0];
	out[4]  *= s[1];
	out[5]  *= s[1];
	out[6]  *= s[1];
	out[8]  *= s[2];
	out[9]  *= s[2];
	out[10] *= s[2];
}

Mat4.setTRS = function(out, v, q, s) { // scale then rotate then translate matrix
	Mat4.setTRInv(out, v, q);
	out[0]  /= s[0];
	out[5]  /= s[1];
	out[10] /= s[2];
}

Mat4.mult = function(out, m0, m1) {
	out[0]  = m0[0] * m1[0]  + m0[4] * m1[1]  + m0[8]  * m1[2]  + m0[12] * m1[3];
	out[1]  = m0[1] * m1[0]  + m0[5] * m1[1]  + m0[8]  * m1[2]  + m0[13] * m1[3];
	out[2]  = m0[2] * m1[0]  + m0[6] * m1[1]  + m0[10] * m1[2]  + m0[14] * m1[3];
	out[3]  = m0[3] * m1[0]  + m0[7] * m1[1]  + m0[11] * m1[2]  + m0[15] * m1[3];
	out[4]  = m0[0] * m1[4]  + m0[4] * m1[5]  + m0[8]  * m1[6]  + m0[12] * m1[7];
	out[5]  = m0[1] * m1[4]  + m0[5] * m1[5]  + m0[9]  * m1[6]  + m0[13] * m1[7];
	out[6]  = m0[2] * m1[4]  + m0[6] * m1[5]  + m0[10] * m1[6]  + m0[14] * m1[7];
	out[7]  = m0[3] * m1[4]  + m0[7] * m1[5]  + m0[11] * m1[6]  + m0[15] * m1[7];
	out[8]  = m0[0] * m1[8]  + m0[4] * m1[9]  + m0[8]  * m1[10] + m0[12] * m1[11];
	out[9]  = m0[1] * m1[8]  + m0[5] * m1[9]  + m0[9]  * m1[10] + m0[13] * m1[11];
	out[10] = m0[2] * m1[8]  + m0[6] * m1[9]  + m0[10] * m1[10] + m0[14] * m1[11];
	out[11] = m0[3] * m1[8]  + m0[7] * m1[9]  + m0[11] * m1[10] + m0[15] * m1[11];
	out[12] = m0[0] * m1[12] + m0[4] * m1[13] + m0[8]  * m1[14] + m0[12] * m1[15];
	out[13] = m0[1] * m1[12] + m0[5] * m1[13] + m0[9]  * m1[14] + m0[13] * m1[15];
	out[14] = m0[2] * m1[12] + m0[6] * m1[13] + m0[10] * m1[14] + m0[14] * m1[15];
	out[15] = m0[3] * m1[12] + m0[7] * m1[13] + m0[11] * m1[14] + m0[15] * m1[15];
}

Mat4.multVec3 = function(out, m, v, w) { // returns a Vec3 and uses w as the fourth component
	out[0] = m[0] * v[0] + m[4] * v[1] + m[8]  * v[2] + m[12] * w;
	out[1] = m[1] * v[0] + m[5] * v[1] + m[8]  * v[2] + m[13] * w;
	out[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * w;
	out[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * w;
}

<commit_msg>Fixed bugs and added toString in mat4<commit_after>Mat4 = {};

Mat4.create = function() { // Creates a identity 64-bit float array
	var m = new Float64Array(16);
	m[0] = 1; m[5] = 1; m[10] = 1; m[15] = 1;
	return m;
}

Mat4.create32 = function() { // Creates a identity 32-bit float array, for use in webgl calls
	var m = new Float32Array(16);
	m[0] = 1; m[5] = 1; m[10] = 1; m[15] = 1;
	return m;
}

Mat4.copy = function(out, m) {
	out[0] = m[0]; out[4] = m[4]; out[8]  = m[8];  out[12] = m[12];
	out[1] = m[1]; out[5] = m[5]; out[9]  = m[8];  out[13] = m[13];
	out[2] = m[2]; out[6] = m[6]; out[10] = m[10]; out[14] = m[14];
	out[3] = m[3]; out[7] = m[7]; out[11] = m[11]; out[15] = m[15];
}

Mat4.setZero = function(out) {
	out[0] = 0; out[4] = 0; out[8]  = 0; out[12] = 0;
	out[1] = 0; out[5] = 0; out[9]  = 0; out[13] = 0;
	out[2] = 0; out[6] = 0; out[10] = 0; out[14] = 0;
	out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 0;
}

Mat4.setIdentity = function(out) {
	out[0] = 1; out[4] = 0; out[8]  = 0; out[12] = 0;
	out[1] = 0; out[5] = 1; out[9]  = 0; out[13] = 0;
	out[2] = 0; out[6] = 0; out[10] = 1; out[14] = 0;
	out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 1;
}

Mat4.setTR = function(out, v, q) { // rotate then translate matrix
	out[0]  = 1 - 2 * (q[1] * q[1] + q[2] * q[2]);
	out[1]  = 2 * (q[0] * q[1] + q[3] * q[2]);
	out[2]  = 2 * (q[2] * q[0] - q[3] * q[1]);
	out[3]  = 0;
	out[4]  = 2 * (q[0] * q[1] - q[3] * q[2]);
	out[5]  = 1 - 2 * (q[2] * q[2] + q[0] * q[0]);
	out[6]  = 2 * (q[1] * q[2] + q[3] * q[0]);
	out[7]  = 0;
	out[8]  = 2 * (q[2] * q[0] + q[3] * q[1]);
	out[9]  = 2 * (q[1] * q[2] - q[3] * q[0]);
	out[10] = 1 - 2 * (q[0] * q[0] + q[1] * q[1]);
	out[11] = 0;
	out[12] = v[0];
	out[13] = v[1];
	out[14] = v[2];
	out[15] = 1;
}

Mat4.setTRInv = function(out, v, q) { // rotate then translate matrix
	out[0]  = 1 - 2 * (q[1] * q[1] + q[2] * q[2]);
	out[1]  = 2 * (q[0] * q[1] - q[3] * q[2]);
	out[2]  = 2 * (q[2] * q[0] + q[3] * q[1]);
	out[3]  = 0;
	out[4]  = 2 * (q[0] * q[1] + q[3] * q[2]);
	out[5]  = 1 - 2 * (q[2] * q[2] + q[0] * q[0]);
	out[6]  = 2 * (q[1] * q[2] - q[3] * q[0]);
	out[7]  = 0;
	out[8]  = 2 * (q[2] * q[0] - q[3] * q[1]);
	out[9]  = 2 * (q[1] * q[2] + q[3] * q[0]);
	out[10] = 1 - 2 * (q[0] * q[0] + q[1] * q[1]);
	out[11] = 0;
	out[12] = -out[0] * v[0] - out[4] * v[1] - out[8] * v[2];
	out[13] = -out[1] * v[0] - out[5] * v[1] - out[9] * v[2];
	out[14] = -out[2] * v[0] - out[6] * v[1] - out[10] * v[2];
	out[15] = 1;
}

Mat4.setTRS = function(out, v, q, s) { // scale then rotate then translate matrix
	Mat4.setTR(out, v, q);
	out[0]  *= s[0];
	out[1]  *= s[0];
	out[2]  *= s[0];
	out[4]  *= s[1];
	out[5]  *= s[1];
	out[6]  *= s[1];
	out[8]  *= s[2];
	out[9]  *= s[2];
	out[10] *= s[2];
}

Mat4.setTRS = function(out, v, q, s) { // scale then rotate then translate matrix
	Mat4.setTRInv(out, v, q);
	out[0]  /= s[0];
	out[5]  /= s[1];
	out[10] /= s[2];
}

Mat4.mult = function(out, m0, m1) {
	out[0]  = m0[0] * m1[0]  + m0[4] * m1[1]  + m0[8]  * m1[2]  + m0[12] * m1[3];
	out[1]  = m0[1] * m1[0]  + m0[5] * m1[1]  + m0[9]  * m1[2]  + m0[13] * m1[3];
	out[2]  = m0[2] * m1[0]  + m0[6] * m1[1]  + m0[10] * m1[2]  + m0[14] * m1[3];
	out[3]  = m0[3] * m1[0]  + m0[7] * m1[1]  + m0[11] * m1[2]  + m0[15] * m1[3];
	out[4]  = m0[0] * m1[4]  + m0[4] * m1[5]  + m0[8]  * m1[6]  + m0[12] * m1[7];
	out[5]  = m0[1] * m1[4]  + m0[5] * m1[5]  + m0[9]  * m1[6]  + m0[13] * m1[7];
	out[6]  = m0[2] * m1[4]  + m0[6] * m1[5]  + m0[10] * m1[6]  + m0[14] * m1[7];
	out[7]  = m0[3] * m1[4]  + m0[7] * m1[5]  + m0[11] * m1[6]  + m0[15] * m1[7];
	out[8]  = m0[0] * m1[8]  + m0[4] * m1[9]  + m0[8]  * m1[10] + m0[12] * m1[11];
	out[9]  = m0[1] * m1[8]  + m0[5] * m1[9]  + m0[9]  * m1[10] + m0[13] * m1[11];
	out[10] = m0[2] * m1[8]  + m0[6] * m1[9]  + m0[10] * m1[10] + m0[14] * m1[11];
	out[11] = m0[3] * m1[8]  + m0[7] * m1[9]  + m0[11] * m1[10] + m0[15] * m1[11];
	out[12] = m0[0] * m1[12] + m0[4] * m1[13] + m0[8]  * m1[14] + m0[12] * m1[15];
	out[13] = m0[1] * m1[12] + m0[5] * m1[13] + m0[9]  * m1[14] + m0[13] * m1[15];
	out[14] = m0[2] * m1[12] + m0[6] * m1[13] + m0[10] * m1[14] + m0[14] * m1[15];
	out[15] = m0[3] * m1[12] + m0[7] * m1[13] + m0[11] * m1[14] + m0[15] * m1[15];
}

Mat4.multVec3 = function(out, m, v, w) { // returns a Vec3 and uses w as the fourth component
	out[0] = m[0] * v[0] + m[4] * v[1] + m[8]  * v[2] + m[12] * w;
	out[1] = m[1] * v[0] + m[5] * v[1] + m[9]  * v[2] + m[13] * w;
	out[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * w;
	out[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * w;
}

Mat4.toString = function(m) {
	return m[0] + ',' + m[4] + ',' + m[8]  + ',' + m[12] + '\n'
		+ m[1] + ',' + m[5] + ',' + m[9]  + ',' + m[13] + '\n'
		+ m[2] + ',' + m[6] + ',' + m[10] + ',' + m[14] + '\n'
		+ m[3] + ',' + m[7] + ',' + m[11] + ',' + m[15];
}<|endoftext|>


<commit_before>var FILE_PATH = "/Users/pete/iMacros/Macros/jcrawler/{0}";
var REGEX_HREF = new RegExp("href=\"[^\"]+\"", "gi");

// Source: http://forum.iopus.com/viewtopic.php?f=11&t=5267
// Note: this may not work depending on Java version(?)
write_file = function(path, data) {
  iimDisplay("Writing file:"+path);
   try {
      var out = new java.io.BufferedWriter(new java.io.OutputStreamWriter(new java.io.FileOutputStream(new java.io.File(path)), "UTF8"));
      out.write(data);
      out.close();
      out=null;
   }
   catch(e) { //catch and report any errors
      alert(""+e);
   }
};

// Source: http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format/4256130#4256130
String.prototype.format = function() {
  var formatted = this;
  for (var i = 0; i < arguments.length; i++) {
    var regexp = new RegExp('\\{'+i+'\\}', 'gi');
    formatted = formatted.replace(regexp, arguments[i]);
  }
  return formatted;
};

// Source: http://stackoverflow.com/questions/646628/javascript-startswith
if (typeof String.prototype.startsWith != 'function') {
  String.prototype.startsWith = function (str){
    return this.slice(0, str.length) == str;
  };
}

// Source: http://stackoverflow.com/questions/280634/endswith-in-javascript
if (typeof String.prototype.endsWith != 'function') {
  String.prototype.endsWith = function(suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
  };
}

// inclusive random range
// Source: http://www.admixweb.com/2010/08/24/javascript-tip-get-a-random-number-between-two-integers/
random_range = function(from, to){
  var val = Math.floor(Math.random() * (to - from + 1) + from);
  if(val > to) { // in case Math.random() can produce 1.0 (does it?)
    val = to;
  }
  return val;
};

// Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date
function date_string(d){
 function pad(n){return n<10 ? '0'+n : n}
 return d.getUTCFullYear()+''
      + pad(d.getUTCMonth()+1)+''
      + pad(d.getUTCDate())+''
      + pad(d.getUTCHours())+''
      + pad(d.getUTCMinutes())+''
      + pad(d.getUTCSeconds())}

srswor = function(list, n, ignore) {
  if(!ignore) ignore = [];
  for(var i=0; i<ignore.length; i++) {
    var idx = list.indexOf(ignore[i]);
    if(idx >= 0) list.splice(idx, 1);
  }
  if(list.length < n) return list;
  var new_list = [];
  while(new_list.length < n && list.length > 0) {
    var rand_idx = random_range(0, list.length - 1);
    new_list.push(list.splice(rand_idx, 1));
  }
  return new_list;
};

run = function(code, n) {
  var retcode = iimPlay("CODE: "+code);
  if(retcode != 1) {
    alert("BAD CODE:\n"+code+"\n\nretcode:"+retcode);
    return;
  }
  if(n) {
    var extract = iimGetLastExtract(n);
    if(extract == "#EANF#") return false; // "Extraction Anchor Not Found"
    return extract;
  }
};

sleep = function(seconds) { run("WAIT SECONDS="+seconds); };
visit_url = function(url) { run("URL GOTO="+url); };

save_profile = function(id) {
  var raw_profile = run("TAG POS=1 TYPE=DIV ATTR=CLASS:prof1-lay EXTRACT=HTM", 1);
  var filename = date_string(new Date())+"_"+id+".data";
  var path = FILE_PATH.format("data/mbga/person/"+filename);
  write_file(path, raw_profile);
};

save_group = function(id) {
  var raw_group = run("TAG POS=1 TYPE=UL ATTR=CLASS:blk-lay EXTRACT=HTM", 1);
  var filename = date_string(new Date())+"_"+id+".data";
  var path = FILE_PATH.format("data/mbga/group/"+filename);
  write_file(path, raw_group);
};

visit_profile = function(id) {

};

visit_group = function(id) {

};

extract_profiles = function() {

};

extract_groups = function() {
  var raw = run("TAG POS=1 TYPE=DIV ATTR=ID:circleentry-sec EXTRACT=HTM", 1);
  var links = raw.match(REGEX_HREF);
  links.pop(); // last link isn't a group link
  var mod_links = [];
  for(var i=0; i<links.length; i++) {
    if(i % 2 == 0)
      mod_links.push({
        type:"group",
        id: links[i].substring(13, links[i].length - 1)
      });
  }
  return mod_links;
};

main = function() {
  //save_profile("http://yahoo-mbga.jp/10086","10086");
  //save_group("http://yahoo-mbga.jp/group/31966079", "31966079");

  var queue = []; // TODO seed nodes
  var visited_groups = [];
  var visited_profiles = [];
  while(queue.length > 0){
    var item = queue.shift();
    if(item["type"] === "profile") {
      if(visited_profiles.indexOf(item["id"]) < 0) continue;
      visit_profile(item["id"]);
      save_profile(item["id"]);
      visited_profiles.push(item["id"]);
      queue.concat(extract_groups());
    }
    else {
      if(visited_groups.indexOf(item["id"]) < 0) continue;
      visit_group(item["id"]);
      save_group(item["id"]);
      visited_groups.push(item["id"]);
      queue.concat(extract_profiles());
    }
  }
};

main();<commit_msg>extract_profiles<commit_after>var FILE_PATH = "/Users/pete/iMacros/Macros/jcrawler/{0}";
var REGEX_HREF = new RegExp("href=\"[^\"]+\"", "gi");

// Source: http://forum.iopus.com/viewtopic.php?f=11&t=5267
// Note: this may not work depending on Java version(?)
write_file = function(path, data) {
  iimDisplay("Writing file:"+path);
   try {
      var out = new java.io.BufferedWriter(new java.io.OutputStreamWriter(new java.io.FileOutputStream(new java.io.File(path)), "UTF8"));
      out.write(data);
      out.close();
      out=null;
   }
   catch(e) { //catch and report any errors
      alert(""+e);
   }
};

// Source: http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format/4256130#4256130
String.prototype.format = function() {
  var formatted = this;
  for (var i = 0; i < arguments.length; i++) {
    var regexp = new RegExp('\\{'+i+'\\}', 'gi');
    formatted = formatted.replace(regexp, arguments[i]);
  }
  return formatted;
};

// Source: http://stackoverflow.com/questions/646628/javascript-startswith
if (typeof String.prototype.startsWith != 'function') {
  String.prototype.startsWith = function (str){
    return this.slice(0, str.length) == str;
  };
}

// Source: http://stackoverflow.com/questions/280634/endswith-in-javascript
if (typeof String.prototype.endsWith != 'function') {
  String.prototype.endsWith = function(suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
  };
}

// inclusive random range
// Source: http://www.admixweb.com/2010/08/24/javascript-tip-get-a-random-number-between-two-integers/
random_range = function(from, to){
  var val = Math.floor(Math.random() * (to - from + 1) + from);
  if(val > to) { // in case Math.random() can produce 1.0 (does it?)
    val = to;
  }
  return val;
};

// Source: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date
function date_string(d){
 function pad(n){return n<10 ? '0'+n : n}
 return d.getUTCFullYear()+''
      + pad(d.getUTCMonth()+1)+''
      + pad(d.getUTCDate())+''
      + pad(d.getUTCHours())+''
      + pad(d.getUTCMinutes())+''
      + pad(d.getUTCSeconds())}

srswor = function(list, n, ignore) {
  if(!ignore) ignore = [];
  for(var i=0; i<ignore.length; i++) {
    var idx = list.indexOf(ignore[i]);
    if(idx >= 0) list.splice(idx, 1);
  }
  if(list.length < n) return list;
  var new_list = [];
  while(new_list.length < n && list.length > 0) {
    var rand_idx = random_range(0, list.length - 1);
    new_list.push(list.splice(rand_idx, 1));
  }
  return new_list;
};

run = function(code, n) {
  var retcode = iimPlay("CODE: "+code);
  if(retcode != 1) {
    alert("BAD CODE:\n"+code+"\n\nretcode:"+retcode);
    return;
  }
  if(n) {
    var extract = iimGetLastExtract(n);
    if(extract == "#EANF#") return false; // "Extraction Anchor Not Found"
    return extract;
  }
};

sleep = function(seconds) { run("WAIT SECONDS="+seconds); };
visit_url = function(url) { run("URL GOTO="+url); };

save_profile = function(id) {
  var raw_profile = run("TAG POS=1 TYPE=DIV ATTR=CLASS:prof1-lay EXTRACT=HTM", 1);
  var filename = date_string(new Date())+"_"+id+".data";
  var path = FILE_PATH.format("data/mbga/person/"+filename);
  write_file(path, raw_profile);
};

save_group = function(id) {
  var raw_group = run("TAG POS=1 TYPE=UL ATTR=CLASS:blk-lay EXTRACT=HTM", 1);
  var filename = date_string(new Date())+"_"+id+".data";
  var path = FILE_PATH.format("data/mbga/group/"+filename);
  write_file(path, raw_group);
};

visit_profile = function(id) {

};

visit_group = function(id) {

};

extract_profiles = function() {
  var raw = run("TAG POS=1 TYPE=DIV ATTR=ID:circlemem-sec EXTRACT=HTM", 1);
  var links = raw.match(REGEX_HREF);
  links.pop(); // last link isn't a profile
  var mod_links = [];
  for(var i=0; i<links.length; i++) {
    if(i % 2 == 0)
      mod_links.push({
        type:"profile",
        id: links[i].substring(7, links[i].length - 1)
      });
  }
  return mod_links;
};

extract_groups = function() {
  var raw = run("TAG POS=1 TYPE=DIV ATTR=ID:circleentry-sec EXTRACT=HTM", 1);
  var links = raw.match(REGEX_HREF);
  links.pop(); // last link isn't a group link
  var mod_links = [];
  for(var i=0; i<links.length; i++) {
    if(i % 2 == 0)
      mod_links.push({
        type:"group",
        id: links[i].substring(13, links[i].length - 1)
      });
  }
  return mod_links;
};

main = function() {
  //save_profile("http://yahoo-mbga.jp/10086","10086");
  //save_group("http://yahoo-mbga.jp/group/31966079", "31966079");

  var queue = []; // TODO seed nodes
  var visited_groups = [];
  var visited_profiles = [];
  while(queue.length > 0){
    var item = queue.shift();
    if(item["type"] === "profile") {
      if(visited_profiles.indexOf(item["id"]) < 0) continue;
      visit_profile(item["id"]);
      save_profile(item["id"]);
      visited_profiles.push(item["id"]);
      queue.concat(extract_groups());
    }
    else {
      if(visited_groups.indexOf(item["id"]) < 0) continue;
      visit_group(item["id"]);
      save_group(item["id"]);
      visited_groups.push(item["id"]);
      queue.concat(extract_profiles());
    }
  }
};

main();<|endoftext|>


<commit_before>// @license
// Copyright (c) 2017 Google Inc. All rights reserved.
// This code may only be used under the BSD style license found at
// http://polymer.github.io/LICENSE.txt
// Code distributed by Google as part of this project is also
// subject to an additional IP rights grant found at
// http://polymer.github.io/PATENTS.txt

'use strict';

defineParticle(({DomParticle, log, html}) => {

  const host = 'arcs-list';

  const style = html`

`;

  let template = html`

${style}

{{columnA}}

{{columnB}}

<template column>

    <icon delete hide$="{{noDelete}}" key="{{arcId}}" on-click="_onDelete">remove_circle_outline</icon>

        <icon show$="{{self}}">account_circle</icon>
        <icon show$="{{friends}}">people</icon>

</template>
`;

  return class extends DomParticle {
    get template() {
      return template;
    }
    willReceiveProps({arcs}) {
      const collation = this._collateItems(arcs);
      this._setState(collation);
    }
    shouldRender(props, state) {
      return Boolean(state.items);
    }
    render(props, {items, profileItems}) {
      const all = items.concat(profileItems);
      const pivot = (all.length + 1) >> 1;
      const columns = [all.slice(0, pivot), all.slice(pivot)];
      return {
        columnA: {
          $template: 'column',
          models: columns[0],
        },
        columnB: {
          $template: 'column',
          models: columns[1],
        }
      };
    }
    _collateItems(arcs) {
      const result = {
        items: [],
        profileItems: []
      };
      arcs.forEach((a, i) => {
        if (!a.deleted) {
          // each item goes in either the `items` or `profileItems` list
          const list = a.profile ? result.profileItems : result.items;
          // massage the description
          //const blurb = a.description.length > 70 ? a.description.slice(0, 70) + '...' : a.description;
          const blurb = a.description;
          const chipStyle = {
            backgroundColor: a.bg || a.color || 'gray',
            color: a.bg ? a.color : 'white',
          };
          // populate the selected list
          list.push({
            arcId: a.id,
            // Don't allow deleting the 'New Arc' arc.
            noDelete: i === 0,
            href: a.href,
            blurb,
            description: a.description,
            icon: a.icon,
            chipStyle,
            self: Boolean(a.profile)
          });
        }
      });
      return result;
    }
    _onDelete(e) {
      const arcId = e.data.key;
      const arc = this._props.arcs.find(a => a.id === arcId);
      if (!arc) {
        log(`Couldn't find arc to delete [arcId=${arcId}].`);
      } else {
        const arcs = this.handles.get('arcs');
        arcs.remove(arc);
        arc.deleted = true;
        arcs.store(arc);
        log(`Marking arc [arcId=${arcId}] for deletion.`);
        //this._views.get('arcs').remove(arc);
      }
    }
    setHandle(name, data) {
      const handle = this._views.get(name);
      handle.set(new (handle.entityClass)(data));
    }
  };
});
<commit_msg>add targets to launcher chips<commit_after>// @license
// Copyright (c) 2017 Google Inc. All rights reserved.
// This code may only be used under the BSD style license found at
// http://polymer.github.io/LICENSE.txt
// Code distributed by Google as part of this project is also
// subject to an additional IP rights grant found at
// http://polymer.github.io/PATENTS.txt

'use strict';

defineParticle(({DomParticle, log, html}) => {

  const host = 'arcs-list';

  const style = html`

`;

  let template = html`

${style}

{{columnA}}

{{columnB}}

<template column>

    <icon delete hide$="{{noDelete}}" key="{{arcId}}" on-click="_onDelete">remove_circle_outline</icon>

        <icon show$="{{self}}">account_circle</icon>
        <icon show$="{{friends}}">people</icon>

</template>
`;

  return class extends DomParticle {
    get template() {
      return template;
    }
    willReceiveProps({arcs}) {
      const collation = this._collateItems(arcs);
      this._setState(collation);
    }
    shouldRender(props, state) {
      return Boolean(state.items);
    }
    render(props, {items, profileItems}) {
      const all = items.concat(profileItems);
      const pivot = (all.length + 1) >> 1;
      const columns = [all.slice(0, pivot), all.slice(pivot)];
      return {
        columnA: {
          $template: 'column',
          models: columns[0],
        },
        columnB: {
          $template: 'column',
          models: columns[1],
        }
      };
    }
    _collateItems(arcs) {
      const result = {
        items: [],
        profileItems: []
      };
      arcs.forEach((a, i) => {
        if (!a.deleted) {
          // each item goes in either the `items` or `profileItems` list
          const list = a.profile ? result.profileItems : result.items;
          // massage the description
          //const blurb = a.description.length > 70 ? a.description.slice(0, 70) + '...' : a.description;
          const blurb = a.description;
          const chipStyle = {
            backgroundColor: a.bg || a.color || 'gray',
            color: a.bg ? a.color : 'white',
          };
          // populate the selected list
          list.push({
            arcId: a.id,
            // Don't allow deleting the 'New Arc' arc.
            noDelete: i === 0,
            href: a.href,
            blurb,
            description: a.description,
            icon: a.icon,
            chipStyle,
            self: Boolean(a.profile)
          });
        }
      });
      return result;
    }
    _onDelete(e) {
      const arcId = e.data.key;
      const arc = this._props.arcs.find(a => a.id === arcId);
      if (!arc) {
        log(`Couldn't find arc to delete [arcId=${arcId}].`);
      } else {
        const arcs = this.handles.get('arcs');
        arcs.remove(arc);
        arc.deleted = true;
        arcs.store(arc);
        log(`Marking arc [arcId=${arcId}] for deletion.`);
        //this._views.get('arcs').remove(arc);
      }
    }
    setHandle(name, data) {
      const handle = this._views.get(name);
      handle.set(new (handle.entityClass)(data));
    }
  };
});
<|endoftext|>


<commit_before>var validator = require('validator');

module.exports = {

  find: function(req, res) {
    Community.fetchAll().then(res.ok).catch(res.serverError);
  },

  findOne: function(req, res) {
    var community = res.locals.community,
      membership = res.locals.membership;

    return Promise.method(() => community.get('network_id') ? community.load('network') : null)()
    .then(() => community.pick('id', 'name', 'slug', 'avatar_url', 'banner_url', 'description', 'settings'))
    .tap(data => {
      var network = community.relations.network;
      if (network) data.network = network.pick('id', 'name', 'slug');
    })
    .tap(() => membership && membership.updateViewedAt())
    .then(res.ok)
    .catch(res.serverError);
  },

  findSettings: function(req, res) {
    var leader;
    Community.find(req.param('communityId'), {withRelated: ['leader']})
    .tap(community => leader = community.relations.leader)
    .then(community => _.merge(community.pick(
      'welcome_message', 'beta_access_code', 'settings'
    ), {
      leader: leader ? leader.pick('id', 'name', 'avatar_url') : null
    }))
    .then(res.ok)
    .catch(res.serverError);
  },

  update: function(req, res) {
    var whitelist = [
        'banner_url', 'avatar_url', 'name', 'description', 'settings',
        'welcome_message', 'leader_id', 'beta_access_code'
      ],
      attributes = _.pick(req.allParams(), whitelist),
      community = new Community({id: req.param('communityId')});

    community.save(attributes, {patch: true})
    .then(() => res.ok({}))
    .catch(res.serverError);
  },

  invite: function(req, res) {
    Community.find(req.param('communityId'))
    .then(function(community) {

      var emails = (req.param('emails') || '').split(',').map(function(email) {
        var trimmed = email.trim(),
          matchLongFormat = trimmed.match(/.*<(.*)>/);

        if (matchLongFormat) return matchLongFormat[1];
        return trimmed;
      });

      return Promise.map(emails, function(email) {
        if (!validator.isEmail(email)) {
          return {email: email, error: "not a valid email address"};
        }

        return Invitation.createAndSend({
          email:       email,
          userId:      req.session.userId,
          communityId: community.id,
          message:     RichText.markdown(req.param('message')),
          moderator:   req.param('moderator'),
          subject:     req.param('subject')
        }).then(function() {
          return {email: email, error: null};
        }).catch(function(err) {
          return {email: email, error: err.message};
        });
      });

    })
    .then(results => res.ok({results: results}));
  },

  findModerators: function(req, res) {
    Community.find(req.param('communityId')).then(function(community) {
      return community.moderators().fetch();
    }).then(function(moderators) {
      res.ok(moderators.map(function(user) {
        return {
          id: user.id,
          name: user.get('name'),
          avatar_url: user.get('avatar_url')
        };
      }));
    });
  },

  addModerator: function(req, res) {
    Membership.setModeratorRole(req.param('userId'), req.param('communityId'))
    .then(() => res.ok({}))
    .catch(res.serverError);
  },

  removeModerator: function(req, res) {
    Membership.removeModeratorRole(req.param('userId'), req.param('communityId'))
    .then(() => res.ok({}))
    .catch(res.serverError);
  },

  joinWithCode: function(req, res) {
    var community;
    Community.query('whereRaw', 'lower(beta_access_code) = lower(?)', req.param('code')).fetch()
    .tap(c => community = c)
    .tap(() => bookshelf.transaction(trx =>
      Promise.join(
        Membership.create(req.session.userId, community.id, {transacting: trx}),
        Post.createWelcomePost(req.session.userId, community.id, trx)
      )))
    .catch(err => {
      if (err.message && err.message.contains('duplicate key value')) {
        return true;
      } else {
        res.serverError(err);
        return false;
      }
    })
    // we get here if the membership was created successfully, or if it already existed
    .then(ok => ok && Membership.find(req.session.userId, community.id)
      .then(membership => _.merge(membership.toJSON(), {
        community: community.pick('id', 'name', 'slug', 'avatar_url')
      }))
      .then(res.ok));
  },

  leave: function(req, res) {
    res.locals.membership.destroyMe()
    .then(() => res.ok({}))
    .catch(res.serverError);
  },

  removeMember: function(req, res) {
    Membership.query().where({
      user_id: req.param('userId'),
      community_id: req.param('communityId')
    }).update({
      active: false,
      deactivated_at: new Date(),
      deactivator_id: req.session.userId
    })
    .then(() => res.ok({}))
    .catch(res.serverError);
  },

  validate: function(req, res) {
    var allowedColumns = ['name', 'slug', 'beta_access_code'],
      allowedConstraints = ['exists', 'unique'],
      params = _.pick(req.allParams(), 'constraint', 'column', 'value');

    // prevent SQL injection
    if (!_.include(allowedColumns, params.column))
      return res.badRequest(format('invalid value "%s" for parameter "column"', params.column));

    if (!params.value)
      return res.badRequest('missing required parameter "value"');

    if (!_.include(allowedConstraints, params.constraint))
      return res.badRequest(format('invalid value "%s" for parameter "constraint"', params.constraint));

    var statement = format('lower(%s) = lower(?)', params.column);
    Community.query().whereRaw(statement, params.value).count()
    .then(function(rows) {
      var data;
      if (params.constraint === 'unique') {
        data = {unique: parseInt(rows[0].count) === 0};
      } else if (params.constraint === 'exists') {
        var exists = parseInt(rows[0].count) >= 1;
        data = {exists: exists};
      }
      res.ok(data);
    })
    .catch(res.serverError.bind(res));
  },

  create: function(req, res) {
    var attrs = _.pick(req.allParams(),
      'name', 'description', 'slug', 'category',
      'beta_access_code', 'banner_url', 'avatar_url');

    var community = new Community(_.merge(attrs, {
      created_at: new Date(),
      created_by_id: req.session.userId
    }));

    if (process.env.NODE_ENV) {
      community.set('leader_id', 21);
      community.set('welcome_message', "Thank you for joining us here at Hylo. " +
        "Through our communities, we can find everything we need. If we share " +
        "with each other the unique gifts and intentions we each have, we can " +
        "create extraordinary things. Let's get started!");
    }

    bookshelf.transaction(function(trx) {
      return community.save(null, {transacting: trx})
      .tap(() => Membership.create(req.session.userId, community.id, {
        role: Membership.MODERATOR_ROLE,
        transacting: trx
      }));
    })
    // The assets were uploaded to /community/new, since we didn't have an id;
    // copy them over to /community/:id now
    .tap(community => Queue.classMethod('Community', 'copyAssets', {communityId: community.id}))
    .tap(community => Queue.classMethod('Community', 'notifyAboutCreate', {communityId: community.id}))
    .tap(() => Tour.skipOnboarding(req.session.userId))
    // FIXME this additional lookup wouldn't be necessary
    // if we had a Membership instance from the previous
    // step. But the absence of an id column on the table
    // doesn't play nice with Bookshelf.
    .then(() => Membership.find(req.session.userId, community.id, {withRelated: ['community']}))
    .then(res.ok)
    .catch(res.serverError);
  },

  findForNetwork: function(req, res) {
    Community.where('network_id', req.param('networkId'))
    .fetchAll({withRelated: ['memberships']})
    .then(communities => communities.map(c =>
      _.extend(c.pick('id', 'name', 'slug', 'avatar_url', 'banner_url'), {
        memberCount: c.relations.memberships.length
      })))
    .then(communities => _.sortBy(communities, c => -c.memberCount))
    .then(res.ok)
    .catch(res.serverError);
  }

};
<commit_msg>add member count to admin list of communities<commit_after>var validator = require('validator');

module.exports = {

  find: function(req, res) {
    Community.fetchAll({withRelated: [
      {memberships: q => q.column('community_id')}
    ]})
    .then(communities => communities.map(c => _.extend(c.toJSON(), {
      memberships: c.relations.memberships.length
    })))
    .then(res.ok, res.serverError);
  },

  findOne: function(req, res) {
    var community = res.locals.community,
      membership = res.locals.membership;

    return Promise.method(() => community.get('network_id') ? community.load('network') : null)()
    .then(() => community.pick('id', 'name', 'slug', 'avatar_url', 'banner_url', 'description', 'settings'))
    .tap(data => {
      var network = community.relations.network;
      if (network) data.network = network.pick('id', 'name', 'slug');
    })
    .tap(() => membership && membership.updateViewedAt())
    .then(res.ok)
    .catch(res.serverError);
  },

  findSettings: function(req, res) {
    var leader;
    Community.find(req.param('communityId'), {withRelated: ['leader']})
    .tap(community => leader = community.relations.leader)
    .then(community => _.merge(community.pick(
      'welcome_message', 'beta_access_code', 'settings'
    ), {
      leader: leader ? leader.pick('id', 'name', 'avatar_url') : null
    }))
    .then(res.ok)
    .catch(res.serverError);
  },

  update: function(req, res) {
    var whitelist = [
        'banner_url', 'avatar_url', 'name', 'description', 'settings',
        'welcome_message', 'leader_id', 'beta_access_code'
      ],
      attributes = _.pick(req.allParams(), whitelist),
      community = new Community({id: req.param('communityId')});

    community.save(attributes, {patch: true})
    .then(() => res.ok({}))
    .catch(res.serverError);
  },

  invite: function(req, res) {
    Community.find(req.param('communityId'))
    .then(function(community) {

      var emails = (req.param('emails') || '').split(',').map(function(email) {
        var trimmed = email.trim(),
          matchLongFormat = trimmed.match(/.*<(.*)>/);

        if (matchLongFormat) return matchLongFormat[1];
        return trimmed;
      });

      return Promise.map(emails, function(email) {
        if (!validator.isEmail(email)) {
          return {email: email, error: "not a valid email address"};
        }

        return Invitation.createAndSend({
          email:       email,
          userId:      req.session.userId,
          communityId: community.id,
          message:     RichText.markdown(req.param('message')),
          moderator:   req.param('moderator'),
          subject:     req.param('subject')
        }).then(function() {
          return {email: email, error: null};
        }).catch(function(err) {
          return {email: email, error: err.message};
        });
      });

    })
    .then(results => res.ok({results: results}));
  },

  findModerators: function(req, res) {
    Community.find(req.param('communityId')).then(function(community) {
      return community.moderators().fetch();
    }).then(function(moderators) {
      res.ok(moderators.map(function(user) {
        return {
          id: user.id,
          name: user.get('name'),
          avatar_url: user.get('avatar_url')
        };
      }));
    });
  },

  addModerator: function(req, res) {
    Membership.setModeratorRole(req.param('userId'), req.param('communityId'))
    .then(() => res.ok({}))
    .catch(res.serverError);
  },

  removeModerator: function(req, res) {
    Membership.removeModeratorRole(req.param('userId'), req.param('communityId'))
    .then(() => res.ok({}))
    .catch(res.serverError);
  },

  joinWithCode: function(req, res) {
    var community;
    Community.query('whereRaw', 'lower(beta_access_code) = lower(?)', req.param('code')).fetch()
    .tap(c => community = c)
    .tap(() => bookshelf.transaction(trx =>
      Promise.join(
        Membership.create(req.session.userId, community.id, {transacting: trx}),
        Post.createWelcomePost(req.session.userId, community.id, trx)
      )))
    .catch(err => {
      if (err.message && err.message.contains('duplicate key value')) {
        return true;
      } else {
        res.serverError(err);
        return false;
      }
    })
    // we get here if the membership was created successfully, or if it already existed
    .then(ok => ok && Membership.find(req.session.userId, community.id)
      .then(membership => _.merge(membership.toJSON(), {
        community: community.pick('id', 'name', 'slug', 'avatar_url')
      }))
      .then(res.ok));
  },

  leave: function(req, res) {
    res.locals.membership.destroyMe()
    .then(() => res.ok({}))
    .catch(res.serverError);
  },

  removeMember: function(req, res) {
    Membership.query().where({
      user_id: req.param('userId'),
      community_id: req.param('communityId')
    }).update({
      active: false,
      deactivated_at: new Date(),
      deactivator_id: req.session.userId
    })
    .then(() => res.ok({}))
    .catch(res.serverError);
  },

  validate: function(req, res) {
    var allowedColumns = ['name', 'slug', 'beta_access_code'],
      allowedConstraints = ['exists', 'unique'],
      params = _.pick(req.allParams(), 'constraint', 'column', 'value');

    // prevent SQL injection
    if (!_.include(allowedColumns, params.column))
      return res.badRequest(format('invalid value "%s" for parameter "column"', params.column));

    if (!params.value)
      return res.badRequest('missing required parameter "value"');

    if (!_.include(allowedConstraints, params.constraint))
      return res.badRequest(format('invalid value "%s" for parameter "constraint"', params.constraint));

    var statement = format('lower(%s) = lower(?)', params.column);
    Community.query().whereRaw(statement, params.value).count()
    .then(function(rows) {
      var data;
      if (params.constraint === 'unique') {
        data = {unique: parseInt(rows[0].count) === 0};
      } else if (params.constraint === 'exists') {
        var exists = parseInt(rows[0].count) >= 1;
        data = {exists: exists};
      }
      res.ok(data);
    })
    .catch(res.serverError.bind(res));
  },

  create: function(req, res) {
    var attrs = _.pick(req.allParams(),
      'name', 'description', 'slug', 'category',
      'beta_access_code', 'banner_url', 'avatar_url');

    var community = new Community(_.merge(attrs, {
      created_at: new Date(),
      created_by_id: req.session.userId
    }));

    if (process.env.NODE_ENV) {
      community.set('leader_id', 21);
      community.set('welcome_message', "Thank you for joining us here at Hylo. " +
        "Through our communities, we can find everything we need. If we share " +
        "with each other the unique gifts and intentions we each have, we can " +
        "create extraordinary things. Let's get started!");
    }

    bookshelf.transaction(function(trx) {
      return community.save(null, {transacting: trx})
      .tap(() => Membership.create(req.session.userId, community.id, {
        role: Membership.MODERATOR_ROLE,
        transacting: trx
      }));
    })
    // The assets were uploaded to /community/new, since we didn't have an id;
    // copy them over to /community/:id now
    .tap(community => Queue.classMethod('Community', 'copyAssets', {communityId: community.id}))
    .tap(community => Queue.classMethod('Community', 'notifyAboutCreate', {communityId: community.id}))
    .tap(() => Tour.skipOnboarding(req.session.userId))
    // FIXME this additional lookup wouldn't be necessary
    // if we had a Membership instance from the previous
    // step. But the absence of an id column on the table
    // doesn't play nice with Bookshelf.
    .then(() => Membership.find(req.session.userId, community.id, {withRelated: ['community']}))
    .then(res.ok)
    .catch(res.serverError);
  },

  findForNetwork: function(req, res) {
    Community.where('network_id', req.param('networkId'))
    .fetchAll({withRelated: ['memberships']})
    .then(communities => communities.map(c =>
      _.extend(c.pick('id', 'name', 'slug', 'avatar_url', 'banner_url'), {
        memberCount: c.relations.memberships.length
      })))
    .then(communities => _.sortBy(communities, c => -c.memberCount))
    .then(res.ok)
    .catch(res.serverError);
  }

};
<|endoftext|>


<commit_before>/**
 * CommunityController
 *
 * @description :: Server-side logic for managing communities
 * @help        :: See http://links.sailsjs.org/docs/controllers
 */

var format = require('util').format,
  validator = require('validator');

var communityAttributes = function(community, membership) {
  return _.extend(community.attributes, {
    canModerate: membership && membership.hasModeratorRole(),
    id: Number(community.id)
  })
}

module.exports = {

  findDefault: function(req, res) {
    User.find(req.session.userId).then(function(user) {
      return user.communities().query(function(qb) { qb.orderBy('id', 'desc') }).fetchOne();
    })
    .then(function(community) {
      if (!community) return res.ok({});

      Membership.find(req.session.userId, community.id).then(function(membership) {
        res.ok(communityAttributes(community, membership));
      })
    })
  },

  findOne: function(req, res) {
    Community.find(req.param('communityId')).then(function(community) {
      Membership.find(req.session.userId, community.id).then(function(membership) {
        res.ok(communityAttributes(community, membership));
      });
    });
  },

  update: function(req, res) {
    var whitelist = ['banner_url', 'avatar_url', 'name', 'description', 'settings'],
      attributes = _.pick(req.allParams(), whitelist),
      community = new Community({id: req.param('communityId')});

    community.save(attributes, {patch: true}).then(function(community) {
      res.ok({});
    }).catch(function(err) {
      res.serverError(err);
    })
  },

  invite: function(req, res) {
    Community.find(req.param('communityId'))
    .then(function(community) {

      var emails = (req.param('emails') || '').split(',').map(function(email) {
        var trimmed = email.trim(),
          matchLongFormat = trimmed.match(/.*<(.*)>/);

        if (matchLongFormat) return matchLongFormat[1];
        return trimmed;
      });

      var marked = require('marked');
      marked.setOptions({
        gfm: true,
        breaks: true
      });

      var message = marked(req.param('message') || '');

      return Promise.map(emails, function(email) {
        if (!validator.isEmail(email)) {
          return {email: email, error: "not a valid email address"};
        }

        return Invitation.createAndSend({
          email:       email,
          userId:      req.session.userId,
          communityId: community.id,
          message:     message,
          moderator:   req.param('moderator'),
          subject:     req.param('subject')
        }).then(function() {
          return {email: email, error: null};
        }).catch(function(err) {
          return {email: email, error: err.message};
        });
      });

    })
    .then(function(results) {
      res.ok({results: results});
    });
  },

  findModerators: function(req, res) {
    Community.find(req.param('communityId')).then(function(community) {
      return community.moderators().fetch();
    }).then(function(moderators) {
      res.ok(moderators.map(function(user) {
        return {
          id: user.id,
          name: user.get('name'),
          avatar_url: user.get('avatar_url')
        };
      }));
    });
  },

  addModerator: function(req, res) {
    Membership.setModeratorRole(req.param('userId'), req.param('communityId')).then(function() {
      res.ok({});
    });
  },

  removeModerator: function(req, res) {
    Membership.removeModeratorRole(req.param('userId'), req.param('communityId')).then(function() {
      res.ok({});
    });
  },

  findMembers: function(req, res) {
    if (TokenAuth.isAuthenticated(res)) {
      if (!RequestValidation.requireTimeRange(req, res)) return;
    }

    var options = _.defaults(
      _.pick(req.allParams(), 'search', 'limit', 'offset', 'start_time', 'end_time'),
      {limit: 1000}
    );

    if (req.param('with')) {
      options.withRelated = _.flatten([req.param('with')]);
    }

    Community.members(req.param('communityId'), options)
    .then(function(users) {

      res.ok(users.map(function(user) {
        var attributes = _.merge(
          _.pick(user.attributes, 'name', 'avatar_url', 'bio', 'facebook_url', 'linkedin_url', 'twitter_name'),
          {
            id: Number(user.id),
            public_email: user.encryptedEmail()
          }
        );

        if (options.withRelated) {
          _.each(options.withRelated, function(relation) {
            var model;
            switch (relation) {
              case 'skills': model = Skill; break;
              case 'organizations': model = Organization;
            }
            attributes[relation] = model.simpleList(user.relations[relation]);
          });
        }

        return attributes;
      }));

    });
  },

  removeMember: function(req, res) {
    res.locals.membership.destroyMe()
    .then(function() {
      res.ok({});
    })
    .catch(res.serverError.bind(res));
  },

  validate: function(req, res) {
    var allowedColumns = ['name', 'slug', 'beta_access_code'],
      params = _.pick(req.allParams(), 'constraint', 'column', 'value');

    if (params.constraint === 'unique') {
      // this whitelist prevents SQL injection
      if (!_.contains(allowedColumns, params.column))
        return res.badRequest(format('invalid value "%s" for parameter "column"', params.column));

      if (!params.value)
        return res.badRequest('missing required parameter "value"');

      var statement = format('lower(%s) = lower(?)', params.column);

      Community.query().whereRaw(statement, params.value).count()
      .then(function(rows) {
        res.ok({unique: parseInt(rows[0].count) == 0});
      })
      .catch(res.serverError.bind(res));

    } else {
      res.badRequest(format('invalid value "%s" for parameter "constraint"', params.constraint));
    }
  },

  create: function(req, res) {
    var attrs = _.pick(req.allParams(),
      'name', 'description', 'slug', 'category',
      'beta_access_code', 'banner_url', 'avatar_url');

    var community = new Community(attrs);

    bookshelf.transaction(function(trx) {
      return community.save(null, {transacting: trx})
      .tap(function() {
        return Membership.create(req.session.userId, community.id, {
          role: Membership.MODERATOR_ROLE,
          transacting: trx
        });
      })
    })
    .then(function() {
      res.ok(communityAttributes(community));
    })
    .catch(res.serverError.bind(res));
  }

};<commit_msg>return new membership after creating community<commit_after>/**
 * CommunityController
 *
 * @description :: Server-side logic for managing communities
 * @help        :: See http://links.sailsjs.org/docs/controllers
 */

var format = require('util').format,
  validator = require('validator');

var communityAttributes = function(community, membership) {
  return _.extend(community.attributes, {
    canModerate: membership && membership.hasModeratorRole(),
    id: Number(community.id)
  })
}

module.exports = {

  findDefault: function(req, res) {
    User.find(req.session.userId).then(function(user) {
      return user.communities().query(function(qb) { qb.orderBy('id', 'desc') }).fetchOne();
    })
    .then(function(community) {
      if (!community) return res.ok({});

      Membership.find(req.session.userId, community.id).then(function(membership) {
        res.ok(communityAttributes(community, membership));
      })
    })
  },

  findOne: function(req, res) {
    Community.find(req.param('communityId')).then(function(community) {
      Membership.find(req.session.userId, community.id).then(function(membership) {
        res.ok(communityAttributes(community, membership));
      });
    });
  },

  update: function(req, res) {
    var whitelist = ['banner_url', 'avatar_url', 'name', 'description', 'settings'],
      attributes = _.pick(req.allParams(), whitelist),
      community = new Community({id: req.param('communityId')});

    community.save(attributes, {patch: true}).then(function(community) {
      res.ok({});
    }).catch(function(err) {
      res.serverError(err);
    })
  },

  invite: function(req, res) {
    Community.find(req.param('communityId'))
    .then(function(community) {

      var emails = (req.param('emails') || '').split(',').map(function(email) {
        var trimmed = email.trim(),
          matchLongFormat = trimmed.match(/.*<(.*)>/);

        if (matchLongFormat) return matchLongFormat[1];
        return trimmed;
      });

      var marked = require('marked');
      marked.setOptions({
        gfm: true,
        breaks: true
      });

      var message = marked(req.param('message') || '');

      return Promise.map(emails, function(email) {
        if (!validator.isEmail(email)) {
          return {email: email, error: "not a valid email address"};
        }

        return Invitation.createAndSend({
          email:       email,
          userId:      req.session.userId,
          communityId: community.id,
          message:     message,
          moderator:   req.param('moderator'),
          subject:     req.param('subject')
        }).then(function() {
          return {email: email, error: null};
        }).catch(function(err) {
          return {email: email, error: err.message};
        });
      });

    })
    .then(function(results) {
      res.ok({results: results});
    });
  },

  findModerators: function(req, res) {
    Community.find(req.param('communityId')).then(function(community) {
      return community.moderators().fetch();
    }).then(function(moderators) {
      res.ok(moderators.map(function(user) {
        return {
          id: user.id,
          name: user.get('name'),
          avatar_url: user.get('avatar_url')
        };
      }));
    });
  },

  addModerator: function(req, res) {
    Membership.setModeratorRole(req.param('userId'), req.param('communityId')).then(function() {
      res.ok({});
    });
  },

  removeModerator: function(req, res) {
    Membership.removeModeratorRole(req.param('userId'), req.param('communityId')).then(function() {
      res.ok({});
    });
  },

  findMembers: function(req, res) {
    if (TokenAuth.isAuthenticated(res)) {
      if (!RequestValidation.requireTimeRange(req, res)) return;
    }

    var options = _.defaults(
      _.pick(req.allParams(), 'search', 'limit', 'offset', 'start_time', 'end_time'),
      {limit: 1000}
    );

    if (req.param('with')) {
      options.withRelated = _.flatten([req.param('with')]);
    }

    Community.members(req.param('communityId'), options)
    .then(function(users) {

      res.ok(users.map(function(user) {
        var attributes = _.merge(
          _.pick(user.attributes, 'name', 'avatar_url', 'bio', 'facebook_url', 'linkedin_url', 'twitter_name'),
          {
            id: Number(user.id),
            public_email: user.encryptedEmail()
          }
        );

        if (options.withRelated) {
          _.each(options.withRelated, function(relation) {
            var model;
            switch (relation) {
              case 'skills': model = Skill; break;
              case 'organizations': model = Organization;
            }
            attributes[relation] = model.simpleList(user.relations[relation]);
          });
        }

        return attributes;
      }));

    });
  },

  removeMember: function(req, res) {
    res.locals.membership.destroyMe()
    .then(function() {
      res.ok({});
    })
    .catch(res.serverError.bind(res));
  },

  validate: function(req, res) {
    var allowedColumns = ['name', 'slug', 'beta_access_code'],
      params = _.pick(req.allParams(), 'constraint', 'column', 'value');

    if (params.constraint === 'unique') {
      // this whitelist prevents SQL injection
      if (!_.contains(allowedColumns, params.column))
        return res.badRequest(format('invalid value "%s" for parameter "column"', params.column));

      if (!params.value)
        return res.badRequest('missing required parameter "value"');

      var statement = format('lower(%s) = lower(?)', params.column);

      Community.query().whereRaw(statement, params.value).count()
      .then(function(rows) {
        res.ok({unique: parseInt(rows[0].count) == 0});
      })
      .catch(res.serverError.bind(res));

    } else {
      res.badRequest(format('invalid value "%s" for parameter "constraint"', params.constraint));
    }
  },

  create: function(req, res) {
    var attrs = _.pick(req.allParams(),
      'name', 'description', 'slug', 'category',
      'beta_access_code', 'banner_url', 'avatar_url');

    var community = new Community(attrs);

    bookshelf.transaction(function(trx) {
      return community.save(null, {transacting: trx})
      .tap(function() {
        return Membership.create(req.session.userId, community.id, {
          role: Membership.MODERATOR_ROLE,
          transacting: trx
        });
      });
    })
    .then(function() {
      return Membership.where({
        users_id: req.session.userId,
        community_id: community.id
      }).fetch({withRelated: ['community']});
    })
    .then(function(membership) {
      res.ok(membership);
    })
    .catch(res.serverError.bind(res));
  }

};<|endoftext|>


<commit_before>var mongoose = require('mongoose');
var Hotel = mongoose.model('Hotel');
// may need to review error handling

// get all reviews for one hotel
module.exports.reviewsGetAll = function(req, res){
  var hotelId = req.params.hotelId; // I named this route in index.js
  console.log("getting one hotel with ID of ", hotelId );

  Hotel
    .findById(hotelId)
    .select('reviews')
    .exec(function(err, doc){
      if(err || !doc){
        console.log("Error finding reviews, reviews controller: ");
        res
          .status(500)
          .json({"message": "there was an error finding reviews"});
      }else{
        console.log("returned doc: ", doc);
        res
          .status(200)
          .json(doc.reviews);
      }//else
    });//exec
};//reviewsGetAll

// GET a single review for a particular hotel
module.exports.reviewsGetOne = function(req, res){
  var hotelId = req.params.hotelId;
  var reviewId = req.params.reviewId;
  console.log("GET reviewId " + reviewId + " for hotelId " + hotelId);

  Hotel
    .findById(hotelId)
    .select('reviews')
    .exec(function(err, hotel){
      if(err || !hotel){
        console.log("Error finding review, reviews controller: ");
        res
          .status(500)
          .json({"message": "there was an error finding this review"});
      }
      else{
        console.log("returned hotel: ", hotel);
        var review = hotel.reviews.id(reviewId);
        res
          .status(200)
          .json(review);
      }

    });
};

//helper function
var _addReview = function(req, res, hotel){

  hotel.reviews.push({
    name: req.body.name,
    rating: parseInt(req.body.rating, 10),
    review: req.body.review
  });

  hotel.save(function(err, hotelUpdated){
    if(err){
      res.status(500).json(err);
    }else{
      console.log("line 68");
      res.status(201).json(hotelUpdated.reviews[hotelUpdated.reviews.length - 1]);
    }
  });
};

module.exports.reviewsAddOne = function(req, res){
  var hotelId = req.params.hotelId; // I named this route in index.js
  console.log(" ", hotelId );

  Hotel
    .findById(hotelId)
    .select('reviews')
    .exec(function(err, doc){
      var response = {
        status: 200,
        message: []
      }

      if(err){
        console.log("Error adding review");
        response.status = 500;
        response.message = err;
      }else if(!doc){
        console.log("returned doc: ", doc);
        response.status = 404;
        response.message = "not found"
      }

      if(doc){
        _addReview(req, res, doc);
      }else {
        res.status(response.status).json(response.message);
      }//else
    });//exec
};

// update one review
module.exports.reviewsUpdateOne = function(req, res){
  var hotelId = req.params.hotelId;
  var reviewId = req.params.reviewId; // PUT route in index.js
  console.log("PUT reviewId " + reviewId + " for hotelId " + hotelId);

  Hotel
    .findById(hotelId)
    .select("reviews")
    .exec(function(err, hotel){
      var thisReview;
      var response = {status: 200, message: {} };

      // changing response if something isn't right
      if(err){
        console.log("Error finding hotel");
        response.status = 500;
        response.message = err;
      }
      else if(!hotel){
        console.log('hotelId not found in hotelData', id);
        response.status = 404;
        response.messaage = {"message": "hotel id not found " + id};
      }
      else{
        thisReview = hotel.reviews.id(reviewId);
        if(!thisReview){
          response.status = 404;
          response.message = {"message": "reviewId not found ", reviewId};
        }
      }//else

      if(response.status !== 200){ // if something wasn't perfect
        res
          .status(response.status)
          .json(response.message);
      }
      else{
        thisReview.name = req.body.name;
        thisReview.rating = req.body.rating;
        thisReview.review = req.body.review;

        hotel.save(function(err, hotelUpdated){
          if(err){
            res.status(500).json(err);
          }
          else{
            res.status(204).json();
          }
        });//save
      }//else

    });//exec
};//reviewsUpdateOne

module.exports.reviewsDeleteOne = function(req, res){

};//reviewsDeleteOne
<commit_msg>need to test updateReview and deleteHotel functions<commit_after>var mongoose = require('mongoose');
var Hotel = mongoose.model('Hotel');
// may need to review error handling

// get all reviews for one hotel
module.exports.reviewsGetAll = function(req, res){
  var hotelId = req.params.hotelId; // I named this route in index.js
  console.log("getting one hotel with ID of ", hotelId );

  Hotel
    .findById(hotelId)
    .select('reviews')
    .exec(function(err, doc){
      if(err || !doc){
        console.log("Error finding reviews, reviews controller: ");
        res
          .status(500)
          .json({"message": "there was an error finding reviews"});
      }else{
        console.log("returned doc: ", doc);
        res
          .status(200)
          .json(doc.reviews);
      }//else
    });//exec
};//reviewsGetAll

// GET a single review for a particular hotel
module.exports.reviewsGetOne = function(req, res){
  var hotelId = req.params.hotelId;
  var reviewId = req.params.reviewId;
  console.log("GET reviewId " + reviewId + " for hotelId " + hotelId);

  Hotel
    .findById(hotelId)
    .select('reviews')
    .exec(function(err, hotel){
      if(err || !hotel){
        console.log("Error finding review, reviews controller: ");
        res
          .status(500)
          .json({"message": "there was an error finding this review"});
      }
      else{
        console.log("returned hotel: ", hotel);
        var review = hotel.reviews.id(reviewId);
        res
          .status(200)
          .json(review);
      }

    });
};

//helper function
var _addReview = function(req, res, hotel){

  hotel.reviews.push({
    name: req.body.name,
    rating: parseInt(req.body.rating, 10),
    review: req.body.review
  });

  hotel.save(function(err, hotelUpdated){
    if(err){
      res.status(500).json(err);
    }else{
      console.log("line 68");
      res.status(201).json(hotelUpdated.reviews[hotelUpdated.reviews.length - 1]);
    }
  });
};

module.exports.reviewsAddOne = function(req, res){
  var hotelId = req.params.hotelId; // I named this route in index.js
  console.log(" ", hotelId );

  Hotel
    .findById(hotelId)
    .select('reviews')
    .exec(function(err, doc){
      var response = {
        status: 200,
        message: []
      }

      if(err){
        console.log("Error adding review");
        response.status = 500;
        response.message = err;
      }else if(!doc){
        console.log("returned doc: ", doc);
        response.status = 404;
        response.message = "not found"
      }

      if(doc){
        _addReview(req, res, doc);
      }else {
        res.status(response.status).json(response.message);
      }//else
    });//exec
};

// update one review
module.exports.reviewsUpdateOne = function(req, res){
  var hotelId = req.params.hotelId;
  var reviewId = req.params.reviewId; // PUT route in index.js
  console.log("PUT reviewId " + reviewId + " for hotelId " + hotelId);

  Hotel
    .findById(hotelId)
    .select("reviews")
    .exec(function(err, hotel){
      var thisReview;
      var response = {status: 200, message: {} };

      // changing response if something isn't right
      if(err){
        console.log("Error finding hotel");
        response.status = 500;
        response.message = err;
      }
      else if(!hotel){
        console.log('hotelId not found in hotelData', id);
        response.status = 404;
        response.messaage = {"message": "hotel id not found " + id};
      }
      else{
        thisReview = hotel.reviews.id(reviewId);
        if(!thisReview){
          response.status = 404;
          response.message = {"message": "reviewId not found ", reviewId};
        }
      }//else

      if(response.status !== 200){ // if something wasn't perfect
        res
          .status(response.status)
          .json(response.message);
      }
      else{
        thisReview.name = req.body.name;
        thisReview.rating = req.body.rating;
        thisReview.review = req.body.review;

        hotel.save(function(err, hotelUpdated){
          if(err){
            res.status(500).json(err);
          }
          else{
            res.status(204).json();
          }
        });//save
      }//else

    });//exec
};//reviewsUpdateOne

module.exports.reviewsDeleteOne = function(req, res){
  var hotelId = req.params.hotelId;
  var reviewId = req.params.reviewId; // PUT route in index.js
  console.log("PUT reviewId " + reviewId + " for hotelId " + hotelId);

  Hotel
    .findById(hotelId)
    .select("reviews")
    .exec(function(err, hotel){
      var thisReview;
      var response = {status: 200, message: {} };

      // changing response if something isn't right
      if(err){
        console.log("Error finding hotel");
        response.status = 500;
        response.message = err;
      }
      else if(!hotel){
        console.log('hotelId not found in hotelData', id);
        response.status = 404;
        response.messaage = {"message": "hotel id not found " + id};
      }
      else{
        thisReview = hotel.reviews.id(reviewId);
        if(!thisReview){
          response.status = 404;
          response.message = {"message": "reviewId not found ", reviewId};
        }
      }//else

      if(response.status !== 200){ // if something wasn't perfect
        res
          .status(response.status)
          .json(response.message);
      }
      else{
        thisReview.name = req.body.name;
        thisReview.rating = req.body.rating;
        thisReview.review = req.body.review;

        hotel.save(function(err, hotelUpdated){
          if(err){
            res.status(500).json(err);
          }
          else{
            res.status(204).json();
          }
        });//save
      }//else
    });//exec

};//reviewsDeleteOne
<|endoftext|>


<commit_before>require('6to5/polyfill')

var Github = require('github')
  , co = require('co')
  , fs = require('mz/fs')
  , render = require('mustache').render
  , moment = require('moment')
  , thenifyAll = require('thenify-all')
  , parseLinkHeader = require('parse-link-header')

var github = new Github({
  version: '3.0.0'
})
var pullRequests = thenifyAll(github.pullRequests)

const defaultConfig = {
  branch: {
    production: 'master',
    staging: 'staging'
  }
}

var config = null

function getRepo() {
  return {
    user: config.repo.split('/')[0],
    repo: config.repo.split('/')[1]
  }
}

function readConfigFile() {
  return fs.readFile('.github-pr-release.json', 'utf8')
           .then(JSON.parse)
           .catch(function () { return {} })
}

var readConfig = co.wrap(function* (runtimeConfig = {}) {
  var fileConfig = yield readConfigFile()

  return Object.assign({}, defaultConfig, fileConfig, runtimeConfig)
})

var createReleaseMessage = co.wrap(function* (prs) {
  var template = yield fs.readFile(__dirname + '/release.mustache', 'utf8')

  var text = render(template, { now: moment().format('YYYY-MM-DD HH:mm:ss'), prs: prs })
  var [title, ...body] = text.split('\n')

  return {
    title: title,
    body: body.join('\n')
  }
})

function getPRCommits(repo, targetPR) {
  var result = []

  function getCommits(page = 1) {
    return pullRequests.getCommits(Object.assign({}, repo, {
      number: targetPR.number,
      per_page: 100,
      page: page
    })).then(function(commits) {
      var hasNext = !!parseLinkHeader(commits.meta.link).next

      result = result.concat(commits)

      if (hasNext) {
        return getCommits(page + 1)
      } else {
        return result
      }
    })
  }

  return getCommits()
}

var getReleasePRs = co.wrap(function* (targetPR) {
  var repo = getRepo()

  var commits = yield getPRCommits(repo, targetPR)

  var shas = commits.map(commit => commit.sha)

  var prs = yield pullRequests.getAll(Object.assign({}, repo, {
    state: 'closed',
    per_page: 100
  }))

  var mergedPRs = prs.filter(pr => pr.merged_at !== null)

  var releasePRs = mergedPRs.reduce((ret, pr) => {
    var matched =  pr.number !== targetPR.number && pr.base.ref === targetPR.head.ref

    if (shas.indexOf(pr.head.sha) !== -1 && matched) {
      ret.push(pr)
    }
    return ret
  }, [])

  return releasePRs
})

module.exports = co.wrap(function* (runtimeConfig = {}) {
  config = yield readConfig(runtimeConfig)

  var repo = getRepo()

  github.authenticate({
    type: 'oauth',
    token: config.token
  })

  var targetPR = yield pullRequests.create(Object.assign({}, repo, {
    title: 'Preparing release pull request...',
    base: config.branch.production,
    head: config.branch.staging
  }))

  var releasePRs = yield getReleasePRs(targetPR)

  var release = yield createReleaseMessage(releasePRs)

  yield pullRequests.update(Object.assign({}, repo, {
    number: targetPR.number,
    title: release.title,
    body: release.body
  }))
})
<commit_msg>6to5/polyfill -> babel/polyfill<commit_after>require('babel/polyfill')

var Github = require('github')
  , co = require('co')
  , fs = require('mz/fs')
  , render = require('mustache').render
  , moment = require('moment')
  , thenifyAll = require('thenify-all')
  , parseLinkHeader = require('parse-link-header')

var github = new Github({
  version: '3.0.0'
})
var pullRequests = thenifyAll(github.pullRequests)

const defaultConfig = {
  branch: {
    production: 'master',
    staging: 'staging'
  }
}

var config = null

function getRepo() {
  return {
    user: config.repo.split('/')[0],
    repo: config.repo.split('/')[1]
  }
}

function readConfigFile() {
  return fs.readFile('.github-pr-release.json', 'utf8')
           .then(JSON.parse)
           .catch(function () { return {} })
}

var readConfig = co.wrap(function* (runtimeConfig = {}) {
  var fileConfig = yield readConfigFile()

  return Object.assign({}, defaultConfig, fileConfig, runtimeConfig)
})

var createReleaseMessage = co.wrap(function* (prs) {
  var template = yield fs.readFile(__dirname + '/release.mustache', 'utf8')

  var text = render(template, { now: moment().format('YYYY-MM-DD HH:mm:ss'), prs: prs })
  var [title, ...body] = text.split('\n')

  return {
    title: title,
    body: body.join('\n')
  }
})

function getPRCommits(repo, targetPR) {
  var result = []

  function getCommits(page = 1) {
    return pullRequests.getCommits(Object.assign({}, repo, {
      number: targetPR.number,
      per_page: 100,
      page: page
    })).then(function(commits) {
      var hasNext = !!parseLinkHeader(commits.meta.link).next

      result = result.concat(commits)

      if (hasNext) {
        return getCommits(page + 1)
      } else {
        return result
      }
    })
  }

  return getCommits()
}

var getReleasePRs = co.wrap(function* (targetPR) {
  var repo = getRepo()

  var commits = yield getPRCommits(repo, targetPR)

  var shas = commits.map(commit => commit.sha)

  var prs = yield pullRequests.getAll(Object.assign({}, repo, {
    state: 'closed',
    per_page: 100
  }))

  var mergedPRs = prs.filter(pr => pr.merged_at !== null)

  var releasePRs = mergedPRs.reduce((ret, pr) => {
    var matched =  pr.number !== targetPR.number && pr.base.ref === targetPR.head.ref

    if (shas.indexOf(pr.head.sha) !== -1 && matched) {
      ret.push(pr)
    }
    return ret
  }, [])

  return releasePRs
})

module.exports = co.wrap(function* (runtimeConfig = {}) {
  config = yield readConfig(runtimeConfig)

  var repo = getRepo()

  github.authenticate({
    type: 'oauth',
    token: config.token
  })

  var targetPR = yield pullRequests.create(Object.assign({}, repo, {
    title: 'Preparing release pull request...',
    base: config.branch.production,
    head: config.branch.staging
  }))

  var releasePRs = yield getReleasePRs(targetPR)

  var release = yield createReleaseMessage(releasePRs)

  yield pullRequests.update(Object.assign({}, repo, {
    number: targetPR.number,
    title: release.title,
    body: release.body
  }))
})
<|endoftext|>