<commit_before>;(function(exports) {
  var Collider = function(coquette) {
    this.coquette = coquette;
  };

  // if no entities have uncollision(), skip expensive record keeping for uncollisions
  var isUncollisionOn = function(entities) {
    for (var i = 0, len = entities.length; i < len; i++) {
      if (entities[i].uncollision !== undefined) {
        return true;
      }
    }
    return false;
  };

  var isSetupForCollisions = function(obj) {
    return obj.center !== undefined && obj.size !== undefined;
  };

  Collider.prototype = {
    _collideRecords: [],

    update: function() {
      var ent = this.coquette.entities.all();
      for (var i = 0, len = ent.length; i < len; i++) {
        for (var j = i + 1; j < len; j++) {
          if (this.isColliding(ent[i], ent[j])) {
            this.collision(ent[i], ent[j]);
          } else {
            this.removeOldCollision(this.getCollideRecordIds(ent[i], ent[j])[0]);
          }
        }
      }
    },

    collision: function(entity1, entity2) {
      var collisionType;
      if (!isUncollisionOn(this.coquette.entities.all())) {
        collisionType = this.INITIAL;
      } else if (this.getCollideRecordIds(entity1, entity2).length === 0) {
        this._collideRecords.push([entity1, entity2]);
        collisionType = this.INITIAL;
      } else {
        collisionType = this.SUSTAINED;
      }

      notifyEntityOfCollision(entity1, entity2, collisionType);
      notifyEntityOfCollision(entity2, entity1, collisionType);
    },

    destroyEntity: function(entity) {
      var recordIds = this.getCollideRecordIds(entity);
      for (var i = 0; i < recordIds.length; i++) {
        this.removeOldCollision(recordIds[i]);
      }
    },

    // remove collision at passed index
    removeOldCollision: function(recordId) {
      var record = this._collideRecords[recordId];
      if (record !== undefined) {
        notifyEntityOfUncollision(record[0], record[1])
        notifyEntityOfUncollision(record[1], record[0])
        this._collideRecords.splice(recordId, 1);
      }
    },

    getCollideRecordIds: function(entity1, entity2) {
      if (entity1 !== undefined && entity2 !== undefined) {
        var recordIds = [];
        for (var i = 0, len = this._collideRecords.length; i < len; i++) {
          if (this._collideRecords[i][0] === entity1 &&
              this._collideRecords[i][1] === entity2) {
            recordIds.push(i);
          }
        }
        return recordIds;
      } else if (entity1 !== undefined) {
        for (var i = 0, len = this._collideRecords.length; i < len; i++) {
          if (this._collideRecords[i][0] === entity1 ||
              this._collideRecords[i][1] === entity1) {
            return [i];
          }
        }
        return [];
      } else {
        throw "You must pass at least one entity when searching collision records."
      }
    },

    isColliding: function(obj1, obj2) {
      return isSetupForCollisions(obj1) && isSetupForCollisions(obj2) &&
        this.isIntersecting(obj1, obj2);
    },

    isIntersecting: function(obj1, obj2) {
      var obj1BoundingBox = getBoundingBox(obj1);
      var obj2BoundingBox = getBoundingBox(obj2);

      if (obj1BoundingBox === this.RECTANGLE && obj2BoundingBox === this.RECTANGLE) {
        return Maths.rectanglesIntersecting(obj1, obj2);
      } else if (obj1BoundingBox === this.CIRCLE && obj2BoundingBox === this.RECTANGLE) {
        return Maths.circleAndRectangleIntersecting(obj1, obj2);
      } else if (obj1BoundingBox === this.RECTANGLE && obj2BoundingBox === this.CIRCLE) {
        return Maths.circleAndRectangleIntersecting(obj2, obj1);
      } else if (obj1BoundingBox === this.CIRCLE && obj2BoundingBox === this.CIRCLE) {
        return Maths.circlesIntersecting(obj1, obj2);
      } else {
        throw "Objects being collision tested have unsupported bounding box types."
      }
    },

    INITIAL: 0,
    SUSTAINED: 1,

    RECTANGLE: 0,
    CIRCLE: 1
  };

  var getBoundingBox = function(obj) {
    return obj.boundingBox || Collider.prototype.RECTANGLE;
  };

  var notifyEntityOfCollision = function(entity, other, type) {
    if (entity.collision !== undefined) {
      entity.collision(other, type);
    }
  };

  var notifyEntityOfUncollision = function(entity, other) {
    if (entity.uncollision !== undefined) {
      entity.uncollision(other);
    }
  };

  var rotated = function(obj) {
    return obj.angle !== undefined && obj.angle !== 0;
  };

  var getAngle = function(obj) {
    return obj.angle === undefined ? 0 : obj.angle;
  };

  var Maths = {
    circlesIntersecting: function(obj1, obj2) {
      return Maths.distance(obj1.center, obj2.center) <
        obj1.size.x / 2 + obj2.size.x / 2;
    },

    rectanglesIntersecting: function(obj1, obj2) {
      if (!rotated(obj1) && !rotated(obj2)) {
        return this.unrotatedRectanglesIntersecting(obj1, obj2); // faster
      } else {
        return this.rotatedRectanglesIntersecting(obj1, obj2); // slower
      }
    },

    circleAndRectangleIntersecting: function(circleObj, rectangleObj) {
      var rectangleObjAngleRad = -getAngle(rectangleObj) * Maths.RADIANS_TO_DEGREES;

      var unrotatedCircleCenter = {
        x: Math.cos(rectangleObjAngleRad) *
          (circleObj.center.x - rectangleObj.center.x) -
          Math.sin(rectangleObjAngleRad) *
          (circleObj.center.y - rectangleObj.center.y) + rectangleObj.center.x,
        y: Math.sin(rectangleObjAngleRad) *
          (circleObj.center.x - rectangleObj.center.x) +
          Math.cos(rectangleObjAngleRad) *
          (circleObj.center.y - rectangleObj.center.y) + rectangleObj.center.y
      };

      var closest = { x: 0, y: 0 };

      if (unrotatedCircleCenter.x < rectangleObj.center.x - rectangleObj.size.x / 2) {
        closest.x = rectangleObj.center.x - rectangleObj.size.x / 2;
      } else if (unrotatedCircleCenter.x > rectangleObj.center.x + rectangleObj.size.x / 2) {
        closest.x = rectangleObj.center.x + rectangleObj.size.x / 2;
      } else {
        closest.x = unrotatedCircleCenter.x;
      }

      if (unrotatedCircleCenter.y < rectangleObj.center.y - rectangleObj.size.y / 2) {
        closest.y = rectangleObj.center.y - rectangleObj.size.y / 2;
      } else if (unrotatedCircleCenter.y > rectangleObj.center.y + rectangleObj.size.y / 2) {
        closest.y = rectangleObj.center.y + rectangleObj.size.y / 2;
      } else {
        closest.y = unrotatedCircleCenter.y;
      }

      return this.distance(unrotatedCircleCenter, closest) < circleObj.size.x / 2;
    },

    unrotatedRectanglesIntersecting: function(obj1, obj2) {
      if(obj1.center.x + obj1.size.x / 2 < obj2.center.x - obj2.size.x / 2) {
        return false;
      } else if(obj1.center.x - obj1.size.x / 2 > obj2.center.x + obj2.size.x / 2) {
        return false;
      } else if(obj1.center.y - obj1.size.y / 2 > obj2.center.y + obj2.size.y / 2) {
        return false;
      } else if(obj1.center.y + obj1.size.y / 2 < obj2.center.y - obj2.size.y / 2) {
        return false
      } else {
        return true;
      }
    },

    rotatedRectanglesIntersecting: function(obj1, obj2) {
      var obj1Normals = this.sat.rectanglePerpendicularNormals(obj1);
      var obj2Normals = this.sat.rectanglePerpendicularNormals(obj2);

      var obj1Corners = this.sat.rectangleCorners(obj1);
      var obj2Corners = this.sat.rectangleCorners(obj2);

      if (this.sat.projectionsSeparate(
        this.sat.getMinMaxProjection(obj1Corners, obj1Normals[1]),
        this.sat.getMinMaxProjection(obj2Corners, obj1Normals[1]))) {
        return false;
      } else if (this.sat.projectionsSeparate(
        this.sat.getMinMaxProjection(obj1Corners, obj1Normals[0]),
        this.sat.getMinMaxProjection(obj2Corners, obj1Normals[0]))) {
        return false;
      } else if (this.sat.projectionsSeparate(
        this.sat.getMinMaxProjection(obj1Corners, obj2Normals[1]),
        this.sat.getMinMaxProjection(obj2Corners, obj2Normals[1]))) {
        return false;
      } else if (this.sat.projectionsSeparate(
        this.sat.getMinMaxProjection(obj1Corners, obj2Normals[0]),
        this.sat.getMinMaxProjection(obj2Corners, obj2Normals[0]))) {
        return false;
      } else {
        return true;
      }
    },

    pointInsideObj: function(point, obj) {
      var objBoundingBox = getBoundingBox(obj);

      if (objBoundingBox === Collider.prototype.RECTANGLE) {
        return this.pointInsideRectangle(point, obj);
      } else if (objBoundingBox === Collider.prototype.CIRCLE) {
        return this.pointInsideCircle(point, obj);
      } else {
        throw "Tried to see if point inside object with unsupported bounding box.";
      }
    },

    pointInsideRectangle: function(point, obj) {
      var c = Math.cos(-getAngle(obj) * Maths.RADIANS_TO_DEGREES);
      var s = Math.sin(-getAngle(obj) * Maths.RADIANS_TO_DEGREES);

      var rotatedX = obj.center.x + c *
          (point.x - obj.center.x) - s * (point.y - obj.center.y);
      var rotatedY = obj.center.y + s *
          (point.x - obj.center.x) + c * (point.y - obj.center.y);

      var leftX = obj.center.x - obj.size.x / 2;
      var rightX = obj.center.x + obj.size.x / 2;
      var topY = obj.center.y - obj.size.y / 2;
      var bottomY = obj.center.y + obj.size.y / 2;

      return leftX <= rotatedX && rotatedX <= rightX &&
        topY <= rotatedY && rotatedY <= bottomY;
    };

    pointInsideCircle: function() {

    },

    distance: function(point1, point2) {
      var x = point1.x - point2.x;
      var y = point1.y - point2.y;
      return Math.sqrt((x * x) + (y * y));
    },

    vectorTo: function(start, end) {
      return {
        x: end.x - start.x,
        y: end.y - start.y
      };
    },

    magnitude: function(vector) {
      return Math.sqrt(vector.x * vector.x + vector.y * vector.y);
    },

    leftNormalizedNormal: function(vector) {
      return {
        x: -vector.y,
        y: vector.x
      };
    },

    dotProduct: function(vector1, vector2) {
      return vector1.x * vector2.x + vector1.y * vector2.y;
    },

    unitVector: function(vector) {
      return {
        x: vector.x / Maths.magnitude(vector),
        y: vector.y / Maths.magnitude(vector)
      };
    },

    sat: {
      projectionsSeparate: function(proj1, proj2) {
        return proj1.max < proj2.min || proj2.max < proj1.min;
      },

      getMinMaxProjection: function(objCorners, normal) {
        var min = Maths.dotProduct(objCorners[0], normal);
        var max = Maths.dotProduct(objCorners[0], normal);

        for (var i = 1; i < objCorners.length; i++) {
          var current = Maths.dotProduct(objCorners[i], normal);
          if (min > current) {
            min = current;
          }

          if (current > max) {
            max = current;
          }
        }

        return { min: min, max: max };
      },

      rectangleCorners: function(obj) {
        var corners = [ // unrotated
          { x:obj.center.x - obj.size.x / 2, y: obj.center.y - obj.size.y / 2 },
          { x:obj.center.x + obj.size.x / 2, y: obj.center.y - obj.size.y / 2 },
          { x:obj.center.x + obj.size.x / 2, y: obj.center.y + obj.size.y / 2 },
          { x:obj.center.x - obj.size.x / 2, y: obj.center.y + obj.size.y / 2 }
        ];

        var angle = (obj.angle === undefined ? 0 : obj.angle) *
          Maths.RADIAN_TO_DEGREES;

			  for (var i = 0; i < corners.length; i++) {
				  var xOffset = corners[i].x - obj.center.x;
				  var yOffset = corners[i].y - obj.center.y;
				  corners[i].x = obj.center.x +
            xOffset * Math.cos(angle) - yOffset * Math.sin(angle);
				  corners[i].y = obj.center.y +
            xOffset * Math.sin(angle) + yOffset * Math.cos(angle);
			  }

        return corners;
      },

      rectangleSideVectors: function(obj) {
        var corners = this.rectangleCorners(obj);
        return [
          { x: corners[0].x - corners[1].x, y: corners[0].y - corners[1].y },
          { x: corners[1].x - corners[2].x, y: corners[1].y - corners[2].y },
          { x: corners[2].x - corners[3].x, y: corners[2].y - corners[3].y },
          { x: corners[3].x - corners[0].x, y: corners[3].y - corners[0].y }
        ];
      },

      rectanglePerpendicularNormals: function(obj) {
        var sides = this.rectangleSideVectors(obj);
        return [
          Maths.leftNormalizedNormal(sides[0]),
          Maths.leftNormalizedNormal(sides[1])
        ];
      }
    },

    RADIAN_TO_DEGREES: 0.01745
  };

  exports.Collider = Collider;
  exports.Collider.Maths = Maths;
})(typeof exports === 'undefined' ? this.Coquette : exports);
<commit_msg>Add Collider.pointInsideCircle()<commit_after>;(function(exports) {
  var Collider = function(coquette) {
    this.coquette = coquette;
  };

  // if no entities have uncollision(), skip expensive record keeping for uncollisions
  var isUncollisionOn = function(entities) {
    for (var i = 0, len = entities.length; i < len; i++) {
      if (entities[i].uncollision !== undefined) {
        return true;
      }
    }
    return false;
  };

  var isSetupForCollisions = function(obj) {
    return obj.center !== undefined && obj.size !== undefined;
  };

  Collider.prototype = {
    _collideRecords: [],

    update: function() {
      var ent = this.coquette.entities.all();
      for (var i = 0, len = ent.length; i < len; i++) {
        for (var j = i + 1; j < len; j++) {
          if (this.isColliding(ent[i], ent[j])) {
            this.collision(ent[i], ent[j]);
          } else {
            this.removeOldCollision(this.getCollideRecordIds(ent[i], ent[j])[0]);
          }
        }
      }
    },

    collision: function(entity1, entity2) {
      var collisionType;
      if (!isUncollisionOn(this.coquette.entities.all())) {
        collisionType = this.INITIAL;
      } else if (this.getCollideRecordIds(entity1, entity2).length === 0) {
        this._collideRecords.push([entity1, entity2]);
        collisionType = this.INITIAL;
      } else {
        collisionType = this.SUSTAINED;
      }

      notifyEntityOfCollision(entity1, entity2, collisionType);
      notifyEntityOfCollision(entity2, entity1, collisionType);
    },

    destroyEntity: function(entity) {
      var recordIds = this.getCollideRecordIds(entity);
      for (var i = 0; i < recordIds.length; i++) {
        this.removeOldCollision(recordIds[i]);
      }
    },

    // remove collision at passed index
    removeOldCollision: function(recordId) {
      var record = this._collideRecords[recordId];
      if (record !== undefined) {
        notifyEntityOfUncollision(record[0], record[1])
        notifyEntityOfUncollision(record[1], record[0])
        this._collideRecords.splice(recordId, 1);
      }
    },

    getCollideRecordIds: function(entity1, entity2) {
      if (entity1 !== undefined && entity2 !== undefined) {
        var recordIds = [];
        for (var i = 0, len = this._collideRecords.length; i < len; i++) {
          if (this._collideRecords[i][0] === entity1 &&
              this._collideRecords[i][1] === entity2) {
            recordIds.push(i);
          }
        }
        return recordIds;
      } else if (entity1 !== undefined) {
        for (var i = 0, len = this._collideRecords.length; i < len; i++) {
          if (this._collideRecords[i][0] === entity1 ||
              this._collideRecords[i][1] === entity1) {
            return [i];
          }
        }
        return [];
      } else {
        throw "You must pass at least one entity when searching collision records."
      }
    },

    isColliding: function(obj1, obj2) {
      return isSetupForCollisions(obj1) && isSetupForCollisions(obj2) &&
        this.isIntersecting(obj1, obj2);
    },

    isIntersecting: function(obj1, obj2) {
      var obj1BoundingBox = getBoundingBox(obj1);
      var obj2BoundingBox = getBoundingBox(obj2);

      if (obj1BoundingBox === this.RECTANGLE && obj2BoundingBox === this.RECTANGLE) {
        return Maths.rectanglesIntersecting(obj1, obj2);
      } else if (obj1BoundingBox === this.CIRCLE && obj2BoundingBox === this.RECTANGLE) {
        return Maths.circleAndRectangleIntersecting(obj1, obj2);
      } else if (obj1BoundingBox === this.RECTANGLE && obj2BoundingBox === this.CIRCLE) {
        return Maths.circleAndRectangleIntersecting(obj2, obj1);
      } else if (obj1BoundingBox === this.CIRCLE && obj2BoundingBox === this.CIRCLE) {
        return Maths.circlesIntersecting(obj1, obj2);
      } else {
        throw "Objects being collision tested have unsupported bounding box types."
      }
    },

    INITIAL: 0,
    SUSTAINED: 1,

    RECTANGLE: 0,
    CIRCLE: 1
  };

  var getBoundingBox = function(obj) {
    return obj.boundingBox || Collider.prototype.RECTANGLE;
  };

  var notifyEntityOfCollision = function(entity, other, type) {
    if (entity.collision !== undefined) {
      entity.collision(other, type);
    }
  };

  var notifyEntityOfUncollision = function(entity, other) {
    if (entity.uncollision !== undefined) {
      entity.uncollision(other);
    }
  };

  var rotated = function(obj) {
    return obj.angle !== undefined && obj.angle !== 0;
  };

  var getAngle = function(obj) {
    return obj.angle === undefined ? 0 : obj.angle;
  };

  var Maths = {
    circlesIntersecting: function(obj1, obj2) {
      return Maths.distance(obj1.center, obj2.center) <
        obj1.size.x / 2 + obj2.size.x / 2;
    },

    rectanglesIntersecting: function(obj1, obj2) {
      if (!rotated(obj1) && !rotated(obj2)) {
        return this.unrotatedRectanglesIntersecting(obj1, obj2); // faster
      } else {
        return this.rotatedRectanglesIntersecting(obj1, obj2); // slower
      }
    },

    circleAndRectangleIntersecting: function(circleObj, rectangleObj) {
      var rectangleObjAngleRad = -getAngle(rectangleObj) * Maths.RADIANS_TO_DEGREES;

      var unrotatedCircleCenter = {
        x: Math.cos(rectangleObjAngleRad) *
          (circleObj.center.x - rectangleObj.center.x) -
          Math.sin(rectangleObjAngleRad) *
          (circleObj.center.y - rectangleObj.center.y) + rectangleObj.center.x,
        y: Math.sin(rectangleObjAngleRad) *
          (circleObj.center.x - rectangleObj.center.x) +
          Math.cos(rectangleObjAngleRad) *
          (circleObj.center.y - rectangleObj.center.y) + rectangleObj.center.y
      };

      var closest = { x: 0, y: 0 };

      if (unrotatedCircleCenter.x < rectangleObj.center.x - rectangleObj.size.x / 2) {
        closest.x = rectangleObj.center.x - rectangleObj.size.x / 2;
      } else if (unrotatedCircleCenter.x > rectangleObj.center.x + rectangleObj.size.x / 2) {
        closest.x = rectangleObj.center.x + rectangleObj.size.x / 2;
      } else {
        closest.x = unrotatedCircleCenter.x;
      }

      if (unrotatedCircleCenter.y < rectangleObj.center.y - rectangleObj.size.y / 2) {
        closest.y = rectangleObj.center.y - rectangleObj.size.y / 2;
      } else if (unrotatedCircleCenter.y > rectangleObj.center.y + rectangleObj.size.y / 2) {
        closest.y = rectangleObj.center.y + rectangleObj.size.y / 2;
      } else {
        closest.y = unrotatedCircleCenter.y;
      }

      return this.distance(unrotatedCircleCenter, closest) < circleObj.size.x / 2;
    },

    unrotatedRectanglesIntersecting: function(obj1, obj2) {
      if(obj1.center.x + obj1.size.x / 2 < obj2.center.x - obj2.size.x / 2) {
        return false;
      } else if(obj1.center.x - obj1.size.x / 2 > obj2.center.x + obj2.size.x / 2) {
        return false;
      } else if(obj1.center.y - obj1.size.y / 2 > obj2.center.y + obj2.size.y / 2) {
        return false;
      } else if(obj1.center.y + obj1.size.y / 2 < obj2.center.y - obj2.size.y / 2) {
        return false
      } else {
        return true;
      }
    },

    rotatedRectanglesIntersecting: function(obj1, obj2) {
      var obj1Normals = this.sat.rectanglePerpendicularNormals(obj1);
      var obj2Normals = this.sat.rectanglePerpendicularNormals(obj2);

      var obj1Corners = this.sat.rectangleCorners(obj1);
      var obj2Corners = this.sat.rectangleCorners(obj2);

      if (this.sat.projectionsSeparate(
        this.sat.getMinMaxProjection(obj1Corners, obj1Normals[1]),
        this.sat.getMinMaxProjection(obj2Corners, obj1Normals[1]))) {
        return false;
      } else if (this.sat.projectionsSeparate(
        this.sat.getMinMaxProjection(obj1Corners, obj1Normals[0]),
        this.sat.getMinMaxProjection(obj2Corners, obj1Normals[0]))) {
        return false;
      } else if (this.sat.projectionsSeparate(
        this.sat.getMinMaxProjection(obj1Corners, obj2Normals[1]),
        this.sat.getMinMaxProjection(obj2Corners, obj2Normals[1]))) {
        return false;
      } else if (this.sat.projectionsSeparate(
        this.sat.getMinMaxProjection(obj1Corners, obj2Normals[0]),
        this.sat.getMinMaxProjection(obj2Corners, obj2Normals[0]))) {
        return false;
      } else {
        return true;
      }
    },

    pointInsideObj: function(point, obj) {
      var objBoundingBox = getBoundingBox(obj);

      if (objBoundingBox === Collider.prototype.RECTANGLE) {
        return this.pointInsideRectangle(point, obj);
      } else if (objBoundingBox === Collider.prototype.CIRCLE) {
        return this.pointInsideCircle(point, obj);
      } else {
        throw "Tried to see if point inside object with unsupported bounding box.";
      }
    },

    pointInsideRectangle: function(point, obj) {
      var c = Math.cos(-getAngle(obj) * Maths.RADIANS_TO_DEGREES);
      var s = Math.sin(-getAngle(obj) * Maths.RADIANS_TO_DEGREES);

      var rotatedX = obj.center.x + c *
          (point.x - obj.center.x) - s * (point.y - obj.center.y);
      var rotatedY = obj.center.y + s *
          (point.x - obj.center.x) + c * (point.y - obj.center.y);

      var leftX = obj.center.x - obj.size.x / 2;
      var rightX = obj.center.x + obj.size.x / 2;
      var topY = obj.center.y - obj.size.y / 2;
      var bottomY = obj.center.y + obj.size.y / 2;

      return leftX <= rotatedX && rotatedX <= rightX &&
        topY <= rotatedY && rotatedY <= bottomY;
    };

    },

    pointInsideCircle: function(point, obj) {
      return this.distance(point, obj.center) <= obj.size.x / 2;
    },

    distance: function(point1, point2) {
      var x = point1.x - point2.x;
      var y = point1.y - point2.y;
      return Math.sqrt((x * x) + (y * y));
    },

    vectorTo: function(start, end) {
      return {
        x: end.x - start.x,
        y: end.y - start.y
      };
    },

    magnitude: function(vector) {
      return Math.sqrt(vector.x * vector.x + vector.y * vector.y);
    },

    leftNormalizedNormal: function(vector) {
      return {
        x: -vector.y,
        y: vector.x
      };
    },

    dotProduct: function(vector1, vector2) {
      return vector1.x * vector2.x + vector1.y * vector2.y;
    },

    unitVector: function(vector) {
      return {
        x: vector.x / Maths.magnitude(vector),
        y: vector.y / Maths.magnitude(vector)
      };
    },

    sat: {
      projectionsSeparate: function(proj1, proj2) {
        return proj1.max < proj2.min || proj2.max < proj1.min;
      },

      getMinMaxProjection: function(objCorners, normal) {
        var min = Maths.dotProduct(objCorners[0], normal);
        var max = Maths.dotProduct(objCorners[0], normal);

        for (var i = 1; i < objCorners.length; i++) {
          var current = Maths.dotProduct(objCorners[i], normal);
          if (min > current) {
            min = current;
          }

          if (current > max) {
            max = current;
          }
        }

        return { min: min, max: max };
      },

      rectangleCorners: function(obj) {
        var corners = [ // unrotated
          { x:obj.center.x - obj.size.x / 2, y: obj.center.y - obj.size.y / 2 },
          { x:obj.center.x + obj.size.x / 2, y: obj.center.y - obj.size.y / 2 },
          { x:obj.center.x + obj.size.x / 2, y: obj.center.y + obj.size.y / 2 },
          { x:obj.center.x - obj.size.x / 2, y: obj.center.y + obj.size.y / 2 }
        ];

        var angle = (obj.angle === undefined ? 0 : obj.angle) *
          Maths.RADIAN_TO_DEGREES;

			  for (var i = 0; i < corners.length; i++) {
				  var xOffset = corners[i].x - obj.center.x;
				  var yOffset = corners[i].y - obj.center.y;
				  corners[i].x = obj.center.x +
            xOffset * Math.cos(angle) - yOffset * Math.sin(angle);
				  corners[i].y = obj.center.y +
            xOffset * Math.sin(angle) + yOffset * Math.cos(angle);
			  }

        return corners;
      },

      rectangleSideVectors: function(obj) {
        var corners = this.rectangleCorners(obj);
        return [
          { x: corners[0].x - corners[1].x, y: corners[0].y - corners[1].y },
          { x: corners[1].x - corners[2].x, y: corners[1].y - corners[2].y },
          { x: corners[2].x - corners[3].x, y: corners[2].y - corners[3].y },
          { x: corners[3].x - corners[0].x, y: corners[3].y - corners[0].y }
        ];
      },

      rectanglePerpendicularNormals: function(obj) {
        var sides = this.rectangleSideVectors(obj);
        return [
          Maths.leftNormalizedNormal(sides[0]),
          Maths.leftNormalizedNormal(sides[1])
        ];
      }
    },

    RADIAN_TO_DEGREES: 0.01745
  };

  exports.Collider = Collider;
  exports.Collider.Maths = Maths;
})(typeof exports === 'undefined' ? this.Coquette : exports);
<|endoftext|>


<commit_before>var assert = require("assert");
var path = require("path");
var local = path.join.bind(path, __dirname);
var Promise = require("nodegit-promise");
var promisify = require("promisify-node");
var fse = promisify(require("fs-extra"));

describe("Index", function() {
  var Repository = require(local("../../lib/repository"));

  var reposPath = local("../repos/workdir/.git");

  before(function() {
    var test = this;

    return Repository.open(reposPath)
      .then(function(repo) {
        test.repo = repo;
        return repo.openIndex();
      })
      .then(function(index) {
        test.index = index;
      });
  });

  after(function() {
    this.index.clear();
  });

  it("can get the index of a repo and examine entries", function() {
    var entries = this.index.entries();

    assert.equal(entries[0].path(), ".gitignore");
  });

  it("can add all entries to the index", function() {
    var repo = this.repo;
    var index = this.index;
    var fileContent = {
      newFile1: "this has some content",
      newFile2: "and this will have more content"
    };
    var fileNames = Object.keys(fileContent);

    return Promise.all(fileNames.map(function(fileName) {
      return fse.writeFile(path.join(repo.workdir(), fileName), fileContent[fileName]);
    }))
    .then(function() {
      return index.addAll();
    })
    .then(function() {
      var newFiles = index.entries().filter(function(entry) {
        return ~fileNames.indexOf(entry.path());
      });

      assert.equal(newFiles.length, 2);
    })
    .then(function() {
      return Promise.all(fileNames.map(function(fileName) {
        return fse.remove(path.join(repo.workdir(), fileName));
      }));
    })
    .then(function() {
      index.clear();
    });
  });

  it("can remove entries from the index", function() {
    var repo = this.repo;
    var index = this.index;
    var fileContent = {
      newFile1: "this has some content",
      newFile2: "and this will have more content",
      differentFileName: "this has a different name and shouldn't be deleted"
    };
    var fileNames = Object.keys(fileContent);

    return Promise.all(fileNames.map(function(fileName) {
      return fse.writeFile(path.join(repo.workdir(), fileName), fileContent[fileName]);
    }))
    .then(function() {
      return index.addAll();
    })
    .then(function() {
      var newFiles = index.entries().filter(function(entry) {
        return ~fileNames.indexOf(entry.path());
      });

      assert.equal(newFiles.length, 3);

      return index.removeAll("newFile*");
    })
    .then(function() {
      var newFiles = index.entries().filter(function(entry) {
        return ~fileNames.indexOf(entry.path());
      });

      assert.equal(newFiles.length, 1);
    })
    .then(function() {
      return Promise.all(fileNames.map(function(fileName) {
        return fse.remove(path.join(repo.workdir(), fileName));
      }));
    })
    .then(function() {
      index.clear();
    });
  });

  it("can update entries in the index", function() {
    var repo = this.repo;
    var index = this.index;
    var fileContent = {
      newFile1: "this has some content",
      newFile2: "and this will have more content"
    };
    var fileNames = Object.keys(fileContent);

    return Promise.all(fileNames.map(function(fileName) {
      return fse.writeFile(path.join(repo.workdir(), fileName), fileContent[fileName]);
    }))
    .then(function() {
      return index.addAll();
    })
    .then(function() {
      var newFiles = index.entries().filter(function(entry) {
        return ~fileNames.indexOf(entry.path());
      });

      assert.equal(newFiles.length, 2);

      return fse.remove(path.join(repo.workdir(), fileNames[0]));
    })
    .then(function() {
      return index.updateAll("newFile*");
    })
    .then(function() {
      var newFiles = index.entries().filter(function(entry) {
        return ~fileNames.indexOf(entry.path());
      });

      assert.equal(newFiles.length, 1);
      return fse.remove(path.join(repo.workdir(), fileNames[1]));
    });
  });
});
<commit_msg>Promisify writeFile by hand in index tests<commit_after>var assert = require("assert");
var path = require("path");
var local = path.join.bind(path, __dirname);
var Promise = require("nodegit-promise");
var promisify = require("promisify-node");
var fse = promisify(require("fs-extra"));

var writeFile = promisify(function(filename, data, callback) {
  return require("fs").writeFile(filename, data, {}, callback);
});

describe("Index", function() {
  var Repository = require(local("../../lib/repository"));

  var reposPath = local("../repos/workdir/.git");

  before(function() {
    var test = this;

    return Repository.open(reposPath)
      .then(function(repo) {
        test.repo = repo;
        return repo.openIndex();
      })
      .then(function(index) {
        test.index = index;
      });
  });

  after(function() {
    this.index.clear();
  });

  it("can get the index of a repo and examine entries", function() {
    var entries = this.index.entries();

    assert.equal(entries[0].path(), ".gitignore");
  });

  it("can add all entries to the index", function() {
    var repo = this.repo;
    var index = this.index;
    var fileContent = {
      newFile1: "this has some content",
      newFile2: "and this will have more content"
    };
    var fileNames = Object.keys(fileContent);

    return Promise.all(fileNames.map(function(fileName) {
      return writeFile(path.join(repo.workdir(), fileName), fileContent[fileName]);
    }))
    .then(function() {
      return index.addAll();
    })
    .then(function() {
      var newFiles = index.entries().filter(function(entry) {
        return ~fileNames.indexOf(entry.path());
      });

      assert.equal(newFiles.length, 2);
    })
    .then(function() {
      return Promise.all(fileNames.map(function(fileName) {
        return fse.remove(path.join(repo.workdir(), fileName));
      }));
    })
    .then(function() {
      index.clear();
    });
  });

  it("can remove entries from the index", function() {
    var repo = this.repo;
    var index = this.index;
    var fileContent = {
      newFile1: "this has some content",
      newFile2: "and this will have more content",
      differentFileName: "this has a different name and shouldn't be deleted"
    };
    var fileNames = Object.keys(fileContent);

    return Promise.all(fileNames.map(function(fileName) {
      return writeFile(path.join(repo.workdir(), fileName), fileContent[fileName]);
    }))
    .then(function() {
      return index.addAll();
    })
    .then(function() {
      var newFiles = index.entries().filter(function(entry) {
        return ~fileNames.indexOf(entry.path());
      });

      assert.equal(newFiles.length, 3);

      return index.removeAll("newFile*");
    })
    .then(function() {
      var newFiles = index.entries().filter(function(entry) {
        return ~fileNames.indexOf(entry.path());
      });

      assert.equal(newFiles.length, 1);
    })
    .then(function() {
      return Promise.all(fileNames.map(function(fileName) {
        return fse.remove(path.join(repo.workdir(), fileName));
      }));
    })
    .then(function() {
      index.clear();
    });
  });

  it("can update entries in the index", function() {
    var repo = this.repo;
    var index = this.index;
    var fileContent = {
      newFile1: "this has some content",
      newFile2: "and this will have more content"
    };
    var fileNames = Object.keys(fileContent);

    return Promise.all(fileNames.map(function(fileName) {
      return writeFile(path.join(repo.workdir(), fileName), fileContent[fileName]);
    }))
    .then(function() {
      return index.addAll();
    })
    .then(function() {
      var newFiles = index.entries().filter(function(entry) {
        return ~fileNames.indexOf(entry.path());
      });

      assert.equal(newFiles.length, 2);

      return fse.remove(path.join(repo.workdir(), fileNames[0]));
    })
    .then(function() {
      return index.updateAll("newFile*");
    })
    .then(function() {
      var newFiles = index.entries().filter(function(entry) {
        return ~fileNames.indexOf(entry.path());
      });

      assert.equal(newFiles.length, 1);
      return fse.remove(path.join(repo.workdir(), fileNames[1]));
    });
  });
});
<|endoftext|>


<commit_before>/* global require, module */

var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var env = EmberApp.env();
var isProductionLikeBuild = ['production', 'staging'].indexOf(env) > -1;
var prepend = null;

if(isProductionLikeBuild) {
  prepend = env==='production' ? '//assets.ember-twiddle.com' : '//staging-assets.ember-twiddle.com';
}

var app = new EmberApp({
  fingerprint: {
    enabled: isProductionLikeBuild,
    prepend: prepend
  },
  codemirror: {
    modes: ['xml', 'javascript', 'htmlmixed'],
  },
  'ember-cli-bootstrap-sassy': {
    'js': ['dropdown']
  }
});

// Use `app.import` to add additional libraries to the generated
// output files.
app.import('bower_components/ember/ember-template-compiler.js');

// If you need to use different assets in different
// environments, specify an object as the first parameter. That
// object's keys should be the environment name and the values
// should be the asset to use in that environment.
//
// If the library that you are including contains AMD or ES6
// modules that you would like to import into your application
// please specify an object with the list of modules as keys
// along with the exports of each module as its value.

module.exports = app.toTree();
<commit_msg>Use correct urls<commit_after>/* global require, module */

var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var env = EmberApp.env();
var isProductionLikeBuild = ['production', 'staging'].indexOf(env) > -1;
var prepend = null;

if(isProductionLikeBuild) {
  prepend = env==='production' ? '//assets.ember-twiddle.com/' : '//staging-assets.ember-twiddle.com/';
}

var app = new EmberApp({
  fingerprint: {
    enabled: isProductionLikeBuild,
    prepend: prepend
  },
  codemirror: {
    modes: ['xml', 'javascript', 'htmlmixed'],
  },
  'ember-cli-bootstrap-sassy': {
    'js': ['dropdown']
  }
});

// Use `app.import` to add additional libraries to the generated
// output files.
app.import('bower_components/ember/ember-template-compiler.js');

// If you need to use different assets in different
// environments, specify an object as the first parameter. That
// object's keys should be the environment name and the values
// should be the asset to use in that environment.
//
// If the library that you are including contains AMD or ES6
// modules that you would like to import into your application
// please specify an object with the list of modules as keys
// along with the exports of each module as its value.

module.exports = app.toTree();
<|endoftext|>


<commit_before>module.exports = [
  "!bling",
  "!airhorn",
  "!joeputa",
  "!fgilipollas",
  "!laloli",
  "!salchichonio",
  "!subnormal",
  "!janso",
  "!yaves",
  "!elagua",
  "!augale",
  "!duah",
  "!mishon",
  "!goodjob",
  "!notcool",
  "!showme",
  "!pitorro",
  "!rekt",
  "!omaewa",
  "!jeff",
  "!okay",
  "!wry",
  "!ezmoney",
  "!rapper",
  "!nanimo",
  "!noesbien",
  "!fornai",
  "!puesyose",
  "!incredibilis",
  "!unaceptable",
  "!baka",
  "!nohayclase",
  "!uitheme",
  "!yourway",
  "!complete",
  "!sacala",
  "!lablanca",
  "!porquesacala",
  "!quemando",
  "!yosha",
  "!wide",
  "!nonono",
  "!yoo",
  "!desgraciatis",
  "!mmm",
  "!mipan",
  "!martes",
  "!miercoles",
  "!jueves",
  "!viernes",
  "!marica",
  "!mikoboat",
  "!nigga",
  "!eekumbokum",
  "!xana"
]
<commit_msg>son las 4 am y no sé darle a guardar archivo<commit_after>module.exports = [
  "!bling",
  "!airhorn",
  "!joeputa",
  "!fgilipollas",
  "!laloli",
  "!salchichonio",
  "!subnormal",
  "!janso",
  "!yaves",
  "!elagua",
  "!augale",
  "!duah",
  "!mishon",
  "!goodjob",
  "!notcool",
  "!showme",
  "!pitorro",
  "!rekt",
  "!omaewa",
  "!jeff",
  "!okay",
  "!wry",
  "!ezmoney",
  "!rapper",
  "!nanimo",
  "!noesbien",
  "!fornai",
  "!puesyose",
  "!incredibilis",
  "!unaceptable",
  "!baka",
  "!nohayclase",
  "!uitheme",
  "!yourway",
  "!complete",
  "!sacala",
  "!lablanca",
  "!porquesacala",
  "!quemando",
  "!yosha",
  "!wide",
  "!nonono",
  "!yoo",
  "!desgraciatis",
  "!mmm",
  "!mipan",
  "!martes",
  "!miercoles",
  "!jueves",
  "!viernes",
  "!marica",
  "!mikoboat",
  "!nigga",
  "!eekumbokum",
  "!xana",
  "!odd"
]
<|endoftext|>


<commit_before>var assert = require("assert");
var path = require("path");
var Promise = require("nodegit-promise");
var promisify = require("promisify-node");
var fse = promisify(require("fs-extra"));

describe("Stage", function() {
  var RepoUtils = require("../utils/repository_setup");
  var NodeGit = require("../../");
	var test;

  beforeEach(function() {
    test = this;
		var repoDir = "../repos/stagingRepo/";
    var repoPath = path.resolve(__dirname, repoDir);

    return RepoUtils.createRepository(repoPath)
      .then(function(repo) {
        test.repository = repo;
        return repo.openIndex();
      })
      .then(function(index) {
        test.index = index;
      });
  });

  after(function() {
		return fse.remove(test.repository.workdir());
  });

function stagingTest(staging, newFileContent) {
    var fileContent = newFileContent ||
                      "One line of text\n" +
                      "Two lines of text\n"+
                      "Three lines of text\n"+
                      "Four lines of text\n"+
                      "Five lines of text\n"+
                      "Six lines of text\n"+
                      "Seven lines of text\n"+
                      "Eight lines of text\n"+
                      "Nine lines of text\n"+
                      "Ten lines of text\n"+
                      "Eleven lines of text\n"+
                      "Twelve lines of text\n"+
                      "Thirteen lines of text\n"+
                      "Fourteen lines of text\n"+
                      "Fifteen lines of text\n"+
                      "Sixteen lines of text\n"+
                      "Seventeen lines of text\n"+
                      "Eighteen lines of text\n"+
                      "Nineteen lines of text\n"+
                      "Twenty lines of text\n";
    var fileName = "stagedLinesTest.txt";
    var index;
    var stagedFile;
    var workingDirFile;
    var getDiffFunction;
    if (staging) {
      stagedFile = fileContent.replace("Fifteen", "Changed fifteen");
      workingDirFile = stagedFile.replace("Three", "Changed three")
                            .replace("Seventeen", "Changed seventeen");
      getDiffFunction = function() {
        return NodeGit.Diff.indexToWorkdir(test.repository, index, {
            flags:
              NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
              NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
          });
      };
    }
    else {
      stagedFile = fileContent.replace("Three", "Changed three")
                            .replace("Seventeen", "Changed seventeen");
      workingDirFile = stagedFile.replace("Fifteen", "Changed fifteen");

      getDiffFunction = function() {
        return RepoUtils.addFileToIndex(test.repository, fileName)
          .then(function() {
            return test.repository.getBranchCommit("master");
          })
          .then(function(masterCommit) {
            return masterCommit.getTree();
          })
          .then(function(masterTree) {
            return NodeGit.Diff.treeToIndex(
              test.repository, masterTree, index, {
              flags:
                NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
                NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
            });
          });
      };
    }

    return RepoUtils.commitFileToRepo(test.repository, fileName, fileContent)
    .then(function() {
      return fse.writeFile(path.join(test.repository.workdir(), fileName),
                            workingDirFile);
    })
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return getDiffFunction();
    })
    .then(function(fileDiff) {
      return fileDiff.patches();
    })
    .then(function(patches) {
      var pathPatch = patches.filter(function(patch) {
        return patch.newFile().path() === fileName;
      });
      return pathPatch[0].hunks();
    })
    .then(function(pathHunks) {
      var linePromises = [];

      pathHunks.forEach(function(pathHunk) {
        linePromises.push(pathHunk.lines());
      });

      return Promise.all(linePromises);
    })
    .then(function(lines) {
      var linesToStage = [];
      lines.forEach(function(hunkLines) {
        hunkLines.forEach(function(line) {
          if (line.content().toLowerCase().indexOf("fifteen") >= 0){
            linesToStage.push(line);
          }
        });
      });
      return test.repository.stageLines(fileName, linesToStage, !staging);
    })
    .then(function(stageResult) {
      assert.equal(stageResult, 0);
      var pathOid = index.getByPath(fileName).id;
      return test.repository.getBlob(pathOid);
    })
    .then(function(resultFileContents) {
      assert.equal(resultFileContents.toString(), stagedFile);
    });
  }

  it("can stage selected lines", function() {
    return stagingTest(true);
  });
  it("can unstage selected lines", function() {
    return stagingTest(false);
  });

  //This is used to test cases where there are no newline at EOF
  var newlineEofTestFileContent =
                  "One line of text\n" +
                  "Two lines of text\n"+
                  "Three lines of text\n"+
                  "Four lines of text\n"+
                  "Five lines of text\n"+
                  "Six lines of text\n"+
                  "Seven lines of text\n"+
                  "Eight lines of text\n"+
                  "Nine lines of text\n"+
                  "Ten lines of text\n"+
                  "Eleven lines of text\n"+
                  "Twelve lines of text\n"+
                  "Thirteen lines of text\n"+
                  "Fourteen lines of text\n"+
                  "Fifteen lines of text";
  it("can stage last line with no newline at EOF", function() {
    return stagingTest(true, newlineEofTestFileContent);
  });
  it("can unstage last line with no newline at EOF", function() {
    return stagingTest(false, newlineEofTestFileContent);
  });
  it("can stage second to last line with no newline at EOF", function() {
    var newlineEofTestFileContent2 = newlineEofTestFileContent +
     "\nSixteen lines of text\nSeventeen lines of text\nEighteen lines of text";
    return stagingTest(true, newlineEofTestFileContent2);
  });
  it("can unstage second to last line with no newline at EOF", function() {
    var newlineEofTestFileContent2 = newlineEofTestFileContent +
     "\nSixteen lines of text\nSeventeen lines of text\nEighteen lines of text";
    return stagingTest(false, newlineEofTestFileContent2);
  });

  //This is used to test case where the last hunk is staged.
  var lastHunkStagedFileContent =
                "Thirteen lines of text\n"+
                "Fourteen lines of text\n"+
                "Fifteen lines of text\n"+
                "Sixteen lines of text\n"+
                "Shforteenteen lines of text\n";

  it("staging last hunk stages whole file if no filemode changes", function() {
    return stagingTest(true, lastHunkStagedFileContent)
      .then(function() {
        return test.repository.openIndex();
      })
      .then(function(index) {
        return NodeGit.Diff.indexToWorkdir(test.repository, index, {
            flags:
              NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
              NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
          });
      })
      .then(function(diff) {
        assert.equal(Object.keys(diff).length, 0);  //Empty diff
        return diff.patches();
      })
      .then(function(patches) {
        //patches will have at least one item if there is something unstaged
        assert.equal(patches.length, 0);
      });
  });

  function stagingFilemodeTest(staging) {
    var getDiffFunction;
    var fileContent = "Blek";
    var fileName = "stageFilemodeTest.txt";
    var index;

    if (staging) {
      getDiffFunction = function() {
        return NodeGit.Diff.indexToWorkdir(test.repository, index, {
            flags:
              NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
              NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
          });
      };
    }
    else {
      getDiffFunction = function() {
        return RepoUtils.addFileToIndex(test.repository, fileName)
          .then(function() {
            return test.repository.getBranchCommit("master");
          })
          .then(function(masterCommit) {
            return masterCommit.getTree();
          })
          .then(function(masterTree) {
            return NodeGit.Diff.treeToIndex(
              test.repository, masterTree, index, {
              flags:
                NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
                NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
            });
          });
      };
    }

    return RepoUtils.commitFileToRepo(test.repository, fileName, fileContent)
    .then(function() {
      return fse.writeFile(path.join(test.repository.workdir(), fileName),
                            fileContent)
        .then(function() {
          return fse.chmod(path.join(test.repository.workdir(), fileName),
            0777);
        });
    })
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return getDiffFunction();
    })
    .then(function(fileDiff) {
      return fileDiff.patches();
    })
    .then(function(patches) {
      assert(patches[0].newFile().mode() - patches[0].oldFile().mode() ===
        0111);
      var pathPatch = patches.filter(function(patch) {
        return patch.newFile().path() === fileName;
      });
      return pathPatch[0].hunks();
    });
  }

  it("can stage filemode changes", function() {
    return stagingFilemodeTest(false);
  });

  it("can unstage filemode changes", function() {
    return stagingFilemodeTest(true);
  });

});
<commit_msg>Fix tests for stage/unstage filemode changes<commit_after>var assert = require("assert");
var path = require("path");
var Promise = require("nodegit-promise");
var promisify = require("promisify-node");
var fse = promisify(require("fs-extra"));

describe("Stage", function() {
  var RepoUtils = require("../utils/repository_setup");
  var NodeGit = require("../../");
	var test;

  beforeEach(function() {
    test = this;
		var repoDir = "../repos/stagingRepo/";
    var repoPath = path.resolve(__dirname, repoDir);

    return RepoUtils.createRepository(repoPath)
      .then(function(repo) {
        test.repository = repo;
        return repo.openIndex();
      })
      .then(function(index) {
        test.index = index;
      });
  });

  after(function() {
		return fse.remove(test.repository.workdir());
  });

function stagingTest(staging, newFileContent) {
    var fileContent = newFileContent ||
                      "One line of text\n" +
                      "Two lines of text\n"+
                      "Three lines of text\n"+
                      "Four lines of text\n"+
                      "Five lines of text\n"+
                      "Six lines of text\n"+
                      "Seven lines of text\n"+
                      "Eight lines of text\n"+
                      "Nine lines of text\n"+
                      "Ten lines of text\n"+
                      "Eleven lines of text\n"+
                      "Twelve lines of text\n"+
                      "Thirteen lines of text\n"+
                      "Fourteen lines of text\n"+
                      "Fifteen lines of text\n"+
                      "Sixteen lines of text\n"+
                      "Seventeen lines of text\n"+
                      "Eighteen lines of text\n"+
                      "Nineteen lines of text\n"+
                      "Twenty lines of text\n";
    var fileName = "stagedLinesTest.txt";
    var index;
    var stagedFile;
    var workingDirFile;
    var getDiffFunction;
    if (staging) {
      stagedFile = fileContent.replace("Fifteen", "Changed fifteen");
      workingDirFile = stagedFile.replace("Three", "Changed three")
                            .replace("Seventeen", "Changed seventeen");
      getDiffFunction = function() {
        return NodeGit.Diff.indexToWorkdir(test.repository, index, {
            flags:
              NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
              NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
          });
      };
    }
    else {
      stagedFile = fileContent.replace("Three", "Changed three")
                            .replace("Seventeen", "Changed seventeen");
      workingDirFile = stagedFile.replace("Fifteen", "Changed fifteen");

      getDiffFunction = function() {
        return RepoUtils.addFileToIndex(test.repository, fileName)
          .then(function() {
            return test.repository.getBranchCommit("master");
          })
          .then(function(masterCommit) {
            return masterCommit.getTree();
          })
          .then(function(masterTree) {
            return NodeGit.Diff.treeToIndex(
              test.repository, masterTree, index, {
              flags:
                NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
                NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
            });
          });
      };
    }

    return RepoUtils.commitFileToRepo(test.repository, fileName, fileContent)
    .then(function() {
      return fse.writeFile(path.join(test.repository.workdir(), fileName),
                            workingDirFile);
    })
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return getDiffFunction();
    })
    .then(function(fileDiff) {
      return fileDiff.patches();
    })
    .then(function(patches) {
      var pathPatch = patches.filter(function(patch) {
        return patch.newFile().path() === fileName;
      });
      return pathPatch[0].hunks();
    })
    .then(function(pathHunks) {
      var linePromises = [];

      pathHunks.forEach(function(pathHunk) {
        linePromises.push(pathHunk.lines());
      });

      return Promise.all(linePromises);
    })
    .then(function(lines) {
      var linesToStage = [];
      lines.forEach(function(hunkLines) {
        hunkLines.forEach(function(line) {
          if (line.content().toLowerCase().indexOf("fifteen") >= 0){
            linesToStage.push(line);
          }
        });
      });
      return test.repository.stageLines(fileName, linesToStage, !staging);
    })
    .then(function(stageResult) {
      assert.equal(stageResult, 0);
      var pathOid = index.getByPath(fileName).id;
      return test.repository.getBlob(pathOid);
    })
    .then(function(resultFileContents) {
      assert.equal(resultFileContents.toString(), stagedFile);
    });
  }

  it("can stage selected lines", function() {
    return stagingTest(true);
  });
  it("can unstage selected lines", function() {
    return stagingTest(false);
  });

  //This is used to test cases where there are no newline at EOF
  var newlineEofTestFileContent =
                  "One line of text\n" +
                  "Two lines of text\n"+
                  "Three lines of text\n"+
                  "Four lines of text\n"+
                  "Five lines of text\n"+
                  "Six lines of text\n"+
                  "Seven lines of text\n"+
                  "Eight lines of text\n"+
                  "Nine lines of text\n"+
                  "Ten lines of text\n"+
                  "Eleven lines of text\n"+
                  "Twelve lines of text\n"+
                  "Thirteen lines of text\n"+
                  "Fourteen lines of text\n"+
                  "Fifteen lines of text";
  it("can stage last line with no newline at EOF", function() {
    return stagingTest(true, newlineEofTestFileContent);
  });
  it("can unstage last line with no newline at EOF", function() {
    return stagingTest(false, newlineEofTestFileContent);
  });
  it("can stage second to last line with no newline at EOF", function() {
    var newlineEofTestFileContent2 = newlineEofTestFileContent +
     "\nSixteen lines of text\nSeventeen lines of text\nEighteen lines of text";
    return stagingTest(true, newlineEofTestFileContent2);
  });
  it("can unstage second to last line with no newline at EOF", function() {
    var newlineEofTestFileContent2 = newlineEofTestFileContent +
     "\nSixteen lines of text\nSeventeen lines of text\nEighteen lines of text";
    return stagingTest(false, newlineEofTestFileContent2);
  });

  //This is used to test case where the last hunk is staged.
  var lastHunkStagedFileContent =
                "Thirteen lines of text\n"+
                "Fourteen lines of text\n"+
                "Fifteen lines of text\n"+
                "Sixteen lines of text\n"+
                "Shforteenteen lines of text\n";

  it("staging last hunk stages whole file if no filemode changes", function() {
    return stagingTest(true, lastHunkStagedFileContent)
      .then(function() {
        return test.repository.openIndex();
      })
      .then(function(index) {
        return NodeGit.Diff.indexToWorkdir(test.repository, index, {
            flags:
              NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
              NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
          });
      })
      .then(function(diff) {
        assert.equal(Object.keys(diff).length, 0);  //Empty diff
        return diff.patches();
      })
      .then(function(patches) {
        //patches will have at least one item if there is something unstaged
        assert.equal(patches.length, 0);
      });
  });

  it("can stage filemode changes", function() {
    var fileContent = "Blek";
    var fileName = "stageFilemodeTest.txt";
    var index;
    var diffPromise = function() {
      return NodeGit.Diff.indexToWorkdir(test.repository, index, {
          flags:
            NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
            NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
        });
      };

    return RepoUtils.commitFileToRepo(test.repository, fileName, fileContent)
    .then(function() {
      //First, create a file, have the same file in both the repo and workdir.
      //Then, change the permission.
      return fse.writeFile(path.join(test.repository.workdir(), fileName),
                            fileContent)
        .then(function() {
          return fse.chmod(path.join(test.repository.workdir(), fileName),
            0777);
        });
    })
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return diffPromise();
    })
    .then(function(fileDiff) {
      return fileDiff.getDelta(0);
    })
    .then(function(delta) {
      //Stage filemode change
      assert(delta.newFile().mode() - delta.oldFile().mode() === 0111);
      return test.repository.stageFilemode(fileName, true);
    })
    .then(function() {
      //Now lets do a commit...
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      index.read(1);
      return index.writeTree();
    })
    .then(function (oid) {
      var signature = NodeGit.Signature.create("Foo bar",
        "foo@bar.com", 123456789, 60);
      return test.repository.createCommit("HEAD", signature, signature,
          "initial commit", oid, []);
      //... alright, we did a commit.
    })
    .then(function() {
      //Now if we compare HEAD to
      return diffPromise();
    })
    .then(function(fileDiff) {
      return fileDiff.getDelta(0);
    })
    .then(function(delta) {
      assert(!delta);
    });
  });

  it("can unstage filemode changes", function() {
    var fileContent = "Blek";
    var fileName = "stageFilemodeTest2.txt";
    var index;
    var oldFilemode;
    var diffPromise = function() {
        return RepoUtils.addFileToIndex(test.repository, fileName)
          .then(function() {
            return test.repository.getBranchCommit("master");
          })
          .then(function(masterCommit) {
            return masterCommit.getTree();
          })
          .then(function(masterTree) {
            return NodeGit.Diff.treeToIndex(
              test.repository, masterTree, index, {
              flags:
                NodeGit.Diff.OPTION.SHOW_UNTRACKED_CONTENT |
                NodeGit.Diff.OPTION.RECURSE_UNTRACKED_DIRS
            });
          });
      };

    return RepoUtils.commitFileToRepo(test.repository, fileName, fileContent)
    .then(function() {
      return fse.writeFile(path.join(test.repository.workdir(), fileName),
                            fileContent)
        .then(function() {
          return fse.chmod(path.join(test.repository.workdir(), fileName),
            0100755);
        });
    })
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return diffPromise();
    })
    .then(function(fileDiff) {
      return fileDiff.getDelta(0);
    })
    .then(function(delta) {
      oldFilemode = delta.oldFile().mode();
      assert(delta.newFile().mode() - delta.oldFile().mode() ===
        0111);

      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return index.entries();
    })
    .then(function(entries) {
      assert(entries[0].mode == 0100755);
      return test.repository.stageFilemode(fileName, false);
    })
    .then(function() {
      return test.repository.openIndex();
    })
    .then(function(repoIndex) {
      index = repoIndex;
      return index.entries();
    })
    .then(function(entries) {
      assert(entries[0].mode == oldFilemode);
    });
  });

});
<|endoftext|>


<commit_before>/*
 Transform a table to a jqGrid.
 Peter Romianowski <peter.romianowski@optivo.de>
 If the first column of the table contains checkboxes or
 radiobuttons then the jqGrid is made selectable.
*/
// Addition - selector can be a class or id
function tableToGrid(selector) {
$(selector).each(function() {
	if(this.grid) {return;} //Adedd from Tony Tomov
	// This is a small "hack" to make the width of the jqGrid 100%
	$(this).width("99%");
	var w = $(this).width();

	// Text whether we have single or multi select
	var inputCheckbox = $('input[type=checkbox]:first', $(this));
	var inputRadio = $('input[type=radio]:first', $(this));
	var selectMultiple = inputCheckbox.length > 0;
	var selectSingle = !selectMultiple && inputRadio.length > 0;
	var selectable = selectMultiple || selectSingle;
	var inputName = inputCheckbox.attr("name") || inputRadio.attr("name");

	// Build up the columnModel and the data
	var colModel = [];
	var colNames = [];
	$('th', $(this)).each(function() {
		if (colModel.length == 0 && selectable) {
			colModel.push({
				name: '__selection__',
				index: '__selection__',
				width: 0,
				hidden: true
			});
			colNames.push('__selection__');
		} else {
			colModel.push({
				name: $(this).html(),
				index: $(this).html(),
				width: $(this).width() || 150
			});
			colNames.push($(this).html());
		}
	});
	var data = [];
	var rowIds = [];
	var rowChecked = [];
	$('tbody > tr', $(this)).each(function() {
		var row = {};
		var rowPos = 0;
		data.push(row);
		$('td', $(this)).each(function() {
			if (rowPos == 0 && selectable) {
				var input = $('input', $(this));
				var rowId = input.attr("value");
				rowIds.push(rowId || data.length);
				if (input.attr("checked")) {
					rowChecked.push(rowId);
				}
				row[colModel[rowPos].name] = input.attr("value");
			} else {
				row[colModel[rowPos].name] = $(this).html();
			}
			rowPos++;
		});
	});

	// Clear the original HTML table
	$(this).empty();

	// Mark it as jqGrid
	$(this).addClass("scroll");

	$(this).jqGrid({
		datatype: "local",
		width: w,
		colNames: colNames,
		colModel: colModel,
		multiselect: selectMultiple
		//inputName: inputName,
		//inputValueCol: imputName != null ? "__selection__" : null
	});

	// Add data
	for (var a = 0; a < data.length; a++) {
		var id = null;
		if (rowIds.length > 0) {
			id = rowIds[a];
			if (id && id.replace) {
				// We have to do this since the value of a checkbox
				// or radio button can be anything
				id = encodeURIComponent(id).replace(/[.\-%]/g, "_");
			}
		}
		if (id == null) {
			id = a + 1;
		}
		$(this).addRowData(id, data[a]);
	}

	// Set the selection
	for (var a = 0; a < rowChecked.length; a++) {
		$(this).setSelection(rowChecked[a]);
	}
});
};
<commit_msg>Extend tableToGrid method to use custom options when building the grid<commit_after>/*
 Transform a table to a jqGrid.
 Peter Romianowski <peter.romianowski@optivo.de>
 If the first column of the table contains checkboxes or
 radiobuttons then the jqGrid is made selectable.
*/
// Addition - selector can be a class or id
function tableToGrid(selector, options) {
$(selector).each(function() {
	if(this.grid) {return;} //Adedd from Tony Tomov
	// This is a small "hack" to make the width of the jqGrid 100%
	$(this).width("99%");
	var w = $(this).width();

	// Text whether we have single or multi select
	var inputCheckbox = $('input[type=checkbox]:first', $(this));
	var inputRadio = $('input[type=radio]:first', $(this));
	var selectMultiple = inputCheckbox.length > 0;
	var selectSingle = !selectMultiple && inputRadio.length > 0;
	var selectable = selectMultiple || selectSingle;
	var inputName = inputCheckbox.attr("name") || inputRadio.attr("name");

	// Build up the columnModel and the data
	var colModel = [];
	var colNames = [];
	$('th', $(this)).each(function() {
		if (colModel.length == 0 && selectable) {
			colModel.push({
				name: '__selection__',
				index: '__selection__',
				width: 0,
				hidden: true
			});
			colNames.push('__selection__');
		} else {
			colModel.push({
				name: $(this).html(),
				index: $(this).html(),
				width: $(this).width() || 150
			});
			colNames.push($(this).html());
		}
	});
	var data = [];
	var rowIds = [];
	var rowChecked = [];
	$('tbody > tr', $(this)).each(function() {
		var row = {};
		var rowPos = 0;
		data.push(row);
		$('td', $(this)).each(function() {
			if (rowPos == 0 && selectable) {
				var input = $('input', $(this));
				var rowId = input.attr("value");
				rowIds.push(rowId || data.length);
				if (input.attr("checked")) {
					rowChecked.push(rowId);
				}
				row[colModel[rowPos].name] = input.attr("value");
			} else {
				row[colModel[rowPos].name] = $(this).html();
			}
			rowPos++;
		});
	});

	// Clear the original HTML table
	$(this).empty();

	// Mark it as jqGrid
	$(this).addClass("scroll");

	$(this).jqGrid($.extend({
		datatype: "local",
		width: w,
		colNames: colNames,
		colModel: colModel,
		multiselect: selectMultiple
		//inputName: inputName,
		//inputValueCol: imputName != null ? "__selection__" : null
	}, options || {}));

	// Add data
	for (var a = 0; a < data.length; a++) {
		var id = null;
		if (rowIds.length > 0) {
			id = rowIds[a];
			if (id && id.replace) {
				// We have to do this since the value of a checkbox
				// or radio button can be anything
				id = encodeURIComponent(id).replace(/[.\-%]/g, "_");
			}
		}
		if (id == null) {
			id = a + 1;
		}
		$(this).addRowData(id, data[a]);
	}

	// Set the selection
	for (var a = 0; a < rowChecked.length; a++) {
		$(this).setSelection(rowChecked[a]);
	}
});
};
<|endoftext|>


<commit_before>const supertest = require('supertest')
const should = require('should')
const PaperUtils = require('../view/paperutils.js')

module.exports = (schsrch, dbModel) =>
  describe('Full text search', function () {
    const {PastPaperDoc} = dbModel
    function ftExpectBasic (x) {
      return x
        .expect(res => res.body.list.should.be.an.Array())
        .expect(res => res.body.list.forEach(x => x.should.be.an.Object()))
        .expect(res => res.body.list.forEach(x => x.doc.should.be.an.Object()))
        .expect(res => res.body.list.forEach(x => x.doc._id.should.be.a.String()))
        .expect(res => res.body.list.forEach(x => x.doc.fileType.should.equal('pdf')))
        .expect(res => res.body.list.forEach(x => should.not.exist(x.doc.doc)))
        .expect(res => res.body.list.forEach(x => should.not.exist(x.doc.fileBlob)))
        .expect(res => res.body.list.forEach(x => x.index.should.be.an.Object()))
        .expect(res => res.body.list.forEach(x => x.index._id.should.be.an.String()))
        .expect(res => res.body.list.forEach(x => x.index.docId.should.be.an.String()))
        .expect(res => res.body.list.forEach(x => x.index.page.should.be.an.Number().and.aboveOrEqual(0)))
        .expect(res => res.body.list.forEach(x => should.not.exist(x.index.sspdfCache)))
        .expect(res => res.body.list = res.body.list.filter(x => x.doc.subject !== '0470'))
    }
    let indexToSearch = null
    let tDocId = null
    function keywordsTest(done, itx) {
      ftExpectBasic(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent(itx ? itx : 'decrease delivery demand desk'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
          .expect(res => res.body.should.be.an.Object())
          .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
          .expect(res => res.body.list.should.be.an.Array()))
        .expect(res => res.body.list.length.should.equal(1, `Response should have one result returned.`))
        .expect(res => res.body.list = res.body.list.map(x => Object.assign(x, {str: `${PaperUtils.setToString(x.doc)}_${x.doc.type}`})))
        .expect(res => res.body.list[0].str.should.equal('0610_s16_1_0_qp'))
        .expect(res => res.body.list[0].related.should.be.an.Array())
        .expect(res => res.body.list[0].related.should.have.length(1))
        .expect(res => res.body.list[0].related[0].should.be.an.Object())
        .expect(res => res.body.list[0].related[0]._id.should.be.a.String())
        .expect(res => res.body.list[0].related[0].type.should.equal('ms'))
        .expect(res => res.body.list[0].related[0].numPages.should.equal(1))
        .expect(res => res.body.list[0].related[0].fileType.should.equal('pdf'))
        .expect(res => should.not.exist(res.body.list[0].related[0].doc))
        .expect(res => should.not.exist(res.body.list[0].related[0].sspdfCache))
        .expect(res => indexToSearch = res.body.list[0].index._id)
        .expect(res => tDocId = res.body.list[0].doc._id)
        .end(done)
    }
    it('Case: decrease delivery bla bla bla...', function (done) {
      keywordsTest(done)
    })
    it('Case: Lorem ipsum dolor sit amet', function (done) {
      ftExpectBasic(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('Lorem ipsum dolor sit amet'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
          .expect(res => res.body.should.be.an.Object())
          .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
          .expect(res => res.body.list.should.be.an.Array())
          .expect(res => res.body.list.length.should.equal(2, `Response should have two results returned.`)))
        .expect(res => res.body.list = res.body.list.map(x => Object.assign(x, {str: `${PaperUtils.setToString(x.doc)}_${x.doc.type}`})))
        .expect(res => res.body.list[0].str.match(/^0612/) ? res.body.list = [res.body.list[1], res.body.list[0]] : null)
        .expect(res => res.body.list[0].str.should.equal('0611_s16_9_0_ms'))
        .expect(res => res.body.list[0].related.should.be.an.Array())
        .expect(res => res.body.list[0].related.should.have.length(0))
        .expect(res => res.body.list[1].str.should.equal('0612_s16_9_0_ms'))
        .expect(res => res.body.list[1].related.should.be.an.Array())
        .expect(res => res.body.list[1].related.should.have.length(0))
        .end(done)
    })
    it('Case: 0612 Lorem ipsum dolor sit amet', function (done) {
      ftExpectBasic(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('0612 Lorem ipsum dolor sit amet'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
          .expect(res => res.body.should.be.an.Object())
          .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
          .expect(res => res.body.list.should.be.an.Array())
          .expect(res => res.body.list.length.should.equal(1, `Response should have one result returned.`)))
        .expect(res => res.body.list = res.body.list.map(x => Object.assign(x, {str: `${PaperUtils.setToString(x.doc)}_${x.doc.type}`})))
        .expect(res => res.body.list[0].str.should.equal('0612_s16_9_0_ms'))
        .expect(res => res.body.list[0].related.should.be.an.Array())
        .expect(res => res.body.list[0].related.should.have.length(0))
        .end(done)
    })
    it('Case: 0611 Lorem ipsum dolor sit amet', function (done) {
      ftExpectBasic(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('0611 Lorem ipsum dolor sit amet'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
          .expect(res => res.body.should.be.an.Object())
          .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
          .expect(res => res.body.list.should.be.an.Array())
          .expect(res => res.body.list.length.should.equal(1, `Response should have one result returned.`)))
        .expect(res => res.body.list = res.body.list.map(x => Object.assign(x, {str: `${PaperUtils.setToString(x.doc)}_${x.doc.type}`})))
        .expect(res => res.body.list[0].str.should.equal('0611_s16_9_0_ms'))
        .expect(res => res.body.list[0].related.should.be.an.Array())
        .expect(res => res.body.list[0].related.should.have.length(0))
        .end(done)
    })
    function ftExpectEmpty (req) {
      return ftExpectBasic(req)
        .expect(res => res.body.should.be.an.Object())
        .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
        .expect(res => res.body.list.should.be.an.Array())
        .expect(res => res.body.list.length.should.equal(0, `Response should have no results returned.`))
    }
    function test0611P9 (paper) {
      return function (done) {
        ftExpectBasic(
          supertest(schsrch)
            .get('/search/?query=' + encodeURIComponent(`0611 ${paper} Lorem ipsum dolor sit amet`))
            .set('Host', 'schsrch.xyz')
            .expect('Content-Type', /json/)
            .expect(200)
            .expect(res => res.body.should.be.an.Object())
            .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
            .expect(res => res.body.list.should.be.an.Array())
            .expect(res => res.body.list.length.should.equal(1, `Response should have one result returned.`)))
          .expect(res => res.body.list = res.body.list.map(x => Object.assign(x, {str: `${PaperUtils.setToString(x.doc)}_${x.doc.type}`})))
          .expect(res => res.body.list[0].str.should.equal('0611_s16_9_0_ms'))
          .expect(res => res.body.list[0].related.should.be.an.Array())
          .expect(res => res.body.list[0].related.should.have.length(0))
          .end(done)
      }
    }
    it('Case: 0611 paper 9 Lorem ipsum dolor sit amet', test0611P9('paper 9'))
    it('Case: 0611 paper9 Lorem ipsum dolor sit amet', test0611P9('paper9'))
    it('Case: 0611 p9 Lorem ipsum dolor sit amet', test0611P9('p9'))
    it('Case: 0611 paper 3 Lorem ipsum dolor sit amet', function (done) {
      ftExpectEmpty(
        supertest(schsrch)
          .get('/search/?query=0611 paper 3 Lorem ipsum dolor sit amet')
          .set('Host', 'schsrch.xyz'))
        .end(done)
    })
    it('Case: 0611 paper3 Lorem ipsum dolor sit amet', function (done) {
      ftExpectEmpty(
        supertest(schsrch)
          .get('/search/?query=0611 paper3 Lorem ipsum dolor sit amet')
          .set('Host', 'schsrch.xyz'))
        .end(done)
    })
    it('Case: 0611 p3 Lorem ipsum dolor sit amet', function (done) {
      ftExpectEmpty(
        supertest(schsrch)
          .get('/search/?query=0611 p3 Lorem ipsum dolor sit amet')
          .set('Host', 'schsrch.xyz'))
        .end(done)
    })
    it('Case: 0613 Lorem ipsum dolor sit amet', function (done) {
      ftExpectBasic(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('0613 Lorem ipsum dolor sit amet'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
          .expect(res => res.body.should.be.an.Object())
          .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
          .expect(res => res.body.list.should.be.an.Array())
          .expect(res => res.body.list.length.should.equal(0, `Response should have no results returned.`)))
        .end(done)
    })
    it('Case: !!index!...', function (done) {
      indexToSearch.should.be.a.String()
      keywordsTest(done, '!!index!' + indexToSearch)
    })
    it('Case: !!index!000000000000000000000000' , function (done) {
      ftExpectEmpty(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('!!index!000000000000000000000000'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
      ).end(done)
    })
    it("Shouldn't return the result if the corrospounding doc disappeared", function (done) {
      PastPaperDoc.remove({_id: tDocId}).then(() => {
        ftExpectEmpty(
          supertest(schsrch)
            .get('/search/?query=' + encodeURIComponent('decrease delivery demand desk'))
            .set('Host', 'schsrch.xyz')
            .expect('Content-Type', /json/)
            .expect(200)
        ).end(done)
      }, err => done(err))
    })
    it("Shouldn't return !!index result if the corrospounding doc disappeared" , function (done) {
      ftExpectEmpty(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('!!index!' + indexToSearch))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
      ).end(done)
    })
  })
<commit_msg>Change keyword since newly added paper contains business words.<commit_after>const supertest = require('supertest')
const should = require('should')
const PaperUtils = require('../view/paperutils.js')

module.exports = (schsrch, dbModel) =>
  describe('Full text search', function () {
    const {PastPaperDoc} = dbModel
    function ftExpectBasic (x) {
      return x
        .expect(res => res.body.list.should.be.an.Array())
        .expect(res => res.body.list.forEach(x => x.should.be.an.Object()))
        .expect(res => res.body.list.forEach(x => x.doc.should.be.an.Object()))
        .expect(res => res.body.list.forEach(x => x.doc._id.should.be.a.String()))
        .expect(res => res.body.list.forEach(x => x.doc.fileType.should.equal('pdf')))
        .expect(res => res.body.list.forEach(x => should.not.exist(x.doc.doc)))
        .expect(res => res.body.list.forEach(x => should.not.exist(x.doc.fileBlob)))
        .expect(res => res.body.list.forEach(x => x.index.should.be.an.Object()))
        .expect(res => res.body.list.forEach(x => x.index._id.should.be.an.String()))
        .expect(res => res.body.list.forEach(x => x.index.docId.should.be.an.String()))
        .expect(res => res.body.list.forEach(x => x.index.page.should.be.an.Number().and.aboveOrEqual(0)))
        .expect(res => res.body.list.forEach(x => should.not.exist(x.index.sspdfCache)))
        .expect(res => res.body.list = res.body.list.filter(x => x.doc.subject !== '0470'))
    }
    let indexToSearch = null
    let tDocId = null
    function keywordsTest(done, itx) {
      ftExpectBasic(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent(itx ? itx : 'servant set since soil'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
          .expect(res => res.body.should.be.an.Object())
          .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
          .expect(res => res.body.list.should.be.an.Array()))
        .expect(res => res.body.list.length.should.equal(1, `Response should have one result returned.`))
        .expect(res => res.body.list = res.body.list.map(x => Object.assign(x, {str: `${PaperUtils.setToString(x.doc)}_${x.doc.type}`})))
        .expect(res => res.body.list[0].str.should.equal('0610_s16_1_0_qp'))
        .expect(res => res.body.list[0].related.should.be.an.Array())
        .expect(res => res.body.list[0].related.should.have.length(1))
        .expect(res => res.body.list[0].related[0].should.be.an.Object())
        .expect(res => res.body.list[0].related[0]._id.should.be.a.String())
        .expect(res => res.body.list[0].related[0].type.should.equal('ms'))
        .expect(res => res.body.list[0].related[0].numPages.should.equal(1))
        .expect(res => res.body.list[0].related[0].fileType.should.equal('pdf'))
        .expect(res => should.not.exist(res.body.list[0].related[0].doc))
        .expect(res => should.not.exist(res.body.list[0].related[0].sspdfCache))
        .expect(res => indexToSearch = res.body.list[0].index._id)
        .expect(res => tDocId = res.body.list[0].doc._id)
        .end(done)
    }
    it('Case: decrease delivery bla bla bla...', function (done) {
      keywordsTest(done)
    })
    it('Case: Lorem ipsum dolor sit amet', function (done) {
      ftExpectBasic(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('Lorem ipsum dolor sit amet'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
          .expect(res => res.body.should.be.an.Object())
          .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
          .expect(res => res.body.list.should.be.an.Array())
          .expect(res => res.body.list.length.should.equal(2, `Response should have two results returned.`)))
        .expect(res => res.body.list = res.body.list.map(x => Object.assign(x, {str: `${PaperUtils.setToString(x.doc)}_${x.doc.type}`})))
        .expect(res => res.body.list[0].str.match(/^0612/) ? res.body.list = [res.body.list[1], res.body.list[0]] : null)
        .expect(res => res.body.list[0].str.should.equal('0611_s16_9_0_ms'))
        .expect(res => res.body.list[0].related.should.be.an.Array())
        .expect(res => res.body.list[0].related.should.have.length(0))
        .expect(res => res.body.list[1].str.should.equal('0612_s16_9_0_ms'))
        .expect(res => res.body.list[1].related.should.be.an.Array())
        .expect(res => res.body.list[1].related.should.have.length(0))
        .end(done)
    })
    it('Case: 0612 Lorem ipsum dolor sit amet', function (done) {
      ftExpectBasic(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('0612 Lorem ipsum dolor sit amet'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
          .expect(res => res.body.should.be.an.Object())
          .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
          .expect(res => res.body.list.should.be.an.Array())
          .expect(res => res.body.list.length.should.equal(1, `Response should have one result returned.`)))
        .expect(res => res.body.list = res.body.list.map(x => Object.assign(x, {str: `${PaperUtils.setToString(x.doc)}_${x.doc.type}`})))
        .expect(res => res.body.list[0].str.should.equal('0612_s16_9_0_ms'))
        .expect(res => res.body.list[0].related.should.be.an.Array())
        .expect(res => res.body.list[0].related.should.have.length(0))
        .end(done)
    })
    it('Case: 0611 Lorem ipsum dolor sit amet', function (done) {
      ftExpectBasic(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('0611 Lorem ipsum dolor sit amet'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
          .expect(res => res.body.should.be.an.Object())
          .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
          .expect(res => res.body.list.should.be.an.Array())
          .expect(res => res.body.list.length.should.equal(1, `Response should have one result returned.`)))
        .expect(res => res.body.list = res.body.list.map(x => Object.assign(x, {str: `${PaperUtils.setToString(x.doc)}_${x.doc.type}`})))
        .expect(res => res.body.list[0].str.should.equal('0611_s16_9_0_ms'))
        .expect(res => res.body.list[0].related.should.be.an.Array())
        .expect(res => res.body.list[0].related.should.have.length(0))
        .end(done)
    })
    function ftExpectEmpty (req) {
      return ftExpectBasic(req)
        .expect(res => res.body.should.be.an.Object())
        .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
        .expect(res => res.body.list.should.be.an.Array())
        .expect(res => res.body.list.length.should.equal(0, `Response should have no results returned.`))
    }
    function test0611P9 (paper) {
      return function (done) {
        ftExpectBasic(
          supertest(schsrch)
            .get('/search/?query=' + encodeURIComponent(`0611 ${paper} Lorem ipsum dolor sit amet`))
            .set('Host', 'schsrch.xyz')
            .expect('Content-Type', /json/)
            .expect(200)
            .expect(res => res.body.should.be.an.Object())
            .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
            .expect(res => res.body.list.should.be.an.Array())
            .expect(res => res.body.list.length.should.equal(1, `Response should have one result returned.`)))
          .expect(res => res.body.list = res.body.list.map(x => Object.assign(x, {str: `${PaperUtils.setToString(x.doc)}_${x.doc.type}`})))
          .expect(res => res.body.list[0].str.should.equal('0611_s16_9_0_ms'))
          .expect(res => res.body.list[0].related.should.be.an.Array())
          .expect(res => res.body.list[0].related.should.have.length(0))
          .end(done)
      }
    }
    it('Case: 0611 paper 9 Lorem ipsum dolor sit amet', test0611P9('paper 9'))
    it('Case: 0611 paper9 Lorem ipsum dolor sit amet', test0611P9('paper9'))
    it('Case: 0611 p9 Lorem ipsum dolor sit amet', test0611P9('p9'))
    it('Case: 0611 paper 3 Lorem ipsum dolor sit amet', function (done) {
      ftExpectEmpty(
        supertest(schsrch)
          .get('/search/?query=0611 paper 3 Lorem ipsum dolor sit amet')
          .set('Host', 'schsrch.xyz'))
        .end(done)
    })
    it('Case: 0611 paper3 Lorem ipsum dolor sit amet', function (done) {
      ftExpectEmpty(
        supertest(schsrch)
          .get('/search/?query=0611 paper3 Lorem ipsum dolor sit amet')
          .set('Host', 'schsrch.xyz'))
        .end(done)
    })
    it('Case: 0611 p3 Lorem ipsum dolor sit amet', function (done) {
      ftExpectEmpty(
        supertest(schsrch)
          .get('/search/?query=0611 p3 Lorem ipsum dolor sit amet')
          .set('Host', 'schsrch.xyz'))
        .end(done)
    })
    it('Case: 0613 Lorem ipsum dolor sit amet', function (done) {
      ftExpectBasic(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('0613 Lorem ipsum dolor sit amet'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
          .expect(res => res.body.should.be.an.Object())
          .expect(res => res.body.response.should.equal('text', 'Response should be "text" type'))
          .expect(res => res.body.list.should.be.an.Array())
          .expect(res => res.body.list.length.should.equal(0, `Response should have no results returned.`)))
        .end(done)
    })
    it('Case: !!index!...', function (done) {
      indexToSearch.should.be.a.String()
      keywordsTest(done, '!!index!' + indexToSearch)
    })
    it('Case: !!index!000000000000000000000000' , function (done) {
      ftExpectEmpty(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('!!index!000000000000000000000000'))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
      ).end(done)
    })
    it("Shouldn't return the result if the corrospounding doc disappeared", function (done) {
      PastPaperDoc.remove({_id: tDocId}).then(() => {
        ftExpectEmpty(
          supertest(schsrch)
            .get('/search/?query=' + encodeURIComponent('servant set since soil'))
            .set('Host', 'schsrch.xyz')
            .expect('Content-Type', /json/)
            .expect(200)
        ).end(done)
      }, err => done(err))
    })
    it("Shouldn't return !!index result if the corrospounding doc disappeared" , function (done) {
      ftExpectEmpty(
        supertest(schsrch)
          .get('/search/?query=' + encodeURIComponent('!!index!' + indexToSearch))
          .set('Host', 'schsrch.xyz')
          .expect('Content-Type', /json/)
          .expect(200)
      ).end(done)
    })
  })
<|endoftext|>


<commit_before>// Copyright 2022, University of Colorado Boulder

/**
 * Produces an assignment list of responsible devs. Run from lint.js
 *
 * The Chip Away option provides a quick and easy method to assign devs to their respective repositories
 * for ease in adopting and applying new typescript linting rules.
 * Chip Away will return a markdown formatted checklist with the repository name, responsible dev,
 * and number of errors.
 * Response  format:
 * - [ ] {{REPO}}: @{{GITHUB_USERNAME}} {{NUMBER}} errors in {{NUMBER}} files.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Marla Schulz (PhET Interactive Simulations)
 */

const fs = require( 'fs' );
const _ = require( 'lodash' ); // eslint-disable-line require-statement-match
const path = require( 'path' );

module.exports = function chipAway( results ) {
  const repos = results.map( result => path.relative( '../', result.filePath ).split( path.sep )[ 0 ] );
  const uniqueRepos = _.uniq( repos ).filter( repo => repo !== 'perennial-alias' );

  // NOTE: This should never be run in a maintenance mode since this loads a file from phet-info which
  // does not have its SHA tracked as a dependency.
  // TODO: For the reviewer, is this OK? https://github.com/phetsims/chipper/issues/1253
  const responsibleDevs = JSON.parse( fs.readFileSync( '../phet-info/sim-info/responsible_dev.json' ) );

  // We only want a list of repos that report lint errors
  const reposWithErrors = uniqueRepos.filter( repo => {
    return errorReport( results, repo ).errorCount > 0;
  } );

  // Format chip away assignments. '{{REPO}} @github # errors in # files'
  const assignments = reposWithErrors.map( repo => {
    const fileCount = errorReport( results, repo ).fileCount;
    const errorCount = errorReport( results, repo ).errorCount;

    return ` - [ ] ${repo}: ${responsibleDevs[ repo ].responsibleDevs.join( ', ' )} ${errorCount} errors in ${fileCount} files.`;
  } );
  console.log( assignments.join( '\n' ) );
};

function errorReport( results, repo ) {
  const filteredResults = results.filter( result => path.relative( '../', result.filePath ).split( path.sep )[ 0 ] === repo );
  const fileCount = filteredResults.filter( result => result.errorCount + result.warningCount > 0 ).length;
  const errorCount = _.sum( filteredResults.map( file => file.errorCount + file.warningCount ) );

  return { errorCount: errorCount, fileCount: fileCount };
}
<commit_msg>Check for responsible devs file early, and exit gracefully if not found or not parseable, see https://github.com/phetsims/chipper/issues/1262<commit_after>// Copyright 2022, University of Colorado Boulder

/**
 * Produces an assignment list of responsible devs. Run from lint.js
 *
 * The Chip Away option provides a quick and easy method to assign devs to their respective repositories
 * for ease in adopting and applying new typescript linting rules.
 * Chip Away will return a markdown formatted checklist with the repository name, responsible dev,
 * and number of errors.
 * Response  format:
 * - [ ] {{REPO}}: @{{GITHUB_USERNAME}} {{NUMBER}} errors in {{NUMBER}} files.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Marla Schulz (PhET Interactive Simulations)
 */

const fs = require( 'fs' );
const _ = require( 'lodash' ); // eslint-disable-line require-statement-match
const path = require( 'path' );

module.exports = function chipAway( results ) {

  // NOTE: This should never be run in a maintenance mode since this loads a file from phet-info which
  // does not have its SHA tracked as a dependency.
  let responsibleDevs = null;
  try {
    responsibleDevs = JSON.parse( fs.readFileSync( '../phet-info/sim-info/responsible_dev.json' ) );
  }
  catch( e ) {

    // return gracefully if that file was not found or not parseable.
    console.log( 'Could not output chip-away information, due to: ' + e.message );
    return;
  }

  const repos = results.map( result => path.relative( '../', result.filePath ).split( path.sep )[ 0 ] );
  const uniqueRepos = _.uniq( repos ).filter( repo => repo !== 'perennial-alias' );

  // We only want a list of repos that report lint errors
  const reposWithErrors = uniqueRepos.filter( repo => {
    return errorReport( results, repo ).errorCount > 0;
  } );

  // Format chip away assignments. '{{REPO}} @github # errors in # files'
  const assignments = reposWithErrors.map( repo => {
    const fileCount = errorReport( results, repo ).fileCount;
    const errorCount = errorReport( results, repo ).errorCount;

    return ` - [ ] ${repo}: ${responsibleDevs[ repo ].responsibleDevs.join( ', ' )} ${errorCount} errors in ${fileCount} files.`;
  } );
  console.log( assignments.join( '\n' ) );
};

function errorReport( results, repo ) {
  const filteredResults = results.filter( result => path.relative( '../', result.filePath ).split( path.sep )[ 0 ] === repo );
  const fileCount = filteredResults.filter( result => result.errorCount + result.warningCount > 0 ).length;
  const errorCount = _.sum( filteredResults.map( file => file.errorCount + file.warningCount ) );

  return { errorCount: errorCount, fileCount: fileCount };
}
<|endoftext|>