<commit_before>class Vector {
    /**
     * @class Vector
     *
     * This is a basic vector class that is used for geometry, position inforamtion,
     * movement infomation, and more complex structures.
     * The vector class follows a immutable paradigm where changes are not made to the
     * vectors themselves. Any change to a vector is returned as a new vector that
     * must be captured.
     *
     * @description This vector class was constructed so that it can mirror two types of common
     * point/vector type objects. This is having object properties stored as object
     * properties (eg. vector.x, vector.y) or as list properties, [x, y] which can
     * be accessed by vector[0], or vector[1].
     *
     * @summary Create a 2D Vector object
     *
     * @property {number} x The x vector component
     * @property {number} y The y vector component
     * @property {number} 0 The x vector component
     * @property {number} 1 The y vector component
     *
     * @param {number|Vector} x The x component or another vector
     * @param {number} [y] The y component
     */
    constructor(x, y) {
        if (x instanceof Vector && !y) {
            this._set(x.x, x.y);
        } else {
            this._set(x, y);
        }
    }

    //---- Helper Functions ----

    /**
     * Internal Helper Function for setting variable properties
     *
     * @private
     * @param {number} x The x component
     * @param {number} y The y component
     * @memberof Vector
     */
    _set(x, y) {
        this.__proto__[0] = x;
        this.__proto__[1] = y;
        this.x = x;
        this.y = y;
    }

    /**
     * Get the vector key:Symbol representation
     *
     * @returns {Symbol} The vector key element
     * @memberof Vector
     */
    key() {
        return Symbol(this.list());
    }

    /**
     * Get the vector in list form
     *
     * @returns {number[]} List representation of the vector of length 2
     * @memberof Vector
     */
    list() {
        return [this.x, this.y];
    }

    /**
     * Returns the vector as a string of (x, y)
     *
     * @returns {string} The string representation of a vector in (x, y) form
     * @memberof Vector
     */
    toString() {
        return `(${this.x}, ${this.y})`;
    }

    /**
     * Get a copy of the input vector
     *
     * @param {Vector} v the vector to be coppied
     * @returns {Vector} The vector copy
     * @memberof Vector
     */
    static copy(v) {
        return new Vector(v.x, v.y);
    }

    //---- Basic Math Functions ----

    /**
     * Add two vectors element wise
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns {Vector} The vector result of adding the two vectors
     * @memberof Vector
     */
    static add(a, b) {
        return new Vector(a.x + b.x, a.y + b.y);
    }

    /**
     * Add this vector with another vector element wise
     *
     * @param {Vector} other The other vector
     * @returns {Vector} The vector result of adding the two vectors
     * @memberof Vector
     */
    add(other) {
        return Vector.add(this, other);
    }

    /**
     * Subtract two vectors element wise
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second Vector
     * @returns {Vector} The vector result of subtracting the two vectors
     * @memberof Vector
     */
    static subtract(a, b) {
        return new Vector(a.x - b.x, a.y - b.y);
    }

    /**
     * Subtract this vector with another vector element wise
     *
     * @param {Vector} other The other vector
     * @returns {Vector} The vector result of subtracting the two vectors
     * @memberof Vector
     */
    subtract(other) {
        return Vector.subtract(this, other);
    }

    /**
     * Multiply the vector by a scalar value
     *
     * @param {number} scalar The number to multiply the vector by
     * @returns {Vector} The result of multiplying the vector by a scalar
     *  element wise
     * @memberof Vector
     */
    multiply(scalar) {
        return new Vector(this.x * scalar, this.y * scalar);
    }

    /**
     * Divide the vector by a scalar value
     *
     * @param {number} scalar
     * @returns {Vector} The result of multiplying the vector by a scalar
     * @memberof Vector
     */
    divide(scalar) {
        return new Vector(this.x / scalar, this.y / scalar);
    }

    //---- Advanced Vector Functions ----

    /**
     * Get the magnitude of the vector
     *
     * @returns {number} The magniture of the vector
     * @memberof Vector
     */
    magnitude() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }

    // Get the unit vector
    /**
     * Get the normal vector of the current vector.
     *
     * @returns {Vector} A vector that is the normal compenent of the vector
     * @memberof Vector
     */
    normalize() {
        return this.divide(this.magnitude());
    }

    /**
     * Get the get the current vector rotated by a certain ammount
     *
     * @param {number} radians
     * @returns {Vector} The vector that results from rotating the current
     *  vector by a particular ammount
     * @memberof Vector
     */
    rotate(radians) {
        const c = Math.cos(radians);
        const s = Math.cos(radians);
        return new Vector(c * this.x - s * this.y, s * this.x + c * this.y);
    }

    /**
     * Get the dot product of two vectors
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns {number} The dot product of the two vectors
     * @memberof Vector
     */
    static dot(a, b) {
        return a.x * b.x + a.y * b.y;
    }

    /**
     * Get the average location between several vectors
     *
     * @param {Vector[]} vectors The list of vectors to average
     * @memberof Vector
     */
    avg(vectors) {
        let average = Vector.zero();

        for (const vector of vectors) {
            average = Vector.add(average, vector);
        }
        return average.divide(vectors.length);
    }

    /**
     * Get the dot product of this vector and another vector
     *
     * @param {Vector} other The other vector
     * @returns {number} The dot product of this and the other vector
     * @memberof Vector
     */
    dot(other) {
        return this.dot(this, other);
    }

    /**
     * Get the cross product of two vectors
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns {number} The cross product of the two vectors
     * @memberof Vector
     */
    static cross(a, b) {
        return a.x * b.y - a.y * b.x;
    }

    /**
     * Get the cross product of this and the other vector
     *
     * @param {Vector} other The other vector
     * @returns {number} The cross product of this and the other vector
     * @memberof Vector
     */
    cross(other) {
        return this.cross(this, other);
    }

    //---- Purely Static Vector Functions ----

    /**
     * Get the midpoint between two vectors
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns The midpoint of two vectors
     * @memberof Vector
     */
    static midpoint(a, b) {
        return new Vector((a.x + b.x) / 2, (a.y + b.y) / 2);
    }

    /**
     * Get the projection of vector a onto vector b
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns The projection vector of a onto b
     * @memberof Vector
     *
     * @todo Add assertion for non-zero length b vector
     */
    static proj(a, b) {

        return b.multiply(Vector.dot(a, b) / Math.pow(b.magnitude(), 2));
    }

    /**
     * Get the angle between two vectors
     *
     * @static
     * @param {Vector} a The frist vector
     * @param {Vector} b The second vector
     * @returns The angle between vector a and vector b
     * @memberof Vector
     */
    static angle(a, b) {
        return Math.acos(Vector.dot(a, b) / (a.magnitude() * b.magnitude()));
    }

    /**
     * Get the euclidean distance between two vectors
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns The euclidean distance between a and b
     * @see {@link dist2}
     * @memberof Vector
     */
    static distance(a, b) {
        return Math.sqrt(Vector.dist2(a, b));
    }

    /**
     * Get the euclidean distnace squared between two vectors.
     * This is used as a helper for the distnace function but can be used
     * to save on speed by not doing the square root operation.
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns The euclidean distance squared between vector a and vector b
     * @see {@link distnace}
     * @memberof Vector
     */
    static dist2(a, b) {
        const dx = a.x - b.x;
        const dy = a.y - b.y;
        return dx * dx + dy * dy;
    }

    /**
     * Get the shortest distance between the point p and the line
     * segment v to w.
     *
     * @static
     * @param {Vector} p The vector point
     * @param {Vector} v The first line segment endpoint
     * @param {Vector} w The second line segment endpoint
     * @returns The shortest euclidean distance between point
     * @see {@link distToSeg2}
     * @see {@link http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment}
     * @memberof Vector
     */
    static distToSeg(p, v, w) {
        return Math.sqrt(Vector.distToSeg2(p, v, w));
    }

    /**
     * Get the shortest distance squared between the point p and the line
     * segment v to w.
     *
     * @static
     * @param {Vector} p The vector point
     * @param {Vector} v The first line segment endpoint
     * @param {Vector} w The second line segment endpoint
     * @returns The shortest euclidean distance squared between point
     * @see {@link distToSeg}
     * @see {@link http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment}
     * @memberof Vector
     */
    static distToSegSquared(p, v, w) {
        const l = Vector.dist2(v, w);
        if (l === 0) { return Vector.dist2(p, v); }
        let t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l;
        t = Math.max(0, Math.min(1, t));
        return Vector.dist2(p, new Vector(v.x + t * (w.x - v.x),
            v.y + t * (w.y - v.y)));
    }

    /**
     * Get the two normal vectors that are perpendicular to the current vector
     *
     * @returns {Vector[]} The two normal vectors that are perpendicular
     *  to the vector. The first vector is the normal vector that is +90 deg or
     *  +PI/2 rad. The second vector is the noraml vector that is -90 deg or
     *  -PI/2 rad.
     * @memberof Vector
     */
    perpendiculars() {
        const plus90 = new Vector(-this.y, this.x).normalize();
        const minus90 = new Vector(this.y, -this.x).normalize();
        return [plus90, minus90];
    }

    //---- Standard Static Vector Objects ----

    /**
     * Get a vector of no magnitude and no direction
     *
     * @static
     * @function
     * @returns {Vector} Vector of magnitude zero
     * @memberof Vector
     */
    static zero() {
        "use strict";
        return new Vector(0, 0);
    }

    /**
     * Get the unit vector pointing in the positive y direction
     *
     * @static
     * @function
     * @returns {Vector} Unit vector pointing up
     * @memberof Vector
     */
    static up() {
        "use strict";
        return new Vector(0, 1);
    }

    /**
     * Get the unit vector pointing in the negative y direction
     *
     * @static
     * @function
     * @returns {Vector} Unit vector pointing down
     * @memberof Vector
     */
    static down() {
        "use strict";
        return new Vector(0, -1);
    }

    /**
     * Get the unit vector pointing in the negative x direction
     *
     * @static
     * @function
     * @returns {Vector} Unit vector pointing right
     * @memberof Vector
     */
    static left() {
        "use strict";
        return new Vector(-1, 0);
    }

    /**
     * Get the unit vector pointing in the positive x direction
     *
     * @static
     * @function
     * @returns {Vector} Unit vector pointing right
     * @memberof Vector
     */
    static right() {
        "use strict";
        return new Vector(1, 0);
    }
}

export default Vector;<commit_msg>Small Branch Cleanup<commit_after>class Vector {
    /**
     * @class Vector
     *
     * This is a basic vector class that is used for geometry, position inforamtion,
     * movement infomation, and more complex structures.
     * The vector class follows a immutable paradigm where changes are not made to the
     * vectors themselves. Any change to a vector is returned as a new vector that
     * must be captured.
     *
     * @description This vector class was constructed so that it can mirror two types of common
     * point/vector type objects. This is having object properties stored as object
     * properties (eg. vector.x, vector.y) or as list properties, [x, y] which can
     * be accessed by vector[0], or vector[1].
     *
     * @summary Create a 2D Vector object
     *
     * @property {number} x The x vector component
     * @property {number} y The y vector component
     * @property {number} 0 The x vector component
     * @property {number} 1 The y vector component
     *
     * @param {number|Vector} x The x component or another vector
     * @param {number} [y] The y component
     */
    constructor(x, y) {
        if (x instanceof Vector && !y) {
            this._set(x.x, x.y);
        } else {
            this._set(x, y);
        }
    }

    //---- Helper Functions ----

    /**
     * Internal Helper Function for setting variable properties
     *
     * @private
     * @param {number} x The x component
     * @param {number} y The y component
     * @memberof Vector
     */
    _set(x, y) {
        this.__proto__[0] = x;
        this.__proto__[1] = y;
        this.x = x;
        this.y = y;
    }

    /**
     * Get the vector key:Symbol representation
     *
     * @returns {Symbol} The vector key element
     * @memberof Vector
     */
    key() {
        return Symbol(this.list());
    }

    /**
     * Get the vector in list form
     *
     * @returns {number[]} List representation of the vector of length 2
     * @memberof Vector
     */
    list() {
        return [this.x, this.y];
    }

    /**
     * Returns the vector as a string of (x, y)
     *
     * @returns {string} The string representation of a vector in (x, y) form
     * @memberof Vector
     */
    toString() {
        return `(${this.x}, ${this.y})`;
    }

    /**
     * Get a copy of the input vector
     *
     * @param {Vector} v the vector to be coppied
     * @returns {Vector} The vector copy
     * @memberof Vector
     */
    static copy(v) {
        return new Vector(v.x, v.y);
    }

    /**
     * Returns the vector as a string of (x, y)
     *
     * @returns {string} The string representation of a vector in (x, y) form
     * @memberof Vector
     */
    toString() {
        return `(${this.x}, ${this.y})`;
    }

    //---- Basic Math Functions ----

    /**
     * Add two vectors element wise
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns {Vector} The vector result of adding the two vectors
     * @memberof Vector
     */
    static add(a, b) {
        return new Vector(a.x + b.x, a.y + b.y);
    }

    /**
     * Add this vector with another vector element wise
     *
     * @param {Vector} other The other vector
     * @returns {Vector} The vector result of adding the two vectors
     * @memberof Vector
     */
    add(other) {
        return Vector.add(this, other);
    }

    /**
     * Subtract two vectors element wise
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second Vector
     * @returns {Vector} The vector result of subtracting the two vectors
     * @memberof Vector
     */
    static subtract(a, b) {
        return new Vector(a.x - b.x, a.y - b.y);
    }

    /**
     * Subtract this vector with another vector element wise
     *
     * @param {Vector} other The other vector
     * @returns {Vector} The vector result of subtracting the two vectors
     * @memberof Vector
     */
    subtract(other) {
        return Vector.subtract(this, other);
    }

    /**
     * Multiply the vector by a scalar value
     *
     * @param {number} scalar The number to multiply the vector by
     * @returns {Vector} The result of multiplying the vector by a scalar
     *  element wise
     * @memberof Vector
     */
    multiply(scalar) {
        return new Vector(this.x * scalar, this.y * scalar);
    }

    /**
     * Divide the vector by a scalar value
     *
     * @param {number} scalar
     * @returns {Vector} The result of multiplying the vector by a scalar
     * @memberof Vector
     */
    divide(scalar) {
        return new Vector(this.x / scalar, this.y / scalar);
    }

    //---- Advanced Vector Functions ----

    /**
     * Get the magnitude of the vector
     *
     * @returns {number} The magniture of the vector
     * @memberof Vector
     */
    magnitude() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }

    // Get the unit vector
    /**
     * Get the normal vector of the current vector.
     *
     * @returns {Vector} A vector that is the normal compenent of the vector
     * @memberof Vector
     */
    normalize() {
        return this.divide(this.magnitude());
    }

    /**
     * Get the get the current vector rotated by a certain ammount
     *
     * @param {number} radians
     * @returns {Vector} The vector that results from rotating the current
     *  vector by a particular ammount
     * @memberof Vector
     */
    rotate(radians) {
        const c = Math.cos(radians);
        const s = Math.cos(radians);
        return new Vector(c * this.x - s * this.y, s * this.x + c * this.y);
    }

    /**
     * Get the dot product of two vectors
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns {number} The dot product of the two vectors
     * @memberof Vector
     */
    static dot(a, b) {
        return a.x * b.x + a.y * b.y;
    }

    /**
     * Get the average location between several vectors
     *
     * @param {Vector[]} vectors The list of vectors to average
     * @memberof Vector
     */
    avg(vectors) {
        let average = Vector.zero();

        for (const vector of vectors) {
            average = Vector.add(average, vector);
        }
        return average.divide(vectors.length);
    }

    /**
     * Get the dot product of this vector and another vector
     *
     * @param {Vector} other The other vector
     * @returns {number} The dot product of this and the other vector
     * @memberof Vector
     */
    dot(other) {
        return this.dot(this, other);
    }

    /**
     * Get the cross product of two vectors
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns {number} The cross product of the two vectors
     * @memberof Vector
     */
    static cross(a, b) {
        return a.x * b.y - a.y * b.x;
    }

    /**
     * Get the cross product of this and the other vector
     *
     * @param {Vector} other The other vector
     * @returns {number} The cross product of this and the other vector
     * @memberof Vector
     */
    cross(other) {
        return this.cross(this, other);
    }

    //---- Purely Static Vector Functions ----

    /**
     * Get the midpoint between two vectors
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns The midpoint of two vectors
     * @memberof Vector
     */
    static midpoint(a, b) {
        return new Vector((a.x + b.x) / 2, (a.y + b.y) / 2);
    }

    /**
     * Get the projection of vector a onto vector b
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns The projection vector of a onto b
     * @memberof Vector
     *
     * @todo Add assertion for non-zero length b vector
     */
    static proj(a, b) {

        return b.multiply(Vector.dot(a, b) / Math.pow(b.magnitude(), 2));
    }

    /**
     * Get the angle between two vectors
     *
     * @static
     * @param {Vector} a The frist vector
     * @param {Vector} b The second vector
     * @returns The angle between vector a and vector b
     * @memberof Vector
     */
    static angle(a, b) {
        return Math.acos(Vector.dot(a, b) / (a.magnitude() * b.magnitude()));
    }

    /**
     * Get the euclidean distance between two vectors
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns The euclidean distance between a and b
     * @see {@link dist2}
     * @memberof Vector
     */
    static distance(a, b) {
        return Math.sqrt(Vector.dist2(a, b));
    }

    /**
     * Get the euclidean distnace squared between two vectors.
     * This is used as a helper for the distnace function but can be used
     * to save on speed by not doing the square root operation.
     *
     * @static
     * @param {Vector} a The first vector
     * @param {Vector} b The second vector
     * @returns The euclidean distance squared between vector a and vector b
     * @see {@link distnace}
     * @memberof Vector
     */
    static dist2(a, b) {
        const dx = a.x - b.x;
        const dy = a.y - b.y;
        return dx * dx + dy * dy;
    }

    /**
     * Get the shortest distance between the point p and the line
     * segment v to w.
     *
     * @static
     * @param {Vector} p The vector point
     * @param {Vector} v The first line segment endpoint
     * @param {Vector} w The second line segment endpoint
     * @returns The shortest euclidean distance between point
     * @see {@link distToSeg2}
     * @see {@link http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment}
     * @memberof Vector
     */
    static distToSeg(p, v, w) {
        return Math.sqrt(Vector.distToSeg2(p, v, w));
    }

    /**
     * Get the shortest distance squared between the point p and the line
     * segment v to w.
     *
     * @static
     * @param {Vector} p The vector point
     * @param {Vector} v The first line segment endpoint
     * @param {Vector} w The second line segment endpoint
     * @returns The shortest euclidean distance squared between point
     * @see {@link distToSeg}
     * @see {@link http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment}
     * @memberof Vector
     */
    static distToSegSquared(p, v, w) {
        const l = Vector.dist2(v, w);
        if (l === 0) { return Vector.dist2(p, v); }
        let t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l;
        t = Math.max(0, Math.min(1, t));
        return Vector.dist2(p, new Vector(v.x + t * (w.x - v.x),
            v.y + t * (w.y - v.y)));
    }

    /**
     * Get the two normal vectors that are perpendicular to the current vector
     *
     * @returns {Vector[]} The two normal vectors that are perpendicular
     *  to the vector. The first vector is the normal vector that is +90 deg or
     *  +PI/2 rad. The second vector is the noraml vector that is -90 deg or
     *  -PI/2 rad.
     * @memberof Vector
     */
    perpendiculars() {
        const plus90 = new Vector(-this.y, this.x).normalize();
        const minus90 = new Vector(this.y, -this.x).normalize();
        return [plus90, minus90];
    }

    //---- Standard Static Vector Objects ----

    /**
     * Get a vector of no magnitude and no direction
     *
     * @static
     * @function
     * @returns {Vector} Vector of magnitude zero
     * @memberof Vector
     */
    static zero() {
        "use strict";
        return new Vector(0, 0);
    }

    /**
     * Get the unit vector pointing in the positive y direction
     *
     * @static
     * @function
     * @returns {Vector} Unit vector pointing up
     * @memberof Vector
     */
    static up() {
        "use strict";
        return new Vector(0, 1);
    }

    /**
     * Get the unit vector pointing in the negative y direction
     *
     * @static
     * @function
     * @returns {Vector} Unit vector pointing down
     * @memberof Vector
     */
    static down() {
        "use strict";
        return new Vector(0, -1);
    }

    /**
     * Get the unit vector pointing in the negative x direction
     *
     * @static
     * @function
     * @returns {Vector} Unit vector pointing right
     * @memberof Vector
     */
    static left() {
        "use strict";
        return new Vector(-1, 0);
    }

    /**
     * Get the unit vector pointing in the positive x direction
     *
     * @static
     * @function
     * @returns {Vector} Unit vector pointing right
     * @memberof Vector
     */
    static right() {
        "use strict";
        return new Vector(1, 0);
    }
}

export default Vector;<|endoftext|>


<commit_before>function connect(/* [nodes] */) {
  for (var i = 0; i < arguments.length - 1; i++) {
    var node = arguments[i]
    if (_.isArray(node)) {
      _.invoke(node, 'connect', arguments[i + 1])
    } else {
      arguments[i].connect(arguments[i + 1])
    }
  }
  return arguments[arguments.length - 1]
}

// TODO: web worker?
Scheduler = function() {}
_.extend(Scheduler.prototype, {
  running: {},

  start: function(generator, name) {
    if (!name) {
      name = _.uniqueId('play')
    }
    var task = {
      name: name,
      generator: generator,
      events: []
    }
    this.running[name] = task
    this._runTask(task, ctx.currentTime)
    this.tick()
    return task
  },

  stop: function(task) {
    delete this.running[task.name]
  },

  _runTask: function(task, t) {
    task.events = task.generator(t)
    if (task.events) {
      task.events = _.sortBy(task.events, 't')
    }
  },

  now: function() {
    return ctx.currentTime
  },

  tick: function() {
    // TODO: move into pattern's concern?
    function t(event) {
      if (event.scheduled) {
        // fudge events that run in another scheduler (Web
        // Audio) by registering them in the scheduler slightly
        // before they are due to run
        return event.t - .2
      } else {
        return event.t
      }
    }

    var now = this.now(),
        next = Number.MAX_VALUE

    _.each(this.running, function(task) {
      while (task.events[0] && t(task.events[0]) <= now) {
        var event = task.events.shift()
        try {
          event.run(event)
        } catch (e) {
          console.error('event run error', e)
        }
      }

      if (!task.events.length) {
        this._runTask(task, now)
      }

      if (task.events && task.events[0]) {
        next = Math.min(next, t(task.events[0]))
      }
    }, this)

    // prune finished tasks
    var stopped = _.filter(this.running, function(task) {
      return !task.events || !task.events.length
    })
    _.each(stopped, $.proxy(this, 'stop'))

    // schedule next tick
    if (next != Number.MAX_VALUE) {
      this._resetTimeout()
      var wait = Math.max((next - now) * 1000, 100)
      this.timeout = setTimeout($.proxy(this, 'tick'), wait)
    }
  },

  _resetTimeout: function() {
    if (this.timeout) {
      clearTimeout(this.timeout)
      this.timeout = null
    }
  },

  stopAll: function() {
    this._resetTimeout()
    this.running = {}
  }
})

function Samples() {}
_.extend(Samples.prototype, {
  index: {},

  fromArrayBuffer: function(name, ab) {
    ctx.decodeAudioData(ab, _.bind(function(buf) {
      console.log('loaded file', name)
      this.index[name] = buf
    }, this))
  },

  download: function(url) {
    var name = _.last(url.split('/'))
    if (name in this.index) {
      return
    }

    var xhr = new XMLHttpRequest()
    xhr.open('GET', url, true)
    xhr.responseType = 'arraybuffer'
    xhr.onload = _.bind(function() {
      this.fromArrayBuffer(name, xhr.response)
    }, this)
    xhr.send()
  }
})

jam = {
  samples: new Samples,
  scheduler: new Scheduler
}

var ctx = new webkitAudioContext()

jam.out = ctx.createGainNode()
jam.gain = ctx.createGainNode()
connect(jam.out, jam.gain, ctx.destination)

jam.outbuffer = ctx.createScriptProcessor(1024, ctx.destination.channelCount, ctx.destination.channelCount)
connect(jam.out, jam.outbuffer, ctx.destination)
<commit_msg>Return sample name from samples.download().<commit_after>function connect(/* [nodes] */) {
  for (var i = 0; i < arguments.length - 1; i++) {
    var node = arguments[i]
    if (_.isArray(node)) {
      _.invoke(node, 'connect', arguments[i + 1])
    } else {
      arguments[i].connect(arguments[i + 1])
    }
  }
  return arguments[arguments.length - 1]
}

// TODO: web worker?
Scheduler = function() {}
_.extend(Scheduler.prototype, {
  running: {},

  start: function(generator, name) {
    if (!name) {
      name = _.uniqueId('play')
    }
    var task = {
      name: name,
      generator: generator,
      events: []
    }
    this.running[name] = task
    this._runTask(task, ctx.currentTime)
    this.tick()
    return task
  },

  stop: function(task) {
    delete this.running[task.name]
  },

  _runTask: function(task, t) {
    task.events = task.generator(t)
    if (task.events) {
      task.events = _.sortBy(task.events, 't')
    }
  },

  now: function() {
    return ctx.currentTime
  },

  tick: function() {
    // TODO: move into pattern's concern?
    function t(event) {
      if (event.scheduled) {
        // fudge events that run in another scheduler (Web
        // Audio) by registering them in the scheduler slightly
        // before they are due to run
        return event.t - .2
      } else {
        return event.t
      }
    }

    var now = this.now(),
        next = Number.MAX_VALUE

    _.each(this.running, function(task) {
      while (task.events[0] && t(task.events[0]) <= now) {
        var event = task.events.shift()
        try {
          event.run(event)
        } catch (e) {
          console.error('event run error', e)
        }
      }

      if (!task.events.length) {
        this._runTask(task, now)
      }

      if (task.events && task.events[0]) {
        next = Math.min(next, t(task.events[0]))
      }
    }, this)

    // prune finished tasks
    var stopped = _.filter(this.running, function(task) {
      return !task.events || !task.events.length
    })
    _.each(stopped, $.proxy(this, 'stop'))

    // schedule next tick
    if (next != Number.MAX_VALUE) {
      this._resetTimeout()
      var wait = Math.max((next - now) * 1000, 100)
      this.timeout = setTimeout($.proxy(this, 'tick'), wait)
    }
  },

  _resetTimeout: function() {
    if (this.timeout) {
      clearTimeout(this.timeout)
      this.timeout = null
    }
  },

  stopAll: function() {
    this._resetTimeout()
    this.running = {}
  }
})

function Samples() {}
_.extend(Samples.prototype, {
  index: {},

  fromArrayBuffer: function(name, ab) {
    ctx.decodeAudioData(ab, _.bind(function(buf) {
      console.log('loaded file', name)
      this.index[name] = buf
    }, this))
  },

  download: function(url) {
    var name = _.last(url.split('/'))
    if (name in this.index) {
      return name
    }

    var xhr = new XMLHttpRequest()
    xhr.open('GET', url, true)
    xhr.responseType = 'arraybuffer'
    xhr.onload = _.bind(function() {
      this.fromArrayBuffer(name, xhr.response)
    }, this)
    xhr.send()
    return name
  }
})

jam = {
  samples: new Samples,
  scheduler: new Scheduler
}

var ctx = new webkitAudioContext()

jam.out = ctx.createGainNode()
jam.gain = ctx.createGainNode()
connect(jam.out, jam.gain, ctx.destination)

jam.outbuffer = ctx.createScriptProcessor(1024, ctx.destination.channelCount, ctx.destination.channelCount)
connect(jam.out, jam.outbuffer, ctx.destination)
<|endoftext|>


<commit_before>var DiscordClient = require('discord.io');
var bot = new DiscordClient({
    token: "...",
    autorun: true
});

bot.on('ready', function(rawEvent) {
   console.log(bot.username + " - (" + bot.id + ")" + "Token: " + "[[" + bot.internals.token + "]]");
    bot.setPresence({
    game: "Doom"
    });

     // Reminds the channel to
    function remindChannel() {
        bot.sendMessage({
            to: "102910652447752192",   // test-area channel
            message: "To see my commands type: *!Commands*",
            typing: true
        });
    }
    setInterval(remindChannel, 7200000); // @ every 2 hours
});

bot.on('presence', function(user, userID, status, gameName, rawEvent) {

 });

bot.on('message', function(user, userID, channelID, message, rawEvent) {

    if(message.toLowerCase() === "!commands"){
    bot.sendMessage({
        to: channelID,
         message: "<@" + userID + ">"+ "```Akephalos\nHere are my commands:\n\n1. @mentions: gives you a rude statement.\n2. !Sample text: Outputs Sample Text Youtube video.\n3. !ping: See ping status\n4. Peace or Godnight: Saying peace or goodnight will result in Akephalos also saying goodbye.\n5. No invite?: Results in saying that, that's cold.\n6. !rekt: Display's rekt meme gif.\n7. 1V1: Bot will fight you.\n8. !Yes: Creepy Jack gif\n9. Why?: Go ahead ask me why.```"
        });
    }

    if(message.toLowerCase() === "!yes"){
        bot.sendMessage({
            to: channelID,
            message:"https://media.giphy.com/media/3rgXBOmTlzyFCURutG/giphy.gif"
        });
       }

    if ((message.toLowerCase() === "!delete") && user === "Mesmaroth")
    {
         bot.getMessages({
            channel: channelID,
            limit: 100 //If 'limit' isn't added, it defaults to 50, the Discord default, 100 is the max.
        }, function(messageArr) {
            for(var i=0;i<5;i++)            // Deletes the last 5 messages
            {
                var ID = messageArr[i].id;
                bot.deleteMessage({
                    channel: channelID,
                    messageID: ID
                });
            }
        });
    }
    else if (message.toLowerCase() === "!delete" && user !== "Mesmaroth")
    {
        bot.sendMessage({
            to: channelID,
            message: "<@" + userID + ">" + " You are not authorized to use this command.",
            typing: true
        });
    }

    // check to see if bot is mentioned
    function mentionedMe(rawEvent) {
        var mentionArr = rawEvent.d.mentions;
        for (var i=0; i<mentionArr.length; i++) {
            if (mentionArr[i].id === bot.id) {
                return true;
            }
        }
        return false;
    }

    // if bot is mentioned with having FU;
    if ( message.toLowerCase() === ("<@" + bot.id + ">"+ "Fuck you")){
        bot.sendMessage({
            to: channelID,
            message: "<@" + userID + ">"+" Why you mad!",
            typing: true
        });
        console.log(bot.id);
        console.log("mentions failed");

    }
    else if (mentionedMe(rawEvent))
    {
        bot.sendMessage({
            to: channelID,
            message: "Why you calling me? Fuck off!",
            typing: true
        });

    }

    if ( message.toLowerCase() === "fuck you!") {
        bot.sendMessage({
            to: channelID,
            message: "http://4.bp.blogspot.com/-XWNXDprHibk/UYxniZERK6I/AAAAAAAAW1Y/RyvRcq_Q_cc/s640/vlcsnap-2011-11-10-19h19m39s159.png"
        });

    }

    //sample text
    if(message.toLowerCase() === "!sample text" || message.toLowerCase() === "!sp"){
        bot.sendMessage({
            to: channelID,
            message: "SampleText.MP4?\nhttps://www.youtube.com/watch?v=Tlr1L8FHp2U",
        });
    }

    //check ping
    if(message.toLowerCase() === "!ping"){
        bot.sendMessage({
            to: channelID,
            message: "<@" + userID + ">" + " Ping deez nuts in your mouth",
            typing: true
        });
    }

    // Say goodye
    if(message.toLowerCase()==="peace" || message.toLowerCase()==="goodnight"){
        bot.sendMessage({
            to: channelID,
            message: "Bye! :)",
            typing: true

        });
    }

    // for when somone didn't invite someone
    if(message.toLowerCase() === "no invite?"){
        bot.sendMessage({
            to: channelID,
            message:"That's cold blooded right there man.",
            typing: true
        });
    }

    // For when someone says rekt
    if(message.toLowerCase() === "!rekt" || message.toLowerCase() === "rekt") {
        bot.sendMessage({
            to: channelID,
            message: "https://giphy.com/gifs/rekt-vSR0fhtT5A9by"
        });
    }

    // For when someone says !1v1
    if (message.toLowerCase()=== "1v1"){
        bot.sendMessage({
            to: channelID,
            message: "<@" + userID + ">"+" My nigga! Let's go then bitch!!",
            typing: true
        });
    }

    // for when someone says why?
    if (message.toLowerCase() === "why?"){
        bot.sendMessage({
            to: channelID,
            message: "<@" + userID + ">" + " Because fuck you! That's why!",
            typing: true
        });
    }

});

<commit_msg>Reorganized code and made msg delete commands for individual members.<commit_after>var DiscordClient = require('discord.io');
var bot = new DiscordClient({
    token: "...",
    autorun: true
});

bot.on('ready', function(rawEvent) {
    //bot.setName();
    require('fs').writeFileSync('./bot.json', JSON.stringify(bot, null, '\t'))
    console.log(bot.username + " - (" + bot.id + ")" + "Token: " + "[[" + bot.internals.token + "]]");
    bot.setPresence({game: "Doom"});

     // Reminds the channel to
    function remindChannel() {
        bot.sendMessage({
            to: "102910652447752192",   // test-area channel
            message: "To see my commands type: *!Commands*",
            typing: true
        });
    }
    setInterval(remindChannel, 7200000); // @ every 2 hours
});

bot.on('presence', function(user, userID, status, gameName, rawEvent) {

 });

bot.on('message', function(user, userID, channelID, message, rawEvent) {

    if(message.toLowerCase() === "!commands") {
    bot.sendMessage({
        to: channelID,
         message: "<@" + userID + ">"+ "```Akephalos\nHere are my commands:\n\n1. @mentions: gives you a rude statement.\n2. !Sample text: Outputs Sample Text Youtube video.\n3. !ping: See ping status\n4. Peace or Godnight: Saying peace or goodnight will result in Akephalos also saying goodbye.\n5. No invite?: Results in saying that, that's cold.\n6. !rekt: Display's rekt meme gif.\n7. 1V1: Bot will fight you.\n8. !Yes: Creepy Jack gif\n9. Why?: Go ahead ask me why.\n10. !doit: JUST DO IT!```"
        });
    }

    if(message.toLowerCase() === "!yes") {
        bot.sendMessage({
            to: channelID,
            message:"https://media.giphy.com/media/3rgXBOmTlzyFCURutG/giphy.gif"
        });
       }

    if ((message.toLowerCase() === "!delete") && user === "Mesmaroth") {
         bot.getMessages({
            channel: channelID,
            limit: 100 //If 'limit' isn't added, it defaults to 50, the Discord default, 100 is the max.
        }, function(messageArr) {
            for(var i = 0; i < messageArr.length; i++)
            {
                var msgID = messageArr[i].id;
                bot.deleteMessage({
                    channel: channelID,
                    messageID: msgID
                })
            }
        });
    }
    else if((message.toLowerCase() === "!delete") && user !== "Mesmaroth") {
        bot.sendMessage({
            to: channelID,
            message: "<@" + userID + ">" + " You are not authorized to use this command.",
            typing: true
        });
    }

// Delete Bot messages only.
if(message.toLowerCase() === "!delmsgakephalos" && user === "Mesmaroth"){
    bot.getMessages({
        channel: channelID,
        limit: 100
    }, function(messageArr){
        for(var i = 0; i < messageArr.length; i++) {
            if(messageArr[i].author.username === 'Akephalos (Bot)') {
                bot.deleteMessage({
                    channel: channelID,
                    messageID: messageArr[i].id
                });
            }
        }
    });
}
    // Delete Mesmaroth messages only
    if(message.toLowerCase() === "!delmsgmes" && user === "Mesmaroth") {
        bot.getMessages({
            channel: channelID,
            limit: 100
        }, function(messageArr){
            var msgsDeleted = 0;
            for(var i = 0; i < messageArr.length; i++){
                if(messageArr[i].author.username === 'Mesmaroth'){
                    bot.deleteMessage({
                        channel: channelID,
                        messageID: messageArr[i].id
                    });
                    msgsDeleted+=1;
                }
            }
            console.log("Deleted "+ (msgsDeleted-1) + " messages for " + user);
        });
    }

// Delete gun messages only
if(message.toLowerCase() === "$sudo rm gun -r" && user === "Gun") {
    bot.getMessages({
        channel: channelID,
        limit: 100
    }, function(messageArr){
        var msgsDeleted = 0;
        for(var i = 0; i < messageArr.length; i++){
            if(messageArr[i].author.username === 'Gun'){
                bot.deleteMessage({
                    channel: channelID,
                    messageID: messageArr[i].id
                });
                msgsDeleted+=1;
            }
        }
        console.log("Deleted "+ (msgsDeleted-1) + " messages for " + user); // not including command request
    });
}
else if(message.toLowerCase() === "$sudo rm gun -r" && user !== "Gun") {
    bot.sendMessage({
        to: channelID,
        message: "<@"+userID + ">" + "You are not authorized to do that.",
        typing: true
    });
}

if(message === "!getMsgs") {
    bot.getMessages({
        channel: channelID,
        limit: 50
    }, function(messageArr){
        console.log(messageArr);
    });
}
if(message=== "!rawEvent")
{
    console.log(rawEvent);
}
// --------------------------------------

    // check to see if bot is mentioned
    function mentionedMe(rawEvent) {
        var mentionArr = rawEvent.d.mentions;
        for (var i=0; i<mentionArr.length; i++) {
            if (mentionArr[i].id === bot.id) {
                return true;
            }
        }
        return false;
    }

    // if bot is mentioned with having FU;
    if ( message.toLowerCase() === "<@" + bot.id + ">"+ " fuck you!") {
        bot.sendMessage({
            to: channelID,
            message: "<@" + userID + ">"+" Why you mad!",
            typing: true
        });
    }
    else if (mentionedMe(rawEvent)) {
        bot.sendMessage({
            to: channelID,
            message: "Why you calling me? Fuck off!",
            typing: true
        });

    }

    if ( message.toLowerCase() === "fuck you!") {
        bot.sendMessage({
            to: channelID,
            message: "http://4.bp.blogspot.com/-XWNXDprHibk/UYxniZERK6I/AAAAAAAAW1Y/RyvRcq_Q_cc/s640/vlcsnap-2011-11-10-19h19m39s159.png"
        });

    }

    //sample text
    if(message.toLowerCase() === "!sample text" || message.toLowerCase() === "!sp") {
        bot.sendMessage({
            to: channelID,
            message: "SampleText.MP4?\nhttps://www.youtube.com/watch?v=Tlr1L8FHp2U",
        });
    }

    //check ping
    if(message.toLowerCase() === "!ping") {
        bot.sendMessage({
            to: channelID,
            message: "<@" + userID + ">" + " Ping deez nuts in your mouth",
            typing: true
        });
    }

    // Say goodye
    if(message.toLowerCase()==="peace" || message.toLowerCase()==="goodnight") {
        bot.sendMessage({
            to: channelID,
            message: "Bye! :)",
            typing: true

        });
    }

    // for when somone didn't invite someone
    if(message.toLowerCase() === "no invite?") {
        bot.sendMessage({
            to: channelID,
            message:"That's cold blooded right there man.",
            typing: true
        });
    }

    // For when someone says rekt
    if(message.toLowerCase() === "!rekt" || message.toLowerCase() === "rekt") {
        bot.sendMessage({
            to: channelID,
            message: "https://giphy.com/gifs/rekt-vSR0fhtT5A9by"
        });
    }

    // For when someone says !1v1
    if (message.toLowerCase()=== "1v1") {
        bot.sendMessage({
            to: channelID,
            message: "<@" + userID + ">"+" My nigga! Let's go then bitch!!",
            typing: true
        });
    }

    // for when someone says why?
    if (message.toLowerCase() === "why?") {
        bot.sendMessage({
            to: channelID,
            message: "<@" + userID + ">" + " Because fuck you! That's why!",
            typing: true
        });
    }
    if(message.toLowerCase() === "!doit") {
        bot.sendMessage({
            to: channelID,
            message: "https://media.giphy.com/media/TCaq4FekwSV5m/giphy.gif"
        });
    }

});

<|endoftext|>


<commit_before>'use strict';

exports.ValidationError = class extends Error {
  constructor(errors) {

    super(errors.name)
    this.name = 'IllegalAccessError'
    this.message = 'Validation error';
    this.errors = errors;
    this.status = '400';
    this.statusText = 'Internal Server Error';
  }
}
<commit_msg>add error transformer for hapi like validation response error<commit_after>'use strict';

const _ = require('lodash');

exports.ValidationError = class extends Error {
  constructor(error) {

    super(error)

    // flat all errors for hapi like validation error response
    const flat = error.details.map(details => {
      return {
        key: _.map(details.context),
        source: details.path.split('.')[0]
      }
    })

    error.name = '';
    this.name = error.toString();
    this.error = 'Bad Request';
    this.statusCode = '400';
    this.validation = {
      key: _.flatten(_.map(flat, 'key')),
      source: _.uniq(_.flatten(_.map(flat, 'source')))[0]
    };
  }
}
<|endoftext|>


<commit_before>var domElements = (function domElementsModule(document, Array, Element, Node, Object, Window) {
    // Fields

    // Parsing the native toString() return value e.g. [object Object]
    var _reTypeOf = /(?:^\[object\s(.*?)\]$)/;

    // Node types
    var _nodeTypeDocumentNode = Node.DOCUMENT_NODE;
    var _nodeTypeFragmentNode = Node.DOCUMENT_FRAGMENT_NODE;
    var _nodeTypeElementNode = Node.ELEMENT_NODE;

    // Polyfills and caching

    var _arrayPrototype = Array.prototype;
    var _arrayFilter = _arrayPrototype.filter;
    var _arraySlice = _arrayPrototype.slice;
    var _arrayFrom = Array.from || function arrayFrom(arrayLike) {
        return _arraySlice.call(arrayLike);
    };

    var _elementPrototype = Element.prototype;

    // URL: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
    var _elementClosest =
        _elementPrototype.closest || function elementClosest(el, selector) {
            var parentNode = el;
            while (parentNode && parentNode.nodeType !== _nodeTypeFragmentNode && !matches(parentNode, selector)) {
                parentNode = parentNode.parentNode;
            }

            return parentNode || null;
        };

    // URL: https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
    var _elementMatches =
        _elementPrototype.matches ||
        _elementPrototype.mozMatchesSelector ||
        _elementPrototype.msMatchesSelector ||
        _elementPrototype.webkitMatchesSelector ||
        function elementMatches(node, selector) {
            var nodes = (node.ownerDocument || document).querySelectorAll(selector);

            var index = 0;
            while (nodes[index] && node !== nodes[index]) {
                index++;
            }

            return !!nodes[index];
        };

    var _objectToString = Object.prototype.toString;

    // Public API
    return {
        $$: $$,
        $: $,
        after: after,
        append: append,
        around: wrap,
        before: before,
        children: children,
        closest: closest,
        contents: contents,
        empty: empty,
        inside: append,
        is: matches,
        matches: matches,
        next: next,
        parent: parent,
        parents: parents,
        prepend: prepend,
        prev: previous,
        previous: previous,
        remove: remove,
        renew: replace,
        replace: replace,
        siblings: siblings,
        start: prepend,
        styles: styles,
        unwrap: unwrap,
        wrap: wrap,

        // Helper functions not related to DOM traversal or manipulation
        toArray: _arrayFrom,
        type: type,
    };

    /**
     * Wrapper for *.querySelector
     * Idea by Bliss, URL: https://github.com/LeaVerou/bliss/blob/gh-pages/bliss.js
     *
     * @param {string} selector Selector string
     * @param {object|null|undefined} context Node to query on. Default is document if falsy
     * @return {Node|null} A node; otherwise, null on error
     */
    function $(selector, context) {
        return type(selector) === 'string' ?
            (context || document).querySelector(selector) :
            (selector || null);
    }

    /**
     * Wrapper for *.querySelectorAll
     * Idea by Bliss, URL: https://github.com/LeaVerou/bliss/blob/gh-pages/bliss.js
     *
     * @param {string} selector Selector string
     * @param {object|null|undefined} context Node to query on. Default is document if falsy
     * @return {array} An array of nodes; otherwise, an empty array on error
     */
    function $$(selector, context) {
        if (selector instanceof Node || selector instanceof Window) {
            return [selector];
        }

        return type(selector) === 'string' ?
            _arrayFrom((context || document).querySelectorAll(selector)) :
            (selector || []);
    }

    /**
     * Insert a node after another node
     *
     * @param {Node} node Node to insert after
     * @param {Node} nodeAfter Node to insert
     * @return {undefined}
     */
    function after(node, nodeAfter) {
        if (node.parentNode) {
            node.parentNode.insertBefore(nodeAfter, node.nextSibling);
        }
    }

    /**
     * Insert a node after an node's content
     *
     * @param {Node} node Node to append after
     * @param {Node} nodeAfter Node to append
     * @return {undefined}
     */
    function append(node, nodeAfter) {
        node.appendChild(nodeAfter);
    }

    /**
     * Insert a node before another node
     *
     * @param {Node} node Node to insert before
     * @param {Node} nodeAfter Node to insert
     * @return {undefined}
     */
    function before(node, nodeBefore) {
        if (node.parentNode) {
            node.parentNode.insertBefore(nodeBefore, node);
        }
    }

    /**
     * Get the children of a node
     *
     * @param {Node} node Node to get the children of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @return {array} Array of nodes/elements; otherwise, an empty array on error
     */
    function children(node, jQueryLike) {
        var nodes = node.childNodes;

        // Enforce the default value
        var allNodes = jQueryLike !== true;

        return _arrayFilter.call(nodes, function filter(node) {
            return allNodes || node.nodeType === _nodeTypeElementNode;
        });
    }

    /**
     * Get the closest element node using a selector string
     * Idea by jonathantneal, URL: https://github.com/jonathantneal/closest/blob/master/closest.js
     *
     * @param {Element} el Element node to start searching from
     * @param {string} selector Selector string
     * @return {Element|null} Closest element node; otherwise, null on error
     */
    function closest(el, selector) {
        return _elementClosest.call(el, selector);
    }

    /**
     * Get the contents of a node
     *
     * @param {HTMLIFrameElement|Node} el HTMLIFrameElement/Node to get the contents of
     * @return {Document|array} A Document if an iFrame/an array of nodes; otherwise, an empty array on error
     */
    function contents(el) {
        var contents = el.documentContent;
        if (contents) {
            return contents;
        }

        return _arrayFrom(el.childNodes);
    }

    /**
     * Empty the contents of a node
     * Idea by dom.js, URL: https://github.com/component/dom/blob/master/dom.js#L2789
     *
     * @param {Node} node Node to empty
     * @return {undefined}
     */
    function empty(node) {
        node.textContent = '';
    }

    /**
     * Check if an element node matches a selector string
     * Idea by jonathantneal, URL: https://github.com/jonathantneal/closest/blob/master/closest.js
     *
     * @param {Element} el Element node to match on
     * @param {string} selector Selector string
     * @return {Element|null} True, the element node matches the selector string; otherwise, false
     */
    function matches(el, selector) {
        return _elementMatches.call(el, selector);
    }

    /**
     * Get the next sibling of a node
     *
     * @param {Node} node Node to get the next sibling of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @return {Node} A node; otherwise, null on error
     */
    function next(node, jQueryLike) {
        return _sibling(node, jQueryLike, 'nextSibling');
    }

    /**
     * Get the parent of a node
     *
     * @param {Node} node Node to get the parent of
     * @return {Node|null} Node; otherwise, null
     */
    function parent(node) {
        var parentNode = node.parentNode;

        return parentNode && parentNode.nodeType !== _nodeTypeFragmentNode ? parentNode : null;
    }

    /**
     * Get the parents of a node
     *
     * @param {Node} node Node to get the parents of
     * @return {array} An array of nodes; otherwise, an empty array
     */
    function parents(node) {
        var parentNode = node.parentNode;

        var parentNodes = [];
        while (parentNode && parentNode.nodeType !== _nodeTypeDocumentNode) {
            parentNodes.push(parentNode);
            parentNode = parentNode.parentNode;
        }

        return parentNodes;
    }

    /**
     * Insert a node before an node's content
     *
     * @param {Node} node Node to prepend before
     * @param {Node} nodeAfter Node to prepend
     * @return {undefined}
     */
    function prepend(node, nodeBefore) {
        node.insertBefore(nodeBefore, node.firstChild);
    }

    /**
     * Get the previous sibling of a node
     *
     * @param {Node} node Node to get the previous sibling of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @return {Node} A node; otherwise, null on error
     */
    function previous(node, jQueryLike) {
        return _sibling(node, jQueryLike, 'previousSibling');
    }

    /**
     * Remove a node
     *
     * @param {Node} node Node to remove
     * @return {undefined}
     */
    function remove(node) {
        if (node.parentNode) {
            node.parentNode.removeChild(node);
        }
    }

    /**
     * Replace a node with another node
     *
     * @param {Node} node Node to replace
     * @param {Node} nodeReplacement Node to replace with
     * @return {undefined}
     */
    function replace(node, nodeReplacement) {
        if (node.parentNode) {
            node.parentNode.replaceChild(nodeReplacement, node);
        }
    }

    /**
     * Get the siblings of a node
     *
     * @param {Node} node Node to get the siblings of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @return {array} Array of nodes/elements; otherwise, an empty array on error
     */
    function siblings(node, jQueryLike) {
        // Could use node.parentNode.children if other node types are not required
        var siblingNodes = [];

        var sibling = node.parentNode;
        if (!sibling) {
            return siblingNodes;
        }

        // Enforce the default value
        var allNodes = jQueryLike !== true;

        sibling = sibling.firstChild;
        while (sibling) {
            if (node !== sibling && (allNodes || sibling.nodeType === _nodeTypeElementNode)) {
                siblingNodes.push(sibling);
            }

            sibling = sibling.nextSibling;
        }

        return siblingNodes;
    }

    /**
     * Get the computed styles of a node
     *
     * @param {Node} node Node to retrieve the styles of
     * @return {object} Object of styles
     */
    function styles(node) {
        return node.ownerDocument.defaultView.getComputedStyle(node, null);
    }

    /**
     * An advanced variation of typeOf, that returns the classname instead of the primitive datatype e.g. 'array', 'date', 'null', 'regexp', string'
     * Idea by JavaScript Weblog, URL: https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
     *
     * @param {mixed} value Variable to check
     * @return {string} Classname of the value
     */
    function type(value) {
        var tag = _objectToString
            .call(value)
            .replace(_reTypeOf, '$1')
            .toLowerCase();
        if (tag === 'number' && value !== value) { // eslint-disable-line
            // Override number if a NaN
            tag = 'nan';
        }

        return tag;
    }

    /**
     * Wrap a node with another node
     *
     * @param {Node} node Node to wrap around
     * @param {Node} nodeWrap Node to wrap with
     * @return {undefined}
     */
    function wrap(node, nodeWrap) {
        before(node, nodeWrap);

        // Idea by Bliss, URL: https://github.com/LeaVerou/bliss/blob/gh-pages/bliss.shy.js#L624
        var reIsTemplate = /(?:^template$)/i;
        if (reIsTemplate.test(nodeWrap.nodeName) && nodeWrap.content) {
            nodeWrap = nodeWrap.content;
        }

        nodeWrap.appendChild(node);
    }

    /**
     * Unwrap a node
     * Idea by plainjs.com, URL: https://plainjs.com/javascript/manipulation/unwrap-a-dom-element-35/
     *
     * @param {Node} node Node to unwrap
     * @return {undefined}
     */
    function unwrap(node) {
        var parentNode = node.parentNode;
        if (!parentNode) {
            return;
        }

        while (node.firstChild) {
            parentNode.insertBefore(node.firstChild, node);
        }

        parentNode.removeChild(node);
    }

     /**
     * Get the type e.g. next/previous sibling of a node
     *
     * @param {Node} node Node to get the sibling type of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @param {string} type Sibling type e.g. nextSibling or previousSibling
     * @return {Node} A node; otherwise, null on error
     */
    function _sibling(node, jQueryLike, type) {
        // Enforce the default value
        var allNodes = jQueryLike !== true;

        var sibling = node[type];
        while (!allNodes && sibling && sibling.nodeType !== _nodeTypeElementNode) {
            sibling = sibling[type];
        }

        return sibling;
    }
}(window.document, window.Array, window.Element, window.Node, window.Object, window.Window));
<commit_msg>Added nextAll and previousAll<commit_after>var domElements = (function domElementsModule(document, Array, Element, Node, Object, Window) {
    // Fields

    // Parsing the native toString() return value e.g. [object Object]
    var _reTypeOf = /(?:^\[object\s(.*?)\]$)/;

    // Node types
    var _nodeTypeDocumentNode = Node.DOCUMENT_NODE;
    var _nodeTypeFragmentNode = Node.DOCUMENT_FRAGMENT_NODE;
    var _nodeTypeElementNode = Node.ELEMENT_NODE;

    // Polyfills and caching

    var _arrayPrototype = Array.prototype;
    var _arrayFilter = _arrayPrototype.filter;
    var _arraySlice = _arrayPrototype.slice;
    var _arrayFrom = Array.from || function arrayFrom(arrayLike) {
        return _arraySlice.call(arrayLike);
    };

    var _elementPrototype = Element.prototype;

    // URL: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
    var _elementClosest =
        _elementPrototype.closest || function elementClosest(el, selector) {
            var parentNode = el;
            while (parentNode && parentNode.nodeType !== _nodeTypeFragmentNode && !matches(parentNode, selector)) {
                parentNode = parentNode.parentNode;
            }

            return parentNode || null;
        };

    // URL: https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
    var _elementMatches =
        _elementPrototype.matches ||
        _elementPrototype.mozMatchesSelector ||
        _elementPrototype.msMatchesSelector ||
        _elementPrototype.webkitMatchesSelector ||
        function elementMatches(node, selector) {
            var nodes = (node.ownerDocument || document).querySelectorAll(selector);

            var index = 0;
            while (nodes[index] && node !== nodes[index]) {
                index++;
            }

            return !!nodes[index];
        };

    var _objectToString = Object.prototype.toString;

    // Public API
    return {
        $$: $$,
        $: $,
        after: after,
        append: append,
        around: wrap,
        before: before,
        children: children,
        closest: closest,
        contents: contents,
        empty: empty,
        inside: append,
        is: matches,
        matches: matches,
        next: next,
        nextAll: nextAll,
        parent: parent,
        parents: parents,
        prepend: prepend,
        prev: previous,
        previous: previous,
        prevAll: previousAll,
        previousAll: previousAll,
        remove: remove,
        renew: replace,
        replace: replace,
        siblings: siblings,
        start: prepend,
        styles: styles,
        unwrap: unwrap,
        wrap: wrap,

        // Helper functions not related to DOM traversal or manipulation
        toArray: _arrayFrom,
        type: type,
    };

    /**
     * Wrapper for *.querySelector
     * Idea by Bliss, URL: https://github.com/LeaVerou/bliss/blob/gh-pages/bliss.js
     *
     * @param {string} selector Selector string
     * @param {object|null|undefined} context Node to query on. Default is document if falsy
     * @return {Node|null} A node; otherwise, null on error
     */
    function $(selector, context) {
        return type(selector) === 'string' ?
            (context || document).querySelector(selector) :
            (selector || null);
    }

    /**
     * Wrapper for *.querySelectorAll
     * Idea by Bliss, URL: https://github.com/LeaVerou/bliss/blob/gh-pages/bliss.js
     *
     * @param {string} selector Selector string
     * @param {object|null|undefined} context Node to query on. Default is document if falsy
     * @return {array} An array of nodes; otherwise, an empty array on error
     */
    function $$(selector, context) {
        if (selector instanceof Node || selector instanceof Window) {
            return [selector];
        }

        return type(selector) === 'string' ?
            _arrayFrom((context || document).querySelectorAll(selector)) :
            (selector || []);
    }

    /**
     * Insert a node after another node
     *
     * @param {Node} node Node to insert after
     * @param {Node} nodeAfter Node to insert
     * @return {undefined}
     */
    function after(node, nodeAfter) {
        if (node.parentNode) {
            node.parentNode.insertBefore(nodeAfter, node.nextSibling);
        }
    }

    /**
     * Insert a node after an node's content
     *
     * @param {Node} node Node to append after
     * @param {Node} nodeAfter Node to append
     * @return {undefined}
     */
    function append(node, nodeAfter) {
        node.appendChild(nodeAfter);
    }

    /**
     * Insert a node before another node
     *
     * @param {Node} node Node to insert before
     * @param {Node} nodeAfter Node to insert
     * @return {undefined}
     */
    function before(node, nodeBefore) {
        if (node.parentNode) {
            node.parentNode.insertBefore(nodeBefore, node);
        }
    }

    /**
     * Get the children of a node
     *
     * @param {Node} node Node to get the children of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @return {array} Array of nodes/elements; otherwise, an empty array on error
     */
    function children(node, jQueryLike) {
        var nodes = node.childNodes;

        // Enforce the default value
        var allNodes = jQueryLike !== true;

        return _arrayFilter.call(nodes, function filter(node) {
            return allNodes || node.nodeType === _nodeTypeElementNode;
        });
    }

    /**
     * Get the closest element node using a selector string
     * Idea by jonathantneal, URL: https://github.com/jonathantneal/closest/blob/master/closest.js
     *
     * @param {Element} el Element node to start searching from
     * @param {string} selector Selector string
     * @return {Element|null} Closest element node; otherwise, null on error
     */
    function closest(el, selector) {
        return _elementClosest.call(el, selector);
    }

    /**
     * Get the contents of a node
     *
     * @param {HTMLIFrameElement|Node} el HTMLIFrameElement/Node to get the contents of
     * @return {Document|array} A Document if an iFrame/an array of nodes; otherwise, an empty array on error
     */
    function contents(el) {
        var contents = el.documentContent;
        if (contents) {
            return contents;
        }

        return _arrayFrom(el.childNodes);
    }

    /**
     * Empty the contents of a node
     * Idea by dom.js, URL: https://github.com/component/dom/blob/master/dom.js#L2789
     *
     * @param {Node} node Node to empty
     * @return {undefined}
     */
    function empty(node) {
        node.textContent = '';
    }

    /**
     * Check if an element node matches a selector string
     * Idea by jonathantneal, URL: https://github.com/jonathantneal/closest/blob/master/closest.js
     *
     * @param {Element} el Element node to match on
     * @param {string} selector Selector string
     * @return {Element|null} True, the element node matches the selector string; otherwise, false
     */
    function matches(el, selector) {
        return _elementMatches.call(el, selector);
    }

    /**
     * Get the next sibling of a node
     *
     * @param {Node} node Node to get the next sibling of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @return {Node} Next sibling nodes; otherwise, null on error
     */
    function next(node, jQueryLike) {
        return _sibling(node, jQueryLike, 'nextSibling');
    }

    /**
     * Get the next siblings of a node
     *
     * @param {Node} node Node to get the next siblings of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @return {array} Array of next sibling nodes; otherwise, an empty array on error
     */
    function nextAll(node, jQueryLike) {
        return _siblingAll(node, jQueryLike, 'nextSibling');
    }

    /**
     * Get the parent of a node
     *
     * @param {Node} node Node to get the parent of
     * @return {Node|null} Node; otherwise, null
     */
    function parent(node) {
        var parentNode = node.parentNode;

        return parentNode && parentNode.nodeType !== _nodeTypeFragmentNode ? parentNode : null;
    }

    /**
     * Get the parents of a node
     *
     * @param {Node} node Node to get the parents of
     * @return {array} An array of nodes; otherwise, an empty array
     */
    function parents(node) {
        var parentNode = node.parentNode;

        var parentNodes = [];
        while (parentNode && parentNode.nodeType !== _nodeTypeDocumentNode) {
            parentNodes.push(parentNode);
            parentNode = parentNode.parentNode;
        }

        return parentNodes;
    }

    /**
     * Insert a node before an node's content
     *
     * @param {Node} node Node to prepend before
     * @param {Node} nodeAfter Node to prepend
     * @return {undefined}
     */
    function prepend(node, nodeBefore) {
        node.insertBefore(nodeBefore, node.firstChild);
    }

    /**
     * Get the previous sibling of a node
     *
     * @param {Node} node Node to get the previous sibling of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @return {Node} Previous sibling nodes; otherwise, null on error
     */
    function previous(node, jQueryLike) {
        return _sibling(node, jQueryLike, 'previousSibling');
    }

    /**
     * Get the previous siblings of a node
     *
     * @param {Node} node Node to get the previous siblings of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @return {array} Array of previous sibling nodes; otherwise, an empty array on error
     */
    function previousAll(node, jQueryLike) {
        return _siblingAll(node, jQueryLike, 'previousSibling');
    }

    /**
     * Remove a node
     *
     * @param {Node} node Node to remove
     * @return {undefined}
     */
    function remove(node) {
        if (node.parentNode) {
            node.parentNode.removeChild(node);
        }
    }

    /**
     * Replace a node with another node
     *
     * @param {Node} node Node to replace
     * @param {Node} nodeReplacement Node to replace with
     * @return {undefined}
     */
    function replace(node, nodeReplacement) {
        if (node.parentNode) {
            node.parentNode.replaceChild(nodeReplacement, node);
        }
    }

    /**
     * Get the siblings of a node
     *
     * @param {Node} node Node to get the siblings of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @return {array} Array of nodes/elements; otherwise, an empty array on error
     */
    function siblings(node, jQueryLike) {
        // Could use node.parentNode.children if other node types are not required
        var siblingNodes = [];

        var siblingNode = node.parentNode;
        if (!siblingNode) {
            return siblingNodes;
        }

        // Enforce the default value
        var allNodes = jQueryLike !== true;

        siblingNode = siblingNode.firstChild;
        while (siblingNode) {
            if (node !== siblingNode && (allNodes || siblingNode.nodeType === _nodeTypeElementNode)) {
                siblingNodes.push(siblingNode);
            }

            siblingNode = siblingNode.nextSibling;
        }

        return siblingNodes;
    }

    /**
     * Get the computed styles of a node
     *
     * @param {Node} node Node to retrieve the styles of
     * @return {object} Object of styles
     */
    function styles(node) {
        return node.ownerDocument.defaultView.getComputedStyle(node, null);
    }

    /**
     * An advanced variation of typeOf, that returns the classname instead of the primitive datatype e.g. 'array', 'date', 'null', 'regexp', string'
     * Idea by JavaScript Weblog, URL: https://javascriptweblog.wordpress.com/2011/08/08/fixing-the-javascript-typeof-operator/
     *
     * @param {mixed} value Variable to check
     * @return {string} Classname of the value
     */
    function type(value) {
        var tag = _objectToString
            .call(value)
            .replace(_reTypeOf, '$1')
            .toLowerCase();
        if (tag === 'number' && value !== value) { // eslint-disable-line
            // Override number if a NaN
            tag = 'nan';
        }

        return tag;
    }

    /**
     * Wrap a node with another node
     *
     * @param {Node} node Node to wrap around
     * @param {Node} nodeWrap Node to wrap with
     * @return {undefined}
     */
    function wrap(node, nodeWrap) {
        before(node, nodeWrap);

        // Idea by Bliss, URL: https://github.com/LeaVerou/bliss/blob/gh-pages/bliss.shy.js#L624
        var reIsTemplate = /(?:^template$)/i;
        if (reIsTemplate.test(nodeWrap.nodeName) && nodeWrap.content) {
            nodeWrap = nodeWrap.content;
        }

        nodeWrap.appendChild(node);
    }

    /**
     * Unwrap a node
     * Idea by plainjs.com, URL: https://plainjs.com/javascript/manipulation/unwrap-a-dom-element-35/
     *
     * @param {Node} node Node to unwrap
     * @return {undefined}
     */
    function unwrap(node) {
        var parentNode = node.parentNode;
        if (!parentNode) {
            return;
        }

        while (node.firstChild) {
            parentNode.insertBefore(node.firstChild, node);
        }

        parentNode.removeChild(node);
    }

    /**
     * Get the first sibling of a node based on a type e.g. next/previous
     *
     * @param {Node} node Node to get the sibling type of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @param {string} type Sibling type e.g. nextSibling or previousSibling
     * @return {Node} A sibling node; otherwise, null on error
     */
    function _sibling(node, jQueryLike, type) {
        // Enforce the default value
        var allNodes = jQueryLike !== true;

        var sibling = node[type];
        while (!allNodes && sibling && sibling.nodeType !== _nodeTypeElementNode) {
            sibling = sibling[type];
        }

        return sibling;
    }

    /**
     * Get all the siblings of a node based on a type e.g. next/previous
     *
     * @param {Node} node Node to get all the sibling types of
     * @param {boolean} jQueryLike Set to true to filter out those nodes which aren't elements (like jQuery). Default is false
     * @param {string} type Sibling type e.g. nextSibling or previousSibling
     * @return {array} An array of sibling nodes based on the type; otherwise, an empty array on error
     */
    function _siblingAll(node, jQueryLike, type) {
        // Enforce the default value
        var allNodes = jQueryLike !== true;
        var siblingNodes = [];

        var siblingNode = node[type];
        while (siblingNode) {
            if (allNodes || siblingNode.nodeType === _nodeTypeElementNode) {
                siblingNodes.push(siblingNode);
            }

            siblingNode = siblingNode[type];
        }

        return siblingNodes;
    }
}(window.document, window.Array, window.Element, window.Node, window.Object, window.Window));
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Amadeus s.a.s.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var Aria = require("../Aria");
var ariaUtilsDom = require("../utils/Dom");
var ariaCoreTimer = require("../core/Timer");
var ariaCoreBrowser = require("../core/Browser");

/**
 * This class contains an implementation of the aria.jsunit.IRobot interface which uses the Selenium Java Robot tool.
 * For this implementation to be usable, the browser must have been started with the Selenium Java Robot tool, which is
 * available at the following address: https://github.com/ariatemplates/selenium-java-robot
 */
module.exports = Aria.classDefinition({
    $classpath : 'aria.jsunit.RobotJavaSelenium',
    $extends : require("./RobotJava"),
    $implements : [require("./IRobot")],
    $singleton : true,
    $constructor : function () {
        this.$RobotJava.constructor.call(this);

        this._robotInitialized = false;

        /**
         * Offset to add to the X coordinates.
         * @type Number
         */
        this.offsetX = 0;

        /**
         * Offset to add to the Y coordinates.
         * @type Number
         */
        this.offsetY = 0;

        if (Aria.$frameworkWindow.top.attester) {
            this.offsetY = 32; // height of the header in attester
        }

        // This is updated in _offsetRecevied
        this._offset = {
            x : NaN,
            y : NaN
        };
    },
    $events : {
        "robotInitialized" : "Raised when the robot initialization has been done."
    },
    $statics : {
        ROBOT_ERROR : "An error occurred in the robot: %1"
    },
    $prototype : {

        /**
         * Return true if the robot is most likely usable.
         */
        isUsable : function () {
            return !!Aria.$frameworkWindow.top.SeleniumJavaRobot;
        },

        /**
         * Initialize the robot, if not already done. This must be called before any other method on the robot.
         * @param {aria.core.CfgBeans:Callback} callback callback to be called when the robot is ready to be used.
         */
        initRobot : function (cb) {
            if (!this._robot) {
                this._robot = Aria.$frameworkWindow.top.SeleniumJavaRobot;
                this._robot.getOffset({
                    fn : this._offsetReceived,
                    scope : this
                });
            }
            if (cb) {
                if (this._robotInitialized) {
                    this.$callback(cb);
                } else {
                    this.$onOnce({
                        "robotInitialized" : cb
                    });
                }
            }
        },

        _getScreenPos : function () {
            var window = Aria.$frameworkWindow;
            return {
                x : window.screenX != null ? window.screenX : window.screenLeft,
                y : window.screenY != null ? window.screenY : window.screenTop
            };
        },

        _offsetReceived : function (response) {
            if (response.success) {
                var res = response.result;
                var screenPos = this._getScreenPos();
                // Removes the current position on the screen so that, if the window is moved,
                // adding later the new position on the screen will give the correct coordinates.
                this._offset.x = res.x - screenPos.x;
                this._offset.y = res.y - screenPos.y;
            } else {
                this.$logError(this.ROBOT_ERROR, [response.result]);
            }
            if (!this._robotInitialized) {
                this._robotInitialized = true;
                this.$raiseEvent("robotInitialized");
            }
        },

        _callCallback : function (response, cb) {
            if (!response.success) {
                this.$logError(this.ROBOT_ERROR, [response.result]);
            }
            this.$callback(cb);
        },

        viewportToAbsolute : function (position) {
            var screenPos = this._getScreenPos();
            var offset = this._offset;
            return {
                x : screenPos.x + offset.x + this.offsetX + position.x,
                y : screenPos.y + offset.y + this.offsetY + position.y
            };
        },

        absoluteMouseMove : function (position, cb) {
            this._robot.mouseMove(position.x, position.y, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        absoluteSmoothMouseMove : function (from, to, duration, cb) {
            this._robot.smoothMouseMove(from.x, from.y, to.x, to.y, duration, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseMove : function (position, cb) {
            var viewport = ariaUtilsDom._getViewportSize();
            if (position.x < 0 || position.y < 0 || position.x > viewport.width || position.y > viewport.height) {
                // FIXME: log error correctly
                this.$logWarn("MouseMove position outside of the viewport.");
                // return;
            }
            this.absoluteMouseMove(this.viewportToAbsolute(position), cb);
        },

        smoothMouseMove : function (from, to, duration, cb) {
            var viewport = ariaUtilsDom._getViewportSize();
            if (from.x < 0 || from.y < 0 || from.x > viewport.width || from.y > viewport.height || to.x < 0 || to.y < 0
                    || to.x > viewport.width || to.y > viewport.height) {
                // FIXME: log error correctly
                this.$logWarn("smoothMouseMove from or to position outside of the viewport.");
                // return;
            }
            this.absoluteSmoothMouseMove(this.viewportToAbsolute(from), this.viewportToAbsolute(to), duration, cb);
        },

        mousePress : function (buttons, cb) {
            this._robot.mousePress(buttons, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseRelease : function (buttons, cb) {
            this._robot.mouseRelease(buttons, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseWheel : function (wheelAmt, cb) {
            this._robot.mouseWheel(wheelAmt, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        keyPress : function (keyCode, cb) {
            // IE sometimes miss some keystrokes, that's why we are adding a 100 ms
            // delay before each keypress (which experimentally seems to help...)
            // http://answers.microsoft.com/en-us/ie/forum/ie8-windows_other/internet-explorer-missing-keystroke-problem/1bee2ec3-828c-4a3d-8b05-638e44baf0a8
            ariaCoreTimer.addCallback({
                fn : this._keyPress,
                scope : this,
                args : {
                    keyCode : keyCode,
                    cb : cb
                },
                delay : ariaCoreBrowser.isIE ? 100 : 1
            });
        },

        _keyPress : function (args) {
            this._robot.keyPress(args.keyCode, {
                scope : this,
                fn : this._callCallback,
                args : args.cb
            });
        },

        keyRelease : function (keycode, cb) {
            this._robot.keyRelease(keycode, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        }
    }
});
<commit_msg>fix Selenium java robot offset when there is no attester iframe<commit_after>/*
 * Copyright 2012 Amadeus s.a.s.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var Aria = require("../Aria");
var ariaUtilsDom = require("../utils/Dom");
var ariaCoreTimer = require("../core/Timer");
var ariaCoreBrowser = require("../core/Browser");

/**
 * This class contains an implementation of the aria.jsunit.IRobot interface which uses the Selenium Java Robot tool.
 * For this implementation to be usable, the browser must have been started with the Selenium Java Robot tool, which is
 * available at the following address: https://github.com/ariatemplates/selenium-java-robot
 */
module.exports = Aria.classDefinition({
    $classpath : 'aria.jsunit.RobotJavaSelenium',
    $extends : require("./RobotJava"),
    $implements : [require("./IRobot")],
    $singleton : true,
    $constructor : function () {
        this.$RobotJava.constructor.call(this);

        this._robotInitialized = false;

        /**
         * Offset to add to the X coordinates.
         * @type Number
         */
        this.offsetX = 0;

        /**
         * Offset to add to the Y coordinates.
         * @type Number
         */
        this.offsetY = 0;

        if (Aria.$frameworkWindow.top.attester && Aria.$frameworkWindow.top.location !== Aria.$frameworkWindow.location) {
            // Aria.$frameworkWindow.top.location === Aria.$frameworkWindow.location means we are not running
            // in the attester iframe, so there is no need to apply the extra offset.
            // Otherwise, we are running in an iframe. Let's apply the offset:
            this.offsetY = 32; // height of the header in attester
        }

        // This is updated in _offsetRecevied
        this._offset = {
            x : NaN,
            y : NaN
        };
    },
    $events : {
        "robotInitialized" : "Raised when the robot initialization has been done."
    },
    $statics : {
        ROBOT_ERROR : "An error occurred in the robot: %1"
    },
    $prototype : {

        /**
         * Return true if the robot is most likely usable.
         */
        isUsable : function () {
            return !!Aria.$frameworkWindow.top.SeleniumJavaRobot;
        },

        /**
         * Initialize the robot, if not already done. This must be called before any other method on the robot.
         * @param {aria.core.CfgBeans:Callback} callback callback to be called when the robot is ready to be used.
         */
        initRobot : function (cb) {
            if (!this._robot) {
                this._robot = Aria.$frameworkWindow.top.SeleniumJavaRobot;
                this._robot.getOffset({
                    fn : this._offsetReceived,
                    scope : this
                });
            }
            if (cb) {
                if (this._robotInitialized) {
                    this.$callback(cb);
                } else {
                    this.$onOnce({
                        "robotInitialized" : cb
                    });
                }
            }
        },

        _getScreenPos : function () {
            var window = Aria.$frameworkWindow;
            return {
                x : window.screenX != null ? window.screenX : window.screenLeft,
                y : window.screenY != null ? window.screenY : window.screenTop
            };
        },

        _offsetReceived : function (response) {
            if (response.success) {
                var res = response.result;
                var screenPos = this._getScreenPos();
                // Removes the current position on the screen so that, if the window is moved,
                // adding later the new position on the screen will give the correct coordinates.
                this._offset.x = res.x - screenPos.x;
                this._offset.y = res.y - screenPos.y;
            } else {
                this.$logError(this.ROBOT_ERROR, [response.result]);
            }
            if (!this._robotInitialized) {
                this._robotInitialized = true;
                this.$raiseEvent("robotInitialized");
            }
        },

        _callCallback : function (response, cb) {
            if (!response.success) {
                this.$logError(this.ROBOT_ERROR, [response.result]);
            }
            this.$callback(cb);
        },

        viewportToAbsolute : function (position) {
            var screenPos = this._getScreenPos();
            var offset = this._offset;
            return {
                x : screenPos.x + offset.x + this.offsetX + position.x,
                y : screenPos.y + offset.y + this.offsetY + position.y
            };
        },

        absoluteMouseMove : function (position, cb) {
            this._robot.mouseMove(position.x, position.y, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        absoluteSmoothMouseMove : function (from, to, duration, cb) {
            this._robot.smoothMouseMove(from.x, from.y, to.x, to.y, duration, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseMove : function (position, cb) {
            var viewport = ariaUtilsDom._getViewportSize();
            if (position.x < 0 || position.y < 0 || position.x > viewport.width || position.y > viewport.height) {
                // FIXME: log error correctly
                this.$logWarn("MouseMove position outside of the viewport.");
                // return;
            }
            this.absoluteMouseMove(this.viewportToAbsolute(position), cb);
        },

        smoothMouseMove : function (from, to, duration, cb) {
            var viewport = ariaUtilsDom._getViewportSize();
            if (from.x < 0 || from.y < 0 || from.x > viewport.width || from.y > viewport.height || to.x < 0 || to.y < 0
                    || to.x > viewport.width || to.y > viewport.height) {
                // FIXME: log error correctly
                this.$logWarn("smoothMouseMove from or to position outside of the viewport.");
                // return;
            }
            this.absoluteSmoothMouseMove(this.viewportToAbsolute(from), this.viewportToAbsolute(to), duration, cb);
        },

        mousePress : function (buttons, cb) {
            this._robot.mousePress(buttons, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseRelease : function (buttons, cb) {
            this._robot.mouseRelease(buttons, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        mouseWheel : function (wheelAmt, cb) {
            this._robot.mouseWheel(wheelAmt, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        },

        keyPress : function (keyCode, cb) {
            // IE sometimes miss some keystrokes, that's why we are adding a 100 ms
            // delay before each keypress (which experimentally seems to help...)
            // http://answers.microsoft.com/en-us/ie/forum/ie8-windows_other/internet-explorer-missing-keystroke-problem/1bee2ec3-828c-4a3d-8b05-638e44baf0a8
            ariaCoreTimer.addCallback({
                fn : this._keyPress,
                scope : this,
                args : {
                    keyCode : keyCode,
                    cb : cb
                },
                delay : ariaCoreBrowser.isIE ? 100 : 1
            });
        },

        _keyPress : function (args) {
            this._robot.keyPress(args.keyCode, {
                scope : this,
                fn : this._callCallback,
                args : args.cb
            });
        },

        keyRelease : function (keycode, cb) {
            this._robot.keyRelease(keycode, {
                scope : this,
                fn : this._callCallback,
                args : cb
            });
        }
    }
});
<|endoftext|>