<commit_before>/*
* numeric.ly
* author: steve kaliski
* last modified: sep 2012
*-----------------------------------------------------------------------------*/

var numeric = {

  //basic addition of vals in an array
  addition: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = 0;
      for (var i = 0 ; i < arr.length ; i++) {
        total = total + arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //subtract items in an array (descending)
  subtraction: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = arr[arr.length - 1];
      for (var i = arr.length - 2; i >= 0; i--) {
        total -= arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //product of items in array
  product: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = arr[0];
      for (var i = 1; i < arr.length; i++) {
        total = total * arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //greatest common denominator
  gcd: function(num1, num2) {
    var result;
    if (num1 > num2) {
      for (var i = 0 ; i <= num2 ; i++) {
        if (num2 % i === 0) {
          if (num1 % i === 0) {
            result = i;
          }
        }
      }
      return result;
    } else if (num2 > num1) {
      for (var i = 0 ; i <= num2 ; i++) {
        if (num1 % i === 0) {
          if (num2 % i === 0) {
            result = i;
          }
        }
      }
      return result;
    } else {
      result = num1 * num2 / num1;
      return result;
    }
  },

  //least common multiple
  lcm: function(num1, num2) {
    var result = Math.abs(num1 * num2) / gcd(num1,num2);
    return result;
  },

  //evaluate function at val (func passed as a string)
  evaluate: function(func, val) {
    return parseFloat(eval("with(Math){var x = " + val + ";" + func+'};'));
  },

/*-----------------------------------------------------------------------------*/

  //a variety of calculus tools
  calculus: {

    //function, point at which differentiation occurs (func passed as string)
    pointDiff: function(func, point) {
      var a = evaluate(func, point - .00001);
      var b = evaluate(func, point + .00001);

      return (b - a) / (.00002);
    },

    //calculate riemann integral (left hand) (func passed as string)
    riemann: function(func, start, finish, n) {
      var inc = (finish - start) / n;
      var result = 0;
      for (var i = start; i < finish; i += inc) {
        result += (evaluate(func, i) * inc);
      }
      return result;
    },

    //estimate integral with adaptive simpson quadrature
    simpsonDef: function(func, a, b) {
      var c = (a + b) / 2;
      var d = Math.abs(b - a) / 6;
      return d * (evaluate(func, a) + 4 * evaluate(func, c) + evaluate(func, b));
    },
    simpsonRecursive: function(func, a, b, eps, whole) {
      var c = a + b;
      var left = simpsonDef(func, a, c);
      var right = simpsonDef(func, c, b);
      if (Math.abs(left + right - whole) <= 15 * eps) {
        return left + right + (left + right - whole) / 15;
      } else {
        return simpsonRecursive(func, a, c, eps/2, left) + simpsonRecursive(func, c, b, eps / 2, right);
      }
    },
    //execute this
    adaptiveSimpson: function(func, a, b, eps) {
      return simpsonRecursive(func, a, b, eps, simpsonDef(func, a, b));
    },

    //take the limit of a function (left, middle, or right)
    limit: function(func, point, approach) {
      if (approach === 'left') {
        return evaluate(func, point - .001);
      } else if (approach === 'right') {
        return evaluate(func, point + .001);
      } else if (approach === 'middle') {
        return (limit(func, point, 'left') + limit(func, point, 'right')) / 2;
      } else {
        throw new Error('Approach not provided');
      }
    },

    //return taylor polynomial for function (func) at point (point) to degree (degree: 0, 1 and 2 for now)
    taylor: function(func, point, degree) {
      if (degree == 0) {

      } else if (degree == 1) {

      } else if (degree == 2) {

      }
    },

    //integrate taylor polynomial for some func
    polyIntegrate: function(func) {
      var taylor = taylor(func, 0, 8);
    }
  },

/*-----------------------------------------------------------------------------*/

  /*
  a variety of matrix analysis tools

  let's consider the matrix A:

  [1 2 3]
  [4 5 6]

  As input, set arg = [[1,2,3],[4,5,6]];

  Note: The "structure" of matrices may be neglected in some calculations,
  however in and transformation, mapping, etc, we recognize the proper
  format.
  */
  matrix: {

    //add two arrays (arrA and arrB)
    addition: function(arrA, arrB) {
      if ((arrA.length === arrB.length) && (arrA[0].length === arrB[0].length)) {
        var result = new Array(arrA.length);
        for (var i = 0; i < arrA.length; i++) {
          result[i] = new Array(arrA[i].length);
          for (var j = 0; j < arrA[i].length; j++) {
            result[i][j] = arrA[i][j] + arrB[i][j];
          }
        }
        return result;
      } else {
        throw new Error('Array mismatch');
      }
    },

    //multiple array (arr) by a scalar (val)
    scalar: function(arr,val) {
      for (var i = 0; i < arr.length; i++) {
        for (var j = 0; j < arr[i].length; j++) {
          arr[i][j] = val * arr[i][j];
        }
      }
      return arr;
    },

    //transpose array
    transpose: function(arr) {
      var result = new Array(arr[0].length);
      for (var i = 0; i < arr[0].length; i++) {
        result[i] = new Array(arr.length);
        for (var j = 0; j < arr.length; j++){
          result[i][j] = arr[j][i];
        }
      }
      return result;
    },

    //return identity matrix of dimension n x n
    identity: function(n) {
      var result = new Array(n);
      for (var i = 0 ; i < n ; i++) {
        result[i] = new Array(n);
        for (var j = 0 ; j < n ; j++) {
          result[i][j] = (i === j) ? 1 : 0;
        }
      }
      return result;
    },

    //dot product
    dotproduct: function(vectorA, vectorB) {
      if (vectorA.length === vectorB.length) {
        var result = 0;
        for (var i = 0 ; i < vectorA.length ; i++) {
          result += vectorA[i]*vectorB[i];
        }
        return result;
      } else {
        throw new Error("Vector mismatch");
      }
    },

    //multiply two matrices
    multiply: function(arrA, arrB) {
      if (arrA[0].length === arrB.length) {
        var result = new Array(arrA.length);

        for (var i = 0 ; i < arrA.length ; i++) {
          result[i] = new Array(arrB[0].length);
        }

        var arrB_T = transpose(arrB);

        for (var i = 0 ; i < result.length ; i++) {
          for (var j = 0 ; j < result[i].length ; j++) {
            result[i][j] = dotproduct(arrA[i],arrB_T[j]);
          }
        }
        return result;
      } else {
        throw new Error("Array mismatch");
      }
    },

    //determinant, only for n x n -> 2 and 3
    determinant: function(m) {
      if ((m.length === 2) && (m[0].length === 2)) {
        return m[0][0] * m[1][1] - m[0][1] * m[1][0];
      } else if ((m.length === 3) && (m[0].length === 3)) {
        return m[0][0] * m[1][1] * m[2][2]
          + m[0][1] * m[1][2] * m[2][0]
          + m[0][2] * m[1][0] * m[2][1]
          - m[0][2] * m[1][1] * m[2][0]
          - m[0][1] * m[1][0] * m[2][2]
          - m[0][0] * m[1][2] * m[2][1];
      }
    }
  },

/*-----------------------------------------------------------------------------*/

  //collection of prime associated tools
  prime: {

    //standard prime evaluation (no consideration towards efficiency)
    simple: function(val) {
      if (val == 1) {
        return false;
      } else if (val == 2) {
        return true;
      } else if (val != null) {
        var start = 2;
        var result = true;
        while (start < val) {
          if (val % start === 0) {
            result = false;
            break;
          } else {
            start++;
          }
        }
        return result;
      }
    },

    //determine primality using elliptic curve testing
    elliptic: function() {
      return null;
    }
  },

/*-----------------------------------------------------------------------------*/

  //statistic oriented tools
  statistic: {

    //get mean value of the numbers in an array
    mean: function(arr) {
      var count = arr.length;
      var sum = addition(arr);
      return sum/count;
    },

    //get median value of the numbers in an array
    median: function(arr) {
      var count = arr.length;
      var middle;
      if (count % 2 === 0) {
        return (arr[count/2] + arr[(count/2 - 1)])/2;
      } else {
        return arr[Math.floor(count / 2)];
      }
    },

    //get mode value (most common value) of the numbers in an array
    mode: function(arr) {
      //sort array
      var maxIndex = 0, maxOccurence = 0, tempIndex = 0, tempOccurence = 0;
      arr = arr.sort();
      while (tempIndex < arr.length) {
        for (var j = tempIndex; j < arr.length; j++) {
          if (arr[j] == arr[tempIndex]) {
            tempOccurence++;
          } else {
            break;
          }
        }
        if (tempOccurence > maxOccurence) {
          maxOccurence = tempOccurence;
          maxIndex = tempIndex;
        }

        tempIndex = j;
        tempOccurence = 0;
      }
      return arr[maxIndex];
    },

    //generate a random sample of n-values within lower/upper bounds
    randomSample: function(lower,upper,n) {
      var sample = new Array();
      var temp;
      for (var i = 0 ; i < n ; i++) {
        temp = Math.random()*upper;
        if (temp > lower)
          sample[i] = temp;
      }
      return sample;
    },

    //standard deviation
    standardDev: function(arr) {
      var count = arr.length;
      var mean = mean(arr);
      var squaredArr = new Array();
      for (var i = 0; i < arr.length; i++) {
        squaredArr[i] = Math.pow((arr[i] - mean),2);
      }
      return Math.sqrt((1/count) * addition(squaredArr));
    },

    //correlation of two arrays
    correlation: function(arrX,arrY) {
      if (arrX.length == arrY.length) {
        var numerator = 0;
        var denominator = (arrX.length) * (standardDev(arrX)) * (standardDev(arrY));
        var xMean = mean(arrX);
        var yMean = mean(arrY);
        for (var i = 0 ; i < arrX.length ; i++) {
          numerator += (arrX[i] - xMean) * (arrY[i] - yMean);
        }
        return numerator / denominator;
      } else {
        throw new Error('Array mismatch');
      }
    }
  }
};<commit_msg>More robust, but still backwards-compatible, evaluate()<commit_after>/*
* numeric.ly
* author: steve kaliski
* last modified: sep 2012
*-----------------------------------------------------------------------------*/

var numeric = {

  //basic addition of vals in an array
  addition: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = 0;
      for (var i = 0 ; i < arr.length ; i++) {
        total = total + arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //subtract items in an array (descending)
  subtraction: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = arr[arr.length - 1];
      for (var i = arr.length - 2; i >= 0; i--) {
        total -= arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //product of items in array
  product: function(arr) {
    if (Object.prototype.toString.call(arr) === '[object Array]') {
      var total = arr[0];
      for (var i = 1; i < arr.length; i++) {
        total = total * arr[i];
      }
      return total;
    } else {
      throw new Error('ERROR: Input must be of type Array');
    }
  },

  //greatest common denominator
  gcd: function(num1, num2) {
    var result;
    if (num1 > num2) {
      for (var i = 0 ; i <= num2 ; i++) {
        if (num2 % i === 0) {
          if (num1 % i === 0) {
            result = i;
          }
        }
      }
      return result;
    } else if (num2 > num1) {
      for (var i = 0 ; i <= num2 ; i++) {
        if (num1 % i === 0) {
          if (num2 % i === 0) {
            result = i;
          }
        }
      }
      return result;
    } else {
      result = num1 * num2 / num1;
      return result;
    }
  },

  //least common multiple
  lcm: function(num1, num2) {
    var result = Math.abs(num1 * num2) / gcd(num1,num2);
    return result;
  },

  //evaluate function at val (func passed as a string)
  evaluate: function(func, val) {
    if(typeof func == 'string') {
      return Math[func.substring(0,func.indexOf('('))](val);
    }
    return func(val);
  },

/*-----------------------------------------------------------------------------*/

  //a variety of calculus tools
  calculus: {

    //function, point at which differentiation occurs (func passed as string)
    pointDiff: function(func, point) {
      var a = evaluate(func, point - .00001);
      var b = evaluate(func, point + .00001);

      return (b - a) / (.00002);
    },

    //calculate riemann integral (left hand) (func passed as string)
    riemann: function(func, start, finish, n) {
      var inc = (finish - start) / n;
      var result = 0;
      for (var i = start; i < finish; i += inc) {
        result += (evaluate(func, i) * inc);
      }
      return result;
    },

    //estimate integral with adaptive simpson quadrature
    simpsonDef: function(func, a, b) {
      var c = (a + b) / 2;
      var d = Math.abs(b - a) / 6;
      return d * (evaluate(func, a) + 4 * evaluate(func, c) + evaluate(func, b));
    },
    simpsonRecursive: function(func, a, b, eps, whole) {
      var c = a + b;
      var left = simpsonDef(func, a, c);
      var right = simpsonDef(func, c, b);
      if (Math.abs(left + right - whole) <= 15 * eps) {
        return left + right + (left + right - whole) / 15;
      } else {
        return simpsonRecursive(func, a, c, eps/2, left) + simpsonRecursive(func, c, b, eps / 2, right);
      }
    },
    //execute this
    adaptiveSimpson: function(func, a, b, eps) {
      return simpsonRecursive(func, a, b, eps, simpsonDef(func, a, b));
    },

    //take the limit of a function (left, middle, or right)
    limit: function(func, point, approach) {
      if (approach === 'left') {
        return evaluate(func, point - .001);
      } else if (approach === 'right') {
        return evaluate(func, point + .001);
      } else if (approach === 'middle') {
        return (limit(func, point, 'left') + limit(func, point, 'right')) / 2;
      } else {
        throw new Error('Approach not provided');
      }
    },

    //return taylor polynomial for function (func) at point (point) to degree (degree: 0, 1 and 2 for now)
    taylor: function(func, point, degree) {
      if (degree == 0) {

      } else if (degree == 1) {

      } else if (degree == 2) {

      }
    },

    //integrate taylor polynomial for some func
    polyIntegrate: function(func) {
      var taylor = taylor(func, 0, 8);
    }
  },

/*-----------------------------------------------------------------------------*/

  /*
  a variety of matrix analysis tools

  let's consider the matrix A:

  [1 2 3]
  [4 5 6]

  As input, set arg = [[1,2,3],[4,5,6]];

  Note: The "structure" of matrices may be neglected in some calculations,
  however in and transformation, mapping, etc, we recognize the proper
  format.
  */
  matrix: {

    //add two arrays (arrA and arrB)
    addition: function(arrA, arrB) {
      if ((arrA.length === arrB.length) && (arrA[0].length === arrB[0].length)) {
        var result = new Array(arrA.length);
        for (var i = 0; i < arrA.length; i++) {
          result[i] = new Array(arrA[i].length);
          for (var j = 0; j < arrA[i].length; j++) {
            result[i][j] = arrA[i][j] + arrB[i][j];
          }
        }
        return result;
      } else {
        throw new Error('Array mismatch');
      }
    },

    //multiple array (arr) by a scalar (val)
    scalar: function(arr,val) {
      for (var i = 0; i < arr.length; i++) {
        for (var j = 0; j < arr[i].length; j++) {
          arr[i][j] = val * arr[i][j];
        }
      }
      return arr;
    },

    //transpose array
    transpose: function(arr) {
      var result = new Array(arr[0].length);
      for (var i = 0; i < arr[0].length; i++) {
        result[i] = new Array(arr.length);
        for (var j = 0; j < arr.length; j++){
          result[i][j] = arr[j][i];
        }
      }
      return result;
    },

    //return identity matrix of dimension n x n
    identity: function(n) {
      var result = new Array(n);
      for (var i = 0 ; i < n ; i++) {
        result[i] = new Array(n);
        for (var j = 0 ; j < n ; j++) {
          result[i][j] = (i === j) ? 1 : 0;
        }
      }
      return result;
    },

    //dot product
    dotproduct: function(vectorA, vectorB) {
      if (vectorA.length === vectorB.length) {
        var result = 0;
        for (var i = 0 ; i < vectorA.length ; i++) {
          result += vectorA[i]*vectorB[i];
        }
        return result;
      } else {
        throw new Error("Vector mismatch");
      }
    },

    //multiply two matrices
    multiply: function(arrA, arrB) {
      if (arrA[0].length === arrB.length) {
        var result = new Array(arrA.length);

        for (var i = 0 ; i < arrA.length ; i++) {
          result[i] = new Array(arrB[0].length);
        }

        var arrB_T = transpose(arrB);

        for (var i = 0 ; i < result.length ; i++) {
          for (var j = 0 ; j < result[i].length ; j++) {
            result[i][j] = dotproduct(arrA[i],arrB_T[j]);
          }
        }
        return result;
      } else {
        throw new Error("Array mismatch");
      }
    },

    //determinant, only for n x n -> 2 and 3
    determinant: function(m) {
      if ((m.length === 2) && (m[0].length === 2)) {
        return m[0][0] * m[1][1] - m[0][1] * m[1][0];
      } else if ((m.length === 3) && (m[0].length === 3)) {
        return m[0][0] * m[1][1] * m[2][2]
          + m[0][1] * m[1][2] * m[2][0]
          + m[0][2] * m[1][0] * m[2][1]
          - m[0][2] * m[1][1] * m[2][0]
          - m[0][1] * m[1][0] * m[2][2]
          - m[0][0] * m[1][2] * m[2][1];
      }
    }
  },

/*-----------------------------------------------------------------------------*/

  //collection of prime associated tools
  prime: {

    //standard prime evaluation (no consideration towards efficiency)
    simple: function(val) {
      if (val == 1) {
        return false;
      } else if (val == 2) {
        return true;
      } else if (val != null) {
        var start = 2;
        var result = true;
        while (start < val) {
          if (val % start === 0) {
            result = false;
            break;
          } else {
            start++;
          }
        }
        return result;
      }
    },

    //determine primality using elliptic curve testing
    elliptic: function() {
      return null;
    }
  },

/*-----------------------------------------------------------------------------*/

  //statistic oriented tools
  statistic: {

    //get mean value of the numbers in an array
    mean: function(arr) {
      var count = arr.length;
      var sum = addition(arr);
      return sum/count;
    },

    //get median value of the numbers in an array
    median: function(arr) {
      var count = arr.length;
      var middle;
      if (count % 2 === 0) {
        return (arr[count/2] + arr[(count/2 - 1)])/2;
      } else {
        return arr[Math.floor(count / 2)];
      }
    },

    //get mode value (most common value) of the numbers in an array
    mode: function(arr) {
      //sort array
      var maxIndex = 0, maxOccurence = 0, tempIndex = 0, tempOccurence = 0;
      arr = arr.sort();
      while (tempIndex < arr.length) {
        for (var j = tempIndex; j < arr.length; j++) {
          if (arr[j] == arr[tempIndex]) {
            tempOccurence++;
          } else {
            break;
          }
        }
        if (tempOccurence > maxOccurence) {
          maxOccurence = tempOccurence;
          maxIndex = tempIndex;
        }

        tempIndex = j;
        tempOccurence = 0;
      }
      return arr[maxIndex];
    },

    //generate a random sample of n-values within lower/upper bounds
    randomSample: function(lower,upper,n) {
      var sample = new Array();
      var temp;
      for (var i = 0 ; i < n ; i++) {
        temp = Math.random()*upper;
        if (temp > lower)
          sample[i] = temp;
      }
      return sample;
    },

    //standard deviation
    standardDev: function(arr) {
      var count = arr.length;
      var mean = mean(arr);
      var squaredArr = new Array();
      for (var i = 0; i < arr.length; i++) {
        squaredArr[i] = Math.pow((arr[i] - mean),2);
      }
      return Math.sqrt((1/count) * addition(squaredArr));
    },

    //correlation of two arrays
    correlation: function(arrX,arrY) {
      if (arrX.length == arrY.length) {
        var numerator = 0;
        var denominator = (arrX.length) * (standardDev(arrX)) * (standardDev(arrY));
        var xMean = mean(arrX);
        var yMean = mean(arrY);
        for (var i = 0 ; i < arrX.length ; i++) {
          numerator += (arrX[i] - xMean) * (arrY[i] - yMean);
        }
        return numerator / denominator;
      } else {
        throw new Error('Array mismatch');
      }
    }
  }
};<|endoftext|>


<commit_before>
var operations = {
	c: { name: 'crop', file: 'crop' },
	f: { name: 'focal', file: 'focal' },
	t: { name: 'thumb', file: 'thumb' },
	r: { name: 'resize', file: 'resize' },
	q: { name: 'quality', file: 'quality' },
	fmt: { name: 'format', file: 'format' },
	rot: { name: 'rotate', file: 'rotate' },
	flp: { name: 'flip', file: 'flip' },
	blr: { name: 'blur', file: 'filters/blur' },
	bri: { name: 'brightness', file: 'filters/brightness' },
	con: { name: 'contrast', file: 'filters/contrast' },
	exp: { name: 'exposure', file: 'filters/exposure' },
	gam: { name: 'gamma', file: 'filters/gamma' },
	hig: { name: 'highlights', file: 'filters/highlights' },
	hue: { name: 'hue', file: 'filters/hue' },
	inv: { name: 'invert', file: 'filters/invert' },
	sat: { name: 'saturation', file: 'filters/saturation' },
	sha: { name: 'shadows', file: 'filters/shadows' },
	shp: { name: 'sharpness', file: 'filters/sharpness' },
	vib: { name: 'vibrance', file: 'filters/vibrance' }
};

module.exports = { byKey: { }, byName: { } };
Object.keys(operations).forEach(function (key) {
	var info = operations[key];
	var run = require('./operations/' + info.file);
	var object = { key: key, name: info.name, run: run };
	module.exports.byKey[key] = object;
	module.exports.byName[info.name] = object;
});<commit_msg>Changed focal to "foc". Changed format to "f".<commit_after>
var operations = {
	c: { name: 'crop', file: 'crop' },
	t: { name: 'thumb', file: 'thumb' },
	r: { name: 'resize', file: 'resize' },
	q: { name: 'quality', file: 'quality' },
	f: { name: 'format', file: 'format' },
	foc: { name: 'focal', file: 'focal' },
	rot: { name: 'rotate', file: 'rotate' },
	flp: { name: 'flip', file: 'flip' },
	blr: { name: 'blur', file: 'filters/blur' },
	bri: { name: 'brightness', file: 'filters/brightness' },
	con: { name: 'contrast', file: 'filters/contrast' },
	exp: { name: 'exposure', file: 'filters/exposure' },
	gam: { name: 'gamma', file: 'filters/gamma' },
	hig: { name: 'highlights', file: 'filters/highlights' },
	hue: { name: 'hue', file: 'filters/hue' },
	inv: { name: 'invert', file: 'filters/invert' },
	sat: { name: 'saturation', file: 'filters/saturation' },
	sha: { name: 'shadows', file: 'filters/shadows' },
	shp: { name: 'sharpness', file: 'filters/sharpness' },
	vib: { name: 'vibrance', file: 'filters/vibrance' }
};

module.exports = { byKey: { }, byName: { } };
Object.keys(operations).forEach(function (key) {
	var info = operations[key];
	var run = require('./operations/' + info.file);
	var object = { key: key, name: info.name, run: run };
	module.exports.byKey[key] = object;
	module.exports.byName[info.name] = object;
});<|endoftext|>


<commit_before>var http = require('http')
var Filter = require('./resource_filter')

module.exports = function (model, options) {
  var buildQuery = require('./buildQuery')(options)
  var filter = new Filter(model, {
    private: options.private,
    protected: options.protected
  })
  var contextFilter

  if (options.contextFilter) {
    contextFilter = options.contextFilter
  } else {
    contextFilter = function (model, req, done) {
      done(model)
    }
  }

  function findById (filteredContext, id) {
    var byId = {}
    byId[options.idProperty] = id
    return filteredContext.findOne().and(byId)
  }

  function getItems (req, res, next) {
    contextFilter(model, req, function (filteredContext) {
      buildQuery(filteredContext.find(), req._ermQueryOptions).lean(options.lean).exec(function (err, items) {
        if (err) {
          err.statusCode = 400
          return options.onError(err, req, res, next)
        }

        var populate = req._ermQueryOptions.populate
        var opts = {
          populate: populate,
          access: req.access
        }

        items = filter.filterObject(items, opts)

        req._ermResult = items
        req._ermStatusCode = 200

        next()
      })
    })
  }

  function getCount (req, res, next) {
    contextFilter(model, req, function (filteredContext) {
      buildQuery(filteredContext.count(), req._ermQueryOptions).exec(function (err, count) {
        if (err) {
          err.statusCode = 400
          return options.onError(err, req, res, next)
        }

        req._ermResult = { count: count }
        req._ermStatusCode = 200

        next()
      })
    })
  }

  function getShallow (req, res, next) {
    contextFilter(model, req, function (filteredContext) {
      buildQuery(findById(filteredContext, req.params.id), req._ermQueryOptions).lean(options.lean).exec(function (err, item) {
        if (err) {
          err.statusCode = 400
          return options.onError(err, req, res, next)
        }

        if (!item) {
          err = new Error(http.STATUS_CODES[404])
          err.statusCode = 404
          return options.onError(err, req, res, next)
        }

        var populate = req._ermQueryOptions.populate
        var opts = {
          populate: populate,
          access: req.access
        }

        item = filter.filterObject(item, opts)

        for (var prop in item) {
          item[prop] = typeof item[prop] === 'object' && prop !== '_id' ? true : item[prop]
        }

        req._ermResult = item
        req._ermStatusCode = 200

        next()
      })
    })
  }

  function deleteItems (req, res, next) {
    contextFilter(model, req, function (filteredContext) {
      buildQuery(filteredContext.find(), req._ermQueryOptions).remove(function (err, items) {
        if (err) {
          err.statusCode = 400
          return options.onError(err, req, res, next)
        }

        req._ermStatusCode = 204

        next()
      })
    })
  }

  function getItem (req, res, next) {
    contextFilter(model, req, function (filteredContext) {
      buildQuery(findById(filteredContext, req.params.id), req._ermQueryOptions).lean(options.lean).exec(function (err, item) {
        if (err) {
          err.statusCode = 400
          return options.onError(err, req, res, next)
        }

        if (!item) {
          err = new Error(http.STATUS_CODES[404])
          err.statusCode = 404
          return options.onError(err, req, res, next)
        }

        var populate = req._ermQueryOptions.populate
        var opts = {
          populate: populate,
          access: req.access
        }

        item = filter.filterObject(item, opts)

        req._ermResult = item
        req._ermStatusCode = 200

        next()
      })
    })
  }

  function deleteItem (req, res, next) {
    var byId = {}
    byId[options.idProperty] = req.params.id

    if (options.findOneAndRemove) {
      contextFilter(model, req, function (filteredContext) {
        findById(filteredContext, req.params.id).findOneAndRemove(function (err, doc) {
          if (err) {
            err.statusCode = 400
            return options.onError(err, req, res, next)
          }

          if (!doc) {
            err = new Error(http.STATUS_CODES[404])
            err.statusCode = 404
            return options.onError(err, req, res, next)
          }

          req._ermStatusCode = 204

          next()
        })
      })
    } else {
      contextFilter(model, req, function (filteredContext) {
        findById(filteredContext, req.params.id).exec(function (err, doc) {
          if (err) {
            err.statusCode = 400
            return options.onError(err, req, res, next)
          }

          if (!doc) {
            err = new Error(http.STATUS_CODES[404])
            err.statusCode = 404
            return options.onError(err, req, res, next)
          }

          doc.remove(function (err, result) {
            if (err) {
              err.statusCode = 400
              return options.onError(err, req, res, next)
            }

            req._ermStatusCode = 204

            next()
          })
        })
      })
    }
  }

  function createObject (req, res, next) {
    var filterOpts = {
      access: req.access
    }

    req.body = filter.filterObject(req.body || {}, filterOpts)

    if (model.schema.options._id) {
      delete req.body._id
    }

    if (model.schema.options.versionKey) {
      delete req.body[model.schema.options.versionKey]
    }

    model.create(req.body, function (err, item) {
      if (err) {
        err.statusCode = 400
        return options.onError(err, req, res, next)
      }

      item = filter.filterObject(item, filterOpts)

      req._ermResult = item
      req._ermStatusCode = 201

      next()
    })
  }

  function modifyObject (req, res, next) {
    var filterOpts = {
      access: req.access
    }

    req.body = filter.filterObject(req.body || {}, filterOpts)
    delete req.body._id

    if (model.schema.options.versionKey) {
      delete req.body[model.schema.options.versionKey]
    }

    if (options.findOneAndUpdate) {
      contextFilter(model, req, function (filteredContext) {
        findById(filteredContext, req.params.id).findOneAndUpdate({}, req.body, {
          new: true,
          runValidators: options.runValidators
        }, function (err, item) {
          if (err) {
            err.statusCode = 400
            return options.onError(err, req, res, next)
          }

          if (!item) {
            err = new Error(http.STATUS_CODES[404])
            err.statusCode = 404
            return options.onError(err, req, res, next)
          }

          item = filter.filterObject(item, filterOpts)

          req._ermResult = item
          req._ermStatusCode = 200

          next()
        })
      })
    } else {
      contextFilter(model, req, function (filteredContext) {
        findById(filteredContext, req.params.id).exec(function (err, doc) {
          if (err) {
            err.statusCode = 400
            return options.onError(err, req, res, next)
          }

          if (!doc) {
            err = new Error(http.STATUS_CODES[404])
            err.statusCode = 404
            return options.onError(err, req, res, next)
          }

          for (var key in req.body) {
            doc.set(key, req.body[key])
          }

          doc.save(function (err, item) {
            if (err) {
              err.statusCode = 400
              return options.onError(err, req, res, next)
            }

            item = filter.filterObject(item, filterOpts)

            req._ermResult = item
            req._ermStatusCode = 200

            next()
          })
        })
      })
    }
  }

  return {
    getItems: getItems,
    getCount: getCount,
    getItem: getItem,
    getShallow: getShallow,
    createObject: createObject,
    modifyObject: modifyObject,
    deleteItems: deleteItems,
    deleteItem: deleteItem
  }
}
<commit_msg>wip(ops): incomplete fix for update<commit_after>var _ = require('lodash')
var http = require('http')
var Filter = require('./resource_filter')

module.exports = function (model, options) {
  var buildQuery = require('./buildQuery')(options)
  var filter = new Filter(model, {
    private: options.private,
    protected: options.protected
  })
  var contextFilter

  if (options.contextFilter) {
    contextFilter = options.contextFilter
  } else {
    contextFilter = function (model, req, done) {
      done(model)
    }
  }

  function findById (filteredContext, id) {
    var byId = {}
    byId[options.idProperty] = id
    return filteredContext.findOne().and(byId)
  }

  function getItems (req, res, next) {
    contextFilter(model, req, function (filteredContext) {
      buildQuery(filteredContext.find(), req._ermQueryOptions).lean(options.lean).exec(function (err, items) {
        if (err) {
          err.statusCode = 400
          return options.onError(err, req, res, next)
        }

        var populate = req._ermQueryOptions.populate
        var opts = {
          populate: populate,
          access: req.access
        }

        items = filter.filterObject(items, opts)

        req._ermResult = items
        req._ermStatusCode = 200

        next()
      })
    })
  }

  function getCount (req, res, next) {
    contextFilter(model, req, function (filteredContext) {
      buildQuery(filteredContext.count(), req._ermQueryOptions).exec(function (err, count) {
        if (err) {
          err.statusCode = 400
          return options.onError(err, req, res, next)
        }

        req._ermResult = { count: count }
        req._ermStatusCode = 200

        next()
      })
    })
  }

  function getShallow (req, res, next) {
    contextFilter(model, req, function (filteredContext) {
      buildQuery(findById(filteredContext, req.params.id), req._ermQueryOptions).lean(options.lean).exec(function (err, item) {
        if (err) {
          err.statusCode = 400
          return options.onError(err, req, res, next)
        }

        if (!item) {
          err = new Error(http.STATUS_CODES[404])
          err.statusCode = 404
          return options.onError(err, req, res, next)
        }

        var populate = req._ermQueryOptions.populate
        var opts = {
          populate: populate,
          access: req.access
        }

        item = filter.filterObject(item, opts)

        for (var prop in item) {
          item[prop] = typeof item[prop] === 'object' && prop !== '_id' ? true : item[prop]
        }

        req._ermResult = item
        req._ermStatusCode = 200

        next()
      })
    })
  }

  function deleteItems (req, res, next) {
    contextFilter(model, req, function (filteredContext) {
      buildQuery(filteredContext.find(), req._ermQueryOptions).remove(function (err, items) {
        if (err) {
          err.statusCode = 400
          return options.onError(err, req, res, next)
        }

        req._ermStatusCode = 204

        next()
      })
    })
  }

  function getItem (req, res, next) {
    contextFilter(model, req, function (filteredContext) {
      buildQuery(findById(filteredContext, req.params.id), req._ermQueryOptions).lean(options.lean).exec(function (err, item) {
        if (err) {
          err.statusCode = 400
          return options.onError(err, req, res, next)
        }

        if (!item) {
          err = new Error(http.STATUS_CODES[404])
          err.statusCode = 404
          return options.onError(err, req, res, next)
        }

        var populate = req._ermQueryOptions.populate
        var opts = {
          populate: populate,
          access: req.access
        }

        item = filter.filterObject(item, opts)

        req._ermResult = item
        req._ermStatusCode = 200

        next()
      })
    })
  }

  function deleteItem (req, res, next) {
    var byId = {}
    byId[options.idProperty] = req.params.id

    if (options.findOneAndRemove) {
      contextFilter(model, req, function (filteredContext) {
        findById(filteredContext, req.params.id).findOneAndRemove(function (err, doc) {
          if (err) {
            err.statusCode = 400
            return options.onError(err, req, res, next)
          }

          if (!doc) {
            err = new Error(http.STATUS_CODES[404])
            err.statusCode = 404
            return options.onError(err, req, res, next)
          }

          req._ermStatusCode = 204

          next()
        })
      })
    } else {
      contextFilter(model, req, function (filteredContext) {
        findById(filteredContext, req.params.id).exec(function (err, doc) {
          if (err) {
            err.statusCode = 400
            return options.onError(err, req, res, next)
          }

          if (!doc) {
            err = new Error(http.STATUS_CODES[404])
            err.statusCode = 404
            return options.onError(err, req, res, next)
          }

          doc.remove(function (err, result) {
            if (err) {
              err.statusCode = 400
              return options.onError(err, req, res, next)
            }

            req._ermStatusCode = 204

            next()
          })
        })
      })
    }
  }

  function createObject (req, res, next) {
    var filterOpts = {
      access: req.access
    }

    req.body = filter.filterObject(req.body || {}, filterOpts)

    if (model.schema.options._id) {
      delete req.body._id
    }

    if (model.schema.options.versionKey) {
      delete req.body[model.schema.options.versionKey]
    }

    model.create(req.body, function (err, item) {
      if (err) {
        err.statusCode = 400
        return options.onError(err, req, res, next)
      }

      item = filter.filterObject(item, filterOpts)

      req._ermResult = item
      req._ermStatusCode = 201

      next()
    })
  }

  function modifyObject (req, res, next) {
    var filterOpts = {
      access: req.access
    }

    req.body = filter.filterObject(req.body || {}, filterOpts)
    delete req.body._id

    if (model.schema.options.versionKey) {
      delete req.body[model.schema.options.versionKey]
    }

    function depopulate (src, dst) {
      dst = dst || {}

      for (var key in src) {
        var path = model.schema.path(key)

        if (typeof path === 'undefined') {
          continue
        }

        if (path.caster !== undefined) {
          if (path.caster.instance === 'ObjectID') {
            if (_.isArray(src[key])) {
              for (var j = 0; j < src[key].length; ++j) {
                if (typeof src[key][j] === 'object') {
                  dst[key][j] = src[key][j]._id
                }
              }
            } else if ((typeof src[key] === 'object') && (src[key] !== null)) {
              dst[key] = src[key]._id
            }
          }
        } else if (_.isPlainObject(src[key])) {
          if (path.instance === 'ObjectID') {
            dst[key] = src[key]._id
          } else {
            depopulate(src, dst)
          }
        } else {
          dst[key] = src[key]
        }
      }

      return dst
    }

    function flatten (src, dst, prefix) {
      dst = dst || {}
      prefix = prefix || ''

      for (var key in src) {
        if (_.isPlainObject(src[key])) {
          flatten(src[key], dst, prefix + key + '.')
        } else {
          dst[prefix + key] = src[key]
        }
      }

      return dst
    }

    var cleanBody = flatten(depopulate(req.body))

    if (options.findOneAndUpdate) {
      contextFilter(model, req, function (filteredContext) {
        findById(filteredContext, req.params.id).findOneAndUpdate({}, {
          $set: cleanBody
        }, {
          new: true,
          runValidators: options.runValidators
        }, function (err, item) {
          if (err) {
            err.statusCode = 400
            return options.onError(err, req, res, next)
          }

          if (!item) {
            err = new Error(http.STATUS_CODES[404])
            err.statusCode = 404
            return options.onError(err, req, res, next)
          }

          item = filter.filterObject(item, filterOpts)

          req._ermResult = item
          req._ermStatusCode = 200

          next()
        })
      })
    } else {
      contextFilter(model, req, function (filteredContext) {
        findById(filteredContext, req.params.id).exec(function (err, doc) {
          if (err) {
            err.statusCode = 400
            return options.onError(err, req, res, next)
          }

          if (!doc) {
            err = new Error(http.STATUS_CODES[404])
            err.statusCode = 404
            return options.onError(err, req, res, next)
          }

          for (var key in cleanBody) {
            doc.set(key, cleanBody[key])
          }

          doc.save(function (err, item) {
            if (err) {
              err.statusCode = 400
              return options.onError(err, req, res, next)
            }

            item = filter.filterObject(item, filterOpts)

            req._ermResult = item
            req._ermStatusCode = 200

            next()
          })
        })
      })
    }
  }

  return {
    getItems: getItems,
    getCount: getCount,
    getItem: getItem,
    getShallow: getShallow,
    createObject: createObject,
    modifyObject: modifyObject,
    deleteItems: deleteItems,
    deleteItem: deleteItem
  }
}
<|endoftext|>


<commit_before>//= require_tree ./templates

var App = Ember.Application.create({
  rootElement: '#builds-application'
});

App.Router.map(function() {
  this.route('release');
  this.route('beta');
  this.route('canary');
  this.route('tagged');
});

App.Router.reopen({
  notifyGoogleAnalytics: function() {
    var url = this.get('url');

    // Add a slash if neccesary
    if (!/^\//.test(url)){ url = '/' + url; }

    _gaq.push(['_trackPageview', '/builds' + url]);
  }.on('didTransition')
});

App.CopyClipboardComponent = Ember.Component.extend({
  tagName: 'span',
  hasFlash: ZeroClipboard.detectFlashSupport(),

  didInsertElement: function () {
    var clip = new ZeroClipboard(this.$('button'), {
      // This would normally be a relative path
      moviePath: "/images/ZeroClipboard.swf",

      trustedDomains: ["*"],
      allowScriptAccess: "always"
    });

    clip.on('mousedown', function(client, e) {
      Em.run.later(this, function() {
        $(this).removeClass('loading');
        $(this).removeAttr('disabled');
      }, 1000);
      Em.run.next(this, function() {
        $(this).addClass('loading');
        $(this).attr('disabled', 'disabled');
      });
    });

    this.$('input').on('click', function() {
      $(this).select();
    });
  }
});

App.S3Bucket = Ember.Object.extend({
  files: [],
  isLoading: false,

  // Setup these as default values.
  // They can be overridden on create.
  queryUseSSL: true,
  objectUseSSL: false,
  delimiter: '/',
  bucket: 'builds.emberjs.com',
  endpoint: 's3.amazonaws.com',

  delimiterParameter: function(){
    var delimiter = this.getWithDefault('delimiter','').toString();
    return (delimiter) ? 'delimiter=' + delimiter : '';
  }.property('delimiter'),

  markerParameter: function(){
    return 'marker=' + this.getWithDefault('marker','').toString();
  }.property('marker'),

  maxKeysParameter: function(){
    return 'max-keys=' + this.getWithDefault('maxKeys','').toString();
  }.property('maxKeys'),

  prefixParameter: function(){
    return 'prefix=' + this.getWithDefault('prefix','').toString();
  }.property('prefix'),

  queryProtocol: function() {
    return this.get('queryUseSSL') ? 'https://' : 'http://';
  }.property('queryUseSSL'),

  queryBaseUrl: function(){
    return this.get('queryProtocol') + this.get('endpoint') + '/' + this.get('bucket')
  }.property('queryProtocol', 'endpoint', 'bucket'),

  objectProtocol: function() {
    return this.get('objectUseSSL') ? 'https://' : 'http://';
  }.property('objectUseSSL'),

  objectBaseUrl: function(){
    return this.get('objectProtocol') + this.get('bucket');
  }.property('objectProtocol', 'bucket'),

  queryParams: function(){
    return this.get('delimiterParameter')  + '&' +
      this.get('markerParameter')     + '&' +
      this.get('maxKeysParameter')    + '&' +
      this.get('prefixParameter');
  }.property('delimiterParameter','markerParameter','maxKeysParameter','prefixParameter'),

  queryUrl: function(){
    return this.get('queryBaseUrl') + '?' + this.get('queryParams');
  }.property('queryBaseUrl','queryParams'),

  filesPresent: function(){
    return this.get('files').length;
  }.property('files.@each'),

  filterFiles: function(filter){
    var files = this.get('files');

    return files.filter(function(e) {
      return e.get('name').indexOf(filter + '.') !== -1;
    });
  },

  load: function(){
    var self = this,
    baseUrl = this.get('objectBaseUrl');

    this.set('isLoading', true);
    Ember.$.get(this.get('queryUrl'), function(data){
      self.set('isLoading', false);
      self.set('response', data);

      var contents = data.getElementsByTagName('Contents'),
      length   = contents.length,
      files    = [];

      for(var i = 0; i < length; i++) {
        var size = contents[i].getElementsByTagName('Size')[0].firstChild.data,
        name = contents[i].getElementsByTagName('Key')[0].firstChild.data,
        lastModified = new Date(contents[i].getElementsByTagName('LastModified')[0].firstChild.data);

        files.push(
          App.S3File.create({
          name: name,
          size: size,
          lastModified: lastModified,
          relativePath: name,
          baseUrl: baseUrl
        })
        );
      }

      self.set('files', files.sort(function(a,b){
        return b.lastModified - a.lastModified;
      }));
    });
  }.observes('queryUrl').on('init')
});

App.S3File = Ember.Object.extend({
  scriptTag: function(){
    var escapedURL = Handlebars.Utils.escapeExpression(this.get('url'));

    return new Handlebars.SafeString('<script src="' + escapedURL + '"></script>').toString();
  }.property('url'),

  url: function(){
    return this.get('baseUrl') + '/' + this.get('relativePath');
  }.property('baseUrl', 'relativePath')
});

App.Project = Ember.Object.extend();

App.Project.reopenClass({
  FIXTURES:
    [ {
      projectName: 'Ember',
      projectFilter: 'ember',
      projectRepo: 'emberjs/ember.js',
      channel: "tagged"
    }, {
      projectName: 'Ember Data',
      projectFilter: 'ember-data',
      projectRepo: 'emberjs/data',
      channel: "tagged"
    }, {
      projectName: "Ember",
      projectFilter: "ember",
      projectRepo: 'emberjs/ember.js',
      initialVersion: "1.9.0",
      initialReleaseDate: "2014-12-08",
      lastRelease: "1.9.0",
      futureVersion: "1.9.1",
      channel: "release",
      date: "2014-12-08",
      changelogPath: "CHANGELOG.md",
      enableTestURL: true
    }, {
      projectName: "Ember",
      projectFilter: "ember",
      projectRepo: 'emberjs/ember.js',
      lastRelease: "1.10.0-beta.1",
      futureVersion: "1.9.0-beta.2",
      finalVersion: '1.10.0',
      channel: "beta",
      cycleEstimatedFinishDate: '2015-02-23',
      date: "2014-12-10",
      nextDate: "2014-12-17",
      changelogPath: "CHANGELOG.md",
      enableTestURL: true
    }, {
      projectName: "Ember Data",
      projectFilter: "ember-data",
      projectRepo: 'emberjs/data',
      lastRelease: "1.0.0-beta.12",
      futureVersion: "1.0.0-beta.13",
      channel: "beta",
      date: "2014-11-26",
      changelogPath: "CHANGELOG.md"
    }, {
      projectName: "Ember",
      projectFilter: "ember",
      projectRepo: 'emberjs/ember.js',
      channel: "canary",
      enableTestURL: true
    }, {
      projectName: "Ember Data",
      projectFilter: "ember-data",
      projectRepo: 'emberjs/data',
      channel: "canary",
    }],

  all: function(channel){
    var projects;

    if (channel)
      projects = this.FIXTURES.filterBy('channel', channel);
    else
      projects = this.FIXTURES;

    return projects.map(function(obj) {
      return App.Project.create(obj);
    });
  },

  find: function(channel, name) {
    var allProjects = this.all(channel);

    if (!name)
      return allProjects;
    else
      return allProjects.filterBy('projectName', name);
  }
});

App.BuildCategoryMixin = Ember.Mixin.create({
  renderTemplate: function() {
    this.render('build-list');
  }
});

App.ApplicationController = Ember.ObjectController.extend({
  isIndexActive: function(){
    return this.isActiveChannel('index');
  }.property('currentRouteName'),

  isTaggedActive: function(){
    return this.isActiveChannel('tagged');
  }.property('currentRouteName'),

  isChannelsActive: function(){
    var self = this;
    return !['index','tagged'].some(function(name){ return name === self.get('currentRouteName'); })
  }.property('currentRouteName'),

  isReleaseActive: function(){
    return this.isActiveChannel('release');
  }.property('currentRouteName'),

  isBetaActive: function(){
    return this.isActiveChannel('beta');
  }.property('currentRouteName'),

  isCanaryActive: function(){
    return this.isActiveChannel('canary');
  }.property('currentRouteName'),

  isActiveChannel: function(channel){
    return this.get('currentRouteName').indexOf(channel) !== -1;
  }
});

App.ProjectsMixin = Ember.Mixin.create({
  projects: function(){
    var projects = App.Project.find(this.get('channel')),
        bucket   = this.get('model'),
        self = this;

    projects.forEach(function(project){
      if (project.channel === 'beta'){
        project.isEmberBeta = project.projectName === 'Ember';

        [1,2,3,4,5].forEach(function(increment){
          var versionParts = project.lastRelease.split('.');
          var currentBetaNumber = parseInt(versionParts[versionParts.length - 1], 10);
          project['beta' + increment + 'Completed'] = increment <= currentBetaNumber;
          project['isBeta' + increment] = increment === currentBetaNumber;
        });

        var release = App.Project.find('release', project.projectName)[0];

        // no releases exist for ember-data (yet)
        if (release) {
          project.lastStableVersion = release.initialVersion;
          project.lastStableDate = release.initialReleaseDate;
        }
      }

      project.files = bucket.filterFiles(project.projectFilter);
      project.description = self.description(project);
      project.lastReleaseDebugUrl = self.lastReleaseUrl(project.projectFilter, project.channel, project.lastRelease, '.js');
      project.lastReleaseProdUrl  = self.lastReleaseUrl(project.projectFilter, project.channel, project.lastRelease, '.prod.js');
      project.lastReleaseMinUrl   = self.lastReleaseUrl(project.projectFilter, project.channel, project.lastRelease, '.min.js');

      if (project.enableTestURL) {
        project.lastReleaseTestUrl  = self.lastReleaseUrl(project.projectFilter, project.channel, project.lastRelease, '-tests-index.html');
      }

      if (project.channel === 'canary')
        project.lastRelease = 'latest';
      else if (project.changelog !== 'false')
        project.lastReleaseChangelogUrl   = 'https://github.com/' + project.projectRepo + '/blob/v' + project.lastRelease + '/' + project.changelogPath;
    });

    return projects;
  }.property('channel', 'model'),

  description: function(project){
    var lastRelease = project.lastRelease,
        futureVersion = project.futureVersion,
        value;

    if (this.get('channel') === 'tagged') {
      value = '';
    } else if (lastRelease) {
      value = 'The builds listed below are incremental improvements made since ' + lastRelease + ' and may become ' + futureVersion + '.'
    } else if (futureVersion) {
      value = 'The builds listed below are not based on a tagged release. Upon the next release cycle they will become ' + futureVersion + '.';
    } else {
      value = 'The builds listed below are based on the most recent development.';
    }

    return new Handlebars.SafeString(value);
  },

  lastReleaseUrl: function(project, channel, lastRelease, extension){
    if (channel === 'canary')
      return 'http://builds.emberjs.com/canary/' + project + extension;
    else
      return 'http://builds.emberjs.com/tags/v' + lastRelease + '/' + project + extension;
  }

});

App.CanaryRoute = Ember.Route.extend(App.BuildCategoryMixin, {
  model: function() {
    return App.S3Bucket.create({title: 'Canary Builds', prefix: 'canary/' });
  }
});

App.CanaryController = Ember.ObjectController.extend(App.ProjectsMixin, {
  templateName: 'buildList',
  channel: 'canary'
});

App.BetaRoute = Ember.Route.extend(App.BuildCategoryMixin, {
  model: function() {
    return App.S3Bucket.create({title: 'Beta Builds', prefix: 'beta/'});
  }
});

App.BetaController = Ember.ObjectController.extend(App.ProjectsMixin, {
  templateName: 'buildList',
  channel: 'beta'
});

App.ReleaseRoute = Ember.Route.extend(App.BuildCategoryMixin, {
  model: function() {
    return App.S3Bucket.create({title: 'Release Builds', prefix: 'release/'});
  }
});

App.ReleaseController = Ember.ObjectController.extend(App.ProjectsMixin, {
  templateName: 'buildList',
  channel: 'release'
});

App.TaggedRoute = Ember.Route.extend(App.BuildCategoryMixin, {
  model: function() {
    var bucket = App.S3Bucket.create({
      title: 'Tagged Release Builds',
      prefix: 'tags/',
      delimiter: '',
    });
    return bucket;
  }
});

App.TaggedController = Ember.ObjectController.extend(App.ProjectsMixin, {
  channel: 'tagged'
});
/*
 * Handlebars Helpers
 */
Ember.Handlebars.helper('format-bytes', function(bytes){
  return (bytes / 1024).toFixed(2) + ' KB';
});

Ember.Handlebars.helper('format-date-time', function(date, format, options) {
  if (!options) {
    options = format;
    format = null;
  }

  if (format){
    return moment(date).format(format);
  } else {
    return moment(date).fromNow();
  }
});

Ember.Handlebars.helper('isHiDPIScreen', function() {
  return window.getDevicePixelRatio() > 1;
});
<commit_msg>Use ember.debug.js for beta/canary build at `/builds`<commit_after>//= require_tree ./templates

var App = Ember.Application.create({
  rootElement: '#builds-application'
});

App.Router.map(function() {
  this.route('release');
  this.route('beta');
  this.route('canary');
  this.route('tagged');
});

App.Router.reopen({
  notifyGoogleAnalytics: function() {
    var url = this.get('url');

    // Add a slash if neccesary
    if (!/^\//.test(url)){ url = '/' + url; }

    _gaq.push(['_trackPageview', '/builds' + url]);
  }.on('didTransition')
});

App.CopyClipboardComponent = Ember.Component.extend({
  tagName: 'span',
  hasFlash: ZeroClipboard.detectFlashSupport(),

  didInsertElement: function () {
    var clip = new ZeroClipboard(this.$('button'), {
      // This would normally be a relative path
      moviePath: "/images/ZeroClipboard.swf",

      trustedDomains: ["*"],
      allowScriptAccess: "always"
    });

    clip.on('mousedown', function(client, e) {
      Em.run.later(this, function() {
        $(this).removeClass('loading');
        $(this).removeAttr('disabled');
      }, 1000);
      Em.run.next(this, function() {
        $(this).addClass('loading');
        $(this).attr('disabled', 'disabled');
      });
    });

    this.$('input').on('click', function() {
      $(this).select();
    });
  }
});

App.S3Bucket = Ember.Object.extend({
  files: [],
  isLoading: false,

  // Setup these as default values.
  // They can be overridden on create.
  queryUseSSL: true,
  objectUseSSL: false,
  delimiter: '/',
  bucket: 'builds.emberjs.com',
  endpoint: 's3.amazonaws.com',

  delimiterParameter: function(){
    var delimiter = this.getWithDefault('delimiter','').toString();
    return (delimiter) ? 'delimiter=' + delimiter : '';
  }.property('delimiter'),

  markerParameter: function(){
    return 'marker=' + this.getWithDefault('marker','').toString();
  }.property('marker'),

  maxKeysParameter: function(){
    return 'max-keys=' + this.getWithDefault('maxKeys','').toString();
  }.property('maxKeys'),

  prefixParameter: function(){
    return 'prefix=' + this.getWithDefault('prefix','').toString();
  }.property('prefix'),

  queryProtocol: function() {
    return this.get('queryUseSSL') ? 'https://' : 'http://';
  }.property('queryUseSSL'),

  queryBaseUrl: function(){
    return this.get('queryProtocol') + this.get('endpoint') + '/' + this.get('bucket')
  }.property('queryProtocol', 'endpoint', 'bucket'),

  objectProtocol: function() {
    return this.get('objectUseSSL') ? 'https://' : 'http://';
  }.property('objectUseSSL'),

  objectBaseUrl: function(){
    return this.get('objectProtocol') + this.get('bucket');
  }.property('objectProtocol', 'bucket'),

  queryParams: function(){
    return this.get('delimiterParameter')  + '&' +
      this.get('markerParameter')     + '&' +
      this.get('maxKeysParameter')    + '&' +
      this.get('prefixParameter');
  }.property('delimiterParameter','markerParameter','maxKeysParameter','prefixParameter'),

  queryUrl: function(){
    return this.get('queryBaseUrl') + '?' + this.get('queryParams');
  }.property('queryBaseUrl','queryParams'),

  filesPresent: function(){
    return this.get('files').length;
  }.property('files.@each'),

  filterFiles: function(filter, ignoreFiles){
    var files = this.get('files');
    var ignoreFiles = Ember.A(ignoreFiles);

    return files.filter(function(e) {
      var name = e.get('name');
      var ignored = ignoreFiles.any(function(f) { return name.indexOf(f) >= 0; });
      var selected = name.indexOf(filter + '.') >= 0;

      return !ignored && selected;
    });
  },

  load: function(){
    var self = this,
    baseUrl = this.get('objectBaseUrl');

    this.set('isLoading', true);
    Ember.$.get(this.get('queryUrl'), function(data){
      self.set('isLoading', false);
      self.set('response', data);

      var contents = data.getElementsByTagName('Contents'),
      length   = contents.length,
      files    = [];

      for(var i = 0; i < length; i++) {
        var size = contents[i].getElementsByTagName('Size')[0].firstChild.data,
        name = contents[i].getElementsByTagName('Key')[0].firstChild.data,
        lastModified = new Date(contents[i].getElementsByTagName('LastModified')[0].firstChild.data);

        files.push(
          App.S3File.create({
          name: name,
          size: size,
          lastModified: lastModified,
          relativePath: name,
          baseUrl: baseUrl
        })
        );
      }

      self.set('files', files.sort(function(a,b){
        return b.lastModified - a.lastModified;
      }));
    });
  }.observes('queryUrl').on('init')
});

App.S3File = Ember.Object.extend({
  scriptTag: function(){
    var escapedURL = Handlebars.Utils.escapeExpression(this.get('url'));

    return new Handlebars.SafeString('<script src="' + escapedURL + '"></script>').toString();
  }.property('url'),

  url: function(){
    return this.get('baseUrl') + '/' + this.get('relativePath');
  }.property('baseUrl', 'relativePath')
});

App.Project = Ember.Object.extend();

App.Project.reopenClass({
  FIXTURES:
    [ {
      projectName: 'Ember',
      projectFilter: 'ember',
      projectRepo: 'emberjs/ember.js',
      channel: "tagged"
    }, {
      projectName: 'Ember Data',
      projectFilter: 'ember-data',
      projectRepo: 'emberjs/data',
      channel: "tagged"
    }, {
      projectName: "Ember",
      projectFilter: "ember",
      projectRepo: 'emberjs/ember.js',
      initialVersion: "1.9.0",
      initialReleaseDate: "2014-12-08",
      lastRelease: "1.9.0",
      futureVersion: "1.9.1",
      channel: "release",
      date: "2014-12-08",
      changelogPath: "CHANGELOG.md",
      enableTestURL: true,
      debugFileName: ".js"
    }, {
      projectName: "Ember",
      projectFilter: "ember",
      projectRepo: 'emberjs/ember.js',
      lastRelease: "1.10.0-beta.1",
      futureVersion: "1.9.0-beta.2",
      finalVersion: '1.10.0',
      channel: "beta",
      cycleEstimatedFinishDate: '2015-02-23',
      date: "2014-12-10",
      nextDate: "2014-12-17",
      changelogPath: "CHANGELOG.md",
      enableTestURL: true,
      debugFileName: ".debug.js",
      ignoreFiles: ['ember.js']
    }, {
      projectName: "Ember Data",
      projectFilter: "ember-data",
      projectRepo: 'emberjs/data',
      lastRelease: "1.0.0-beta.12",
      futureVersion: "1.0.0-beta.13",
      channel: "beta",
      date: "2014-11-26",
      changelogPath: "CHANGELOG.md",
      debugFileName: ".js"
    }, {
      projectName: "Ember",
      projectFilter: "ember",
      projectRepo: 'emberjs/ember.js',
      channel: "canary",
      enableTestURL: true,
      debugFileName: ".debug.js",
      ignoreFiles: ['ember.js']
    }, {
      projectName: "Ember Data",
      projectFilter: "ember-data",
      projectRepo: 'emberjs/data',
      channel: "canary",
      debugFileName: ".js"
    }],

  all: function(channel){
    var projects;

    if (channel)
      projects = this.FIXTURES.filterBy('channel', channel);
    else
      projects = this.FIXTURES;

    return projects.map(function(obj) {
      return App.Project.create(obj);
    });
  },

  find: function(channel, name) {
    var allProjects = this.all(channel);

    if (!name)
      return allProjects;
    else
      return allProjects.filterBy('projectName', name);
  }
});

App.BuildCategoryMixin = Ember.Mixin.create({
  renderTemplate: function() {
    this.render('build-list');
  }
});

App.ApplicationController = Ember.ObjectController.extend({
  isIndexActive: function(){
    return this.isActiveChannel('index');
  }.property('currentRouteName'),

  isTaggedActive: function(){
    return this.isActiveChannel('tagged');
  }.property('currentRouteName'),

  isChannelsActive: function(){
    var self = this;
    return !['index','tagged'].some(function(name){ return name === self.get('currentRouteName'); })
  }.property('currentRouteName'),

  isReleaseActive: function(){
    return this.isActiveChannel('release');
  }.property('currentRouteName'),

  isBetaActive: function(){
    return this.isActiveChannel('beta');
  }.property('currentRouteName'),

  isCanaryActive: function(){
    return this.isActiveChannel('canary');
  }.property('currentRouteName'),

  isActiveChannel: function(channel){
    return this.get('currentRouteName').indexOf(channel) !== -1;
  }
});

App.ProjectsMixin = Ember.Mixin.create({
  projects: function(){
    var projects = App.Project.find(this.get('channel')),
        bucket   = this.get('model'),
        self = this;

    projects.forEach(function(project){
      if (project.channel === 'beta'){
        project.isEmberBeta = project.projectName === 'Ember';

        [1,2,3,4,5].forEach(function(increment){
          var versionParts = project.lastRelease.split('.');
          var currentBetaNumber = parseInt(versionParts[versionParts.length - 1], 10);
          project['beta' + increment + 'Completed'] = increment <= currentBetaNumber;
          project['isBeta' + increment] = increment === currentBetaNumber;
        });

        var release = App.Project.find('release', project.projectName)[0];

        // no releases exist for ember-data (yet)
        if (release) {
          project.lastStableVersion = release.initialVersion;
          project.lastStableDate = release.initialReleaseDate;
        }
      }

      project.files = bucket.filterFiles(project.projectFilter, project.ignoreFiles);
      project.description = self.description(project);
      project.lastReleaseDebugUrl = self.lastReleaseUrl(project.projectFilter, project.channel, project.lastRelease, project.debugFileName);
      project.lastReleaseProdUrl  = self.lastReleaseUrl(project.projectFilter, project.channel, project.lastRelease, '.prod.js');
      project.lastReleaseMinUrl   = self.lastReleaseUrl(project.projectFilter, project.channel, project.lastRelease, '.min.js');

      if (project.enableTestURL) {
        project.lastReleaseTestUrl  = self.lastReleaseUrl(project.projectFilter, project.channel, project.lastRelease, '-tests-index.html');
      }

      if (project.channel === 'canary') {
        project.lastRelease = 'latest';
      } else if (project.changelog !== 'false') {
        project.lastReleaseChangelogUrl   = 'https://github.com/' + project.projectRepo + '/blob/v' + project.lastRelease + '/' + project.changelogPath;
      }
    });

    return projects;
  }.property('channel', 'model'),

  description: function(project){
    var lastRelease = project.lastRelease,
        futureVersion = project.futureVersion,
        value;

    if (this.get('channel') === 'tagged') {
      value = '';
    } else if (lastRelease) {
      value = 'The builds listed below are incremental improvements made since ' + lastRelease + ' and may become ' + futureVersion + '.'
    } else if (futureVersion) {
      value = 'The builds listed below are not based on a tagged release. Upon the next release cycle they will become ' + futureVersion + '.';
    } else {
      value = 'The builds listed below are based on the most recent development.';
    }

    return new Handlebars.SafeString(value);
  },

  lastReleaseUrl: function(project, channel, lastRelease, extension){
    if (channel === 'canary')
      return 'http://builds.emberjs.com/canary/' + project + extension;
    else
      return 'http://builds.emberjs.com/tags/v' + lastRelease + '/' + project + extension;
  }

});

App.CanaryRoute = Ember.Route.extend(App.BuildCategoryMixin, {
  model: function() {
    return App.S3Bucket.create({title: 'Canary Builds', prefix: 'canary/' });
  }
});

App.CanaryController = Ember.ObjectController.extend(App.ProjectsMixin, {
  templateName: 'buildList',
  channel: 'canary'
});

App.BetaRoute = Ember.Route.extend(App.BuildCategoryMixin, {
  model: function() {
    return App.S3Bucket.create({title: 'Beta Builds', prefix: 'beta/'});
  }
});

App.BetaController = Ember.ObjectController.extend(App.ProjectsMixin, {
  templateName: 'buildList',
  channel: 'beta'
});

App.ReleaseRoute = Ember.Route.extend(App.BuildCategoryMixin, {
  model: function() {
    return App.S3Bucket.create({title: 'Release Builds', prefix: 'release/'});
  }
});

App.ReleaseController = Ember.ObjectController.extend(App.ProjectsMixin, {
  templateName: 'buildList',
  channel: 'release'
});

App.TaggedRoute = Ember.Route.extend(App.BuildCategoryMixin, {
  model: function() {
    var bucket = App.S3Bucket.create({
      title: 'Tagged Release Builds',
      prefix: 'tags/',
      delimiter: '',
    });
    return bucket;
  }
});

App.TaggedController = Ember.ObjectController.extend(App.ProjectsMixin, {
  channel: 'tagged'
});
/*
 * Handlebars Helpers
 */
Ember.Handlebars.helper('format-bytes', function(bytes){
  return (bytes / 1024).toFixed(2) + ' KB';
});

Ember.Handlebars.helper('format-date-time', function(date, format, options) {
  if (!options) {
    options = format;
    format = null;
  }

  if (format){
    return moment(date).format(format);
  } else {
    return moment(date).fromNow();
  }
});

Ember.Handlebars.helper('isHiDPIScreen', function() {
  return window.getDevicePixelRatio() > 1;
});
<|endoftext|>


<commit_before>/*  VCO.TimelineConfig
separate the configuration from the display (VCO.Timeline)
to make testing easier
================================================== */
VCO.TimelineConfig = VCO.Class.extend({

	includes: [],
	messages: {
		errors: [],
		warnings: []
	},
	VALID_PROPERTIES: ['scale', 'title', 'events'], // we'll only pull things in from this

	initialize: function (data) {
		// Initialize the data
		if (typeof data === 'object' && data.events) {
			this._importProperties(data);
			this._cleanData();
		} else {
			this.logError("Argument to TimelineConfig should be a JSON object conforming to the TimelineJS3 JSON specification.");
		}
	},
	logError: function(msg) {
		trace(msg);
		this.messages.errors.push(msg);
	},
	/*
	 * Return any accumulated error messages. If `sep` is passed, it should be a string which will be used to join all messages, resulting in a string return value. Otherwise,
	 * errors will be returned as an array.
	 */
	getErrors: function(sep) {
		if (sep) {
			return this.messages.errors.join(sep);
		} else {
			return this.messages.errors;
		}
	},
	/*
	 * Perform any sanity checks we can before trying to use this to make a timeline. Returns nothing, but errors will be logged
	 * such that after this is called, one can test `this.isValid()` to see if everything is OK.
	 */
	validate: function() {
		if (typeof(this.events) == "undefined" || typeof(this.events.length) == "undefined" || this.events.length == 0) {
			this.logError("Timeline configuration has no events.")
		}
	},
	isValid: function() {
		return this.messages.errors.length == 0;
	},
	/* Add an event and return the unique id
	*/
	addEvent: function(data) {
		var _id = (this.title) ? this.title.uniqueid : '';
		this.events.push(data);
		this._makeUniqueIdentifiers(_id, this.events);
		this._processDates(this.events);

		var uniqueid = this.events[this.events.length - 1].uniqueid;
		VCO.DateUtil.sortByDate(this.events);
		return uniqueid;
	},

	_cleanData: function() {
		var _id = (this.title) ? this.title.uniqueid : '';
		this._makeUniqueIdentifiers(_id, this.events);
		this._processDates(this.events);
		this._cleanGroups(this.events)          ;
		VCO.DateUtil.sortByDate(this.events);
	},

	_importProperties: function(d) {
		for (var i = 0; i < this.VALID_PROPERTIES.length; i++) {
			k = this.VALID_PROPERTIES[i];
			this[k] = d[k];
		}

		// Make sure title slide has unique id
		if(this.title && !('uniqueid' in this.title)) {
			this.title.uniqueid = '';
		}
	},

	_makeUniqueIdentifiers: function(title_id, array) {
		var used = [title_id];
		for (var i = 0; i < array.length; i++) {
			if (array[i].uniqueid && array[i].uniqueid.replace(/\s+/,'').length > 0) {
				array[i].uniqueid = VCO.Util.slugify(array[i].uniqueid); // enforce valid
				if (used.indexOf(array[i].uniqueid) != -1) {
					array[i].uniqueid = '';
				} else {
					used.push(array[i].uniqueid);
				}
			}
		};
		if (used.length != (array.length + 1)) {
			for (var i = 0; i < array.length; i++) {
				if (!array[i].uniqueid) {
					var slug = (array[i].text) ? VCO.Util.slugify(array[i].text.headline) : null;
					if (!slug) {
						slug = VCO.Util.unique_ID(6);
					}
					if (used.indexOf(slug) != -1) {
						slug = slug + '-' + i;
					}
					used.push(slug);
					array[i].uniqueid = slug;
				}
			}
		}
	},

	_processDates: function(array) {
		var dateCls = null;

		if(!this.scale) {
			trace("Determining scale dynamically");

			this.scale = "human"; // default

			for (var i = 0; i < array.length; i++) {
				if (typeof(array[i].start_date) == 'undefined') {
					this.logError("item " + i + " is missing a start_date");
				} else if (typeof(array[i].start_date.year) == 'undefined' || !(array[i].start_date.year.match(/^\s*\-?\d+\s*$/))) {
					this.logError("item " + i + " is has invalid start_date.");
				} else {
					var d = new VCO.BigDate(array[i].start_date);
					var year = d.data.date_obj.year;
					if(year < -271820 || year >  275759) {
						this.scale = "cosmological";
						break;
					}
				}
			}
		}

		if(this.scale == 'human') {
			dateCls = VCO.Date;
			trace('using VCO.Date');
		} else if(this.scale == 'cosmological') {
			dateCls = VCO.BigDate;
			trace('using VCO.BigDate');
		} else {
			this.logError("Don't know how to process dates on scale "+this.scale);
		}

		for (var i = 0; i < array.length; i++) {
			if (typeof(array[i].start_date) == 'undefined') {
				this.logError("item " + i + " is missing a start_date");
			}
			if(!(array[i].start_date instanceof dateCls)) {
				var start_date = array[i].start_date;
				array[i].start_date = new dateCls(start_date);

				// eliminate redundant end dates.
				if (typeof(array[i].end_date) != 'undefined' && !(array[i].end_date instanceof dateCls)) {
					var end_date = array[i].end_date;
					var equal = true;
					for (property in start_date) {
						equal = equal && (start_date[property] == end_date[property]);
					}
					if (equal) {
						trace("End date same as start date is redundant; dropping end date");
						delete array[i].end_date;
					} else {
						array[i].end_date = new dateCls(end_date);
					}

				}
			}
		}
	},

	_cleanGroups: function(array) {
		for (var i = 0; i < array.length; i++) {
			if (array[i].group) {
				array[i].group = VCO.Util.trim(array[i].group);
			}
		};
	}
});
<commit_msg>could we make a TimelineConfig that is incrementally built up?<commit_after>/*  VCO.TimelineConfig
separate the configuration from the display (VCO.Timeline)
to make testing easier
================================================== */
VCO.TimelineConfig = VCO.Class.extend({

	includes: [],
	title: null,
	scale: null,
	events: [],
	messages: {
		errors: [],
		warnings: []
	},
	VALID_PROPERTIES: ['scale', 'title', 'events'], // we'll only pull things in from this

	initialize: function (data) {
		// Initialize the data
		if (typeof data === 'object' && data.events) {
			this._importProperties(data);
			this._cleanData();
		}
	},
	logError: function(msg) {
		trace(msg);
		this.messages.errors.push(msg);
	},
	/*
	 * Return any accumulated error messages. If `sep` is passed, it should be a string which will be used to join all messages, resulting in a string return value. Otherwise,
	 * errors will be returned as an array.
	 */
	getErrors: function(sep) {
		if (sep) {
			return this.messages.errors.join(sep);
		} else {
			return this.messages.errors;
		}
	},
	/*
	 * Perform any sanity checks we can before trying to use this to make a timeline. Returns nothing, but errors will be logged
	 * such that after this is called, one can test `this.isValid()` to see if everything is OK.
	 */
	validate: function() {
		if (typeof(this.events) == "undefined" || typeof(this.events.length) == "undefined" || this.events.length == 0) {
			this.logError("Timeline configuration has no events.")
		}
	},
	isValid: function() {
		return this.messages.errors.length == 0;
	},
	/* Add an event and return the unique id
	*/
	addEvent: function(data) {
		var _id = (this.title) ? this.title.uniqueid : '';
		this.events.push(data);
		this._makeUniqueIdentifiers(_id, this.events);
		this._processDates(this.events);

		var uniqueid = this.events[this.events.length - 1].uniqueid;
		VCO.DateUtil.sortByDate(this.events);
		return uniqueid;
	},

	_cleanData: function() {
		var _id = (this.title) ? this.title.uniqueid : '';
		this._makeUniqueIdentifiers(_id, this.events);
		this._processDates(this.events);
		this._cleanGroups(this.events)          ;
		VCO.DateUtil.sortByDate(this.events);
	},

	_importProperties: function(d) {
		for (var i = 0; i < this.VALID_PROPERTIES.length; i++) {
			k = this.VALID_PROPERTIES[i];
			this[k] = d[k];
		}

		// Make sure title slide has unique id
		if(this.title && !('uniqueid' in this.title)) {
			this.title.uniqueid = '';
		}
	},

	_makeUniqueIdentifiers: function(title_id, array) {
		var used = [title_id];
		for (var i = 0; i < array.length; i++) {
			if (array[i].uniqueid && array[i].uniqueid.replace(/\s+/,'').length > 0) {
				array[i].uniqueid = VCO.Util.slugify(array[i].uniqueid); // enforce valid
				if (used.indexOf(array[i].uniqueid) != -1) {
					array[i].uniqueid = '';
				} else {
					used.push(array[i].uniqueid);
				}
			}
		};
		if (used.length != (array.length + 1)) {
			for (var i = 0; i < array.length; i++) {
				if (!array[i].uniqueid) {
					var slug = (array[i].text) ? VCO.Util.slugify(array[i].text.headline) : null;
					if (!slug) {
						slug = VCO.Util.unique_ID(6);
					}
					if (used.indexOf(slug) != -1) {
						slug = slug + '-' + i;
					}
					used.push(slug);
					array[i].uniqueid = slug;
				}
			}
		}
	},

	_processDates: function(array) {
		var dateCls = null;

		if(!this.scale) {
			trace("Determining scale dynamically");

			this.scale = "human"; // default

			for (var i = 0; i < array.length; i++) {
				if (typeof(array[i].start_date) == 'undefined') {
					this.logError("item " + i + " is missing a start_date");
				} else if (typeof(array[i].start_date.year) == 'undefined' || !(array[i].start_date.year.match(/^\s*\-?\d+\s*$/))) {
					this.logError("item " + i + " is has invalid start_date.");
				} else {
					var d = new VCO.BigDate(array[i].start_date);
					var year = d.data.date_obj.year;
					if(year < -271820 || year >  275759) {
						this.scale = "cosmological";
						break;
					}
				}
			}
		}

		if(this.scale == 'human') {
			dateCls = VCO.Date;
			trace('using VCO.Date');
		} else if(this.scale == 'cosmological') {
			dateCls = VCO.BigDate;
			trace('using VCO.BigDate');
		} else {
			this.logError("Don't know how to process dates on scale "+this.scale);
		}

		for (var i = 0; i < array.length; i++) {
			if (typeof(array[i].start_date) == 'undefined') {
				this.logError("item " + i + " is missing a start_date");
			}
			if(!(array[i].start_date instanceof dateCls)) {
				var start_date = array[i].start_date;
				array[i].start_date = new dateCls(start_date);

				// eliminate redundant end dates.
				if (typeof(array[i].end_date) != 'undefined' && !(array[i].end_date instanceof dateCls)) {
					var end_date = array[i].end_date;
					var equal = true;
					for (property in start_date) {
						equal = equal && (start_date[property] == end_date[property]);
					}
					if (equal) {
						trace("End date same as start date is redundant; dropping end date");
						delete array[i].end_date;
					} else {
						array[i].end_date = new dateCls(end_date);
					}

				}
			}
		}
	},

	_cleanGroups: function(array) {
		for (var i = 0; i < array.length; i++) {
			if (array[i].group) {
				array[i].group = VCO.Util.trim(array[i].group);
			}
		};
	}
});
<|endoftext|>


<commit_before>(function (enyo) {
	//*@public
	/**
		An _enyo.Mixin_ is a group of properties and/or methods to apply to a kind
		or instance without requiring the kind to be subclassed. There are a few
		things to keep in mind when creating an _enyo.Mixin_ for use with your
		kinds:

		- A property on a mixin will automatically override the same property on the
			kind or instance it is being applied to, should it already exist.

		- A method that already exists on the kind or instance will not
			automatically call the super-method. If the intention is to extend the
			kind's own method, make sure that you wrap the method with _enyo.super_.

		- Mixins must have a name so they can be identified when applied; otherwise,
			the same mixin may be applied multiple times to a given kind,
			potentially resulting in an infinite loop.

		An _enyo.Mixin_ is _not a kind_. It is simply a named collection of methods
		and properties that may be reused with multiple kinds.

		To create an _enyo.Mixin_, simply create a hash of methods and properties,
		and assign it to a referenceable namespace.

		To apply an _enyo.Mixin_ to a kind, simply add its name or a reference to it
		in the special _mixins_ property in the kind definition. Alternatively, you
		may call _extend()_ on the constructor for the kind, passing in the mixin
		(or an array of mixins).

		To apply an _enyo.Mixin_ to an instance of a kind, call the _extend()_
		method on the instance and pass it the name of (or a reference to) the mixin,
		or an array of mixins.
	*/
	enyo.concat.push("mixins");
	//*@protected
	/**
		We add the feature that will execute last in the feature chain but will scan
		for mixins and extend the kind accordingly, only applying any given mixin one time
		to any kind base.
	*/
	var applyMixin = function (proto, props) {
		var mx = proto._appliedMixins,
			m = props, n;
		// if the mixin is a string we have to try to resolve it to an object
		if (enyo.isString(m)) {
			m = enyo.getPath(m);
			if (!m) {
				enyo.warn("could not find the requested mixin " + props);
				// could not find the mixin
				return;
			}
		}
		// we can't do anything if someone attempts to extend a kind with a mixin
		// that does not have a name but all internal mixins should have names
		if (m.name) {
			if (!~enyo.indexOf(m.name, mx)) {
				mx.push(m.name);
			} else {
				// we will not add the same mixin twice, but we throw the warning
				// to alert the developer of the attempt so it can be tracked down
				enyo.warn("attempt to add the same mixin more than once, " +
					m.name + " onto -> " + proto.kindName);
				return;
			}
			n = m.name;
			delete m.name;
		} else {
			n = null;
		}
		enyo.kind.statics.extend(enyo.clone(m), proto);
		if (n) {
			m.name = n;
		}
	};
	var mixinsFeature = function (ctor, props) {
		if (props.mixins) {
			var cp = ctor.prototype || ctor,
				pm = props.mixins;
			cp._appliedMixins = cp._appliedMixins? enyo.cloneArray(cp._appliedMixins): [],
			// prevent recursion
			delete props.mixins;
			for (var i=0, m; (m=pm[i]); ++i) {
				applyMixin(cp, m);
			}
		}
	};
	enyo.kind.features.push(mixinsFeature);
	enyo.concatHandler("mixins", function (proto, props) {
		proto.mixins = enyo.merge(proto.mixins, props.mixins);
	});
	//*@public
	enyo.MixinSupport = {
		name: "MixinSupport",
		/**
			Takes a single parameter--a hash of properties to apply. To be considered
			a _mixin_, it must have a _name_ property that is unique, but the method
			will apply even non-mixins to the kind instance.
		*/
		extend: function (props) {
			applyMixin(this, props);
		},
		/**
			Extend the _importProps()_ method to ensure we can handle runtime additions
			of the mixins' properties since they can be added at any time, even by other
			mixins. This will only be executed against mixins applied after the kind
			has already been evaluated and it is being initialized as an instance.
			However, if a mixin applies more mixins at runtime, it will have no effect.
		*/
		importProps: enyo.super(function (sup) {
			return function (props) {
				if (props) { mixinsFeature(this, props); }
				sup.apply(this, arguments);
			};
		})
	};
}(enyo));
<commit_msg>allow mixins applied to constructors to actually be applied to the kind<commit_after>(function (enyo) {
	//*@public
	/**
		An _enyo.Mixin_ is a group of properties and/or methods to apply to a kind
		or instance without requiring the kind to be subclassed. There are a few
		things to keep in mind when creating an _enyo.Mixin_ for use with your
		kinds:

		- A property on a mixin will automatically override the same property on the
			kind or instance it is being applied to, should it already exist.

		- A method that already exists on the kind or instance will not
			automatically call the super-method. If the intention is to extend the
			kind's own method, make sure that you wrap the method with _enyo.super_.

		- Mixins must have a name so they can be identified when applied; otherwise,
			the same mixin may be applied multiple times to a given kind,
			potentially resulting in an infinite loop.

		An _enyo.Mixin_ is _not a kind_. It is simply a named collection of methods
		and properties that may be reused with multiple kinds.

		To create an _enyo.Mixin_, simply create a hash of methods and properties,
		and assign it to a referenceable namespace.

		To apply an _enyo.Mixin_ to a kind, simply add its name or a reference to it
		in the special _mixins_ property in the kind definition. Alternatively, you
		may call _extend()_ on the constructor for the kind, passing in the mixin
		(or an array of mixins).

		To apply an _enyo.Mixin_ to an instance of a kind, call the _extend()_
		method on the instance and pass it the name of (or a reference to) the mixin,
		or an array of mixins.
	*/
	enyo.concat.push("mixins");
	//*@protected
	/**
		We add the feature that will execute last in the feature chain but will scan
		for mixins and extend the kind accordingly, only applying any given mixin one time
		to any kind base.
	*/
	var applyMixin = function (proto, props) {
		var mx = proto._appliedMixins,
			m = props, n;
		// if the mixin is a string we have to try to resolve it to an object
		if (enyo.isString(m)) {
			m = enyo.getPath(m);
			if (!m) {
				enyo.warn("could not find the requested mixin " + props);
				// could not find the mixin
				return;
			}
		}
		// we can't do anything if someone attempts to extend a kind with a mixin
		// that does not have a name but all internal mixins should have names
		if (m.name) {
			if (!~enyo.indexOf(m.name, mx)) {
				mx.push(m.name);
			} else {
				// we will not add the same mixin twice, but we throw the warning
				// to alert the developer of the attempt so it can be tracked down
				enyo.warn("attempt to add the same mixin more than once, " +
					m.name + " onto -> " + proto.kindName);
				return;
			}
			n = m.name;
			delete m.name;
		} else {
			n = null;
		}
		enyo.kind.statics.extend(enyo.clone(m), proto);
		if (n) {
			m.name = n;
		}
	};
	var mixinsFeature = function (ctor, props) {
		if (props.mixins) {
			var cp = ctor.prototype || ctor,
				pm = props.mixins;
			cp._appliedMixins = cp._appliedMixins? enyo.cloneArray(cp._appliedMixins): [],
			// prevent recursion
			delete props.mixins;
			for (var i=0, m; (m=pm[i]); ++i) {
				applyMixin(cp, m);
			}
		}
	};
	enyo.kind.features.push(mixinsFeature);
	enyo.concatHandler("mixins", function (proto, props) {
		proto.mixins = enyo.merge(proto.mixins, props.mixins);
	});
	enyo.kind.extendMethods(enyo.kind.statics, {
		extend: enyo.super(function (sup) {
			return function (props, target) {
				var proto = target || this.prototype;
				if (props.mixins) {
					// cut-out the need for concatenated properties to handle
					// this (and it won't be able to because we're removing the
					// new mixins array)
					proto.mixins = enyo.merge(proto.mixins, props.mixins);
					mixinsFeature(proto, props);
				}
				return sup.apply(this, arguments);
			};
		})
	}, true);
	//*@public
	enyo.MixinSupport = {
		name: "MixinSupport",
		/**
			Takes a single parameter--a hash of properties to apply. To be considered
			a _mixin_, it must have a _name_ property that is unique, but the method
			will apply even non-mixins to the kind instance.
		*/
		extend: function (props) {
			applyMixin(this, props);
		},
		/**
			Extend the _importProps()_ method to ensure we can handle runtime additions
			of the mixins' properties since they can be added at any time, even by other
			mixins. This will only be executed against mixins applied after the kind
			has already been evaluated and it is being initialized as an instance.
			However, if a mixin applies more mixins at runtime, it will have no effect.
		*/
		importProps: enyo.super(function (sup) {
			return function (props) {
				if (props) { mixinsFeature(this, props); }
				sup.apply(this, arguments);
			};
		})
	};
}(enyo));
<|endoftext|>


<commit_before>'use strict';
let request = require('request');

const PAGE_SIZE = 20;

/**
 * Requests to the Jama API are paginated, so this function handles any set of paged data, collecting any interval of
 * pages requested from the endpoint into a single array of response data to be used by the calling function.
 *
 * @param baseUrl
 * @param startAt
 * @param maxResults
 * @returns {Promise}
 */
function pagination (baseUrl, startAt = 0, maxResults = Number.MAX_SAFE_INTEGER) {
  return new Promise(function (resolve, reject) {
    let payload = [];
    let resultCount = -1;
    let counter = 0;

    // Recursively retrieves all the pages and stores them in payload
    function getPages (baseUrl, start, max) {
      ++counter;
      if (resultCount === 0) {
        resolve(payload);
      } else {
        let maxResultsParam = 'maxResults=' + PAGE_SIZE;
        let startAtParam = 'startAt=' + start;
        let url;
        if (baseUrl.indexOf('?') !== -1) {
          url = baseUrl + '&' + startAtParam + '&' + maxResultsParam;
        } else {
          url = baseUrl + '?' + startAtParam + '&' + maxResultsParam;
        }
        request({url: url, json: true}, function (error, response, body) {
          if (response.statusCode !== 200 || error) {
            // The non-200 response needs to be made into an error before it may be rejected as an error
            if (!error) {
              error = {'statusCode': response.statusCode, 'status': response.body.meta.status};
            }
            reject(error);
          } else {
            // When only a single item is returned from Jama, it is not stored in a list (handled by else case)
            if (response.body.data instanceof Array) {
              response.body.data.forEach(function (item) {
                if (payload.length < max) {
                  payload.push(item);
                }
              });
              let pageInfo = response.body.meta.pageInfo;
              start = pageInfo.startIndex + PAGE_SIZE;
              resultCount = (payload.length <= max) ? pageInfo.resultCount : 0;
              return getPages(baseUrl, start, max);
            } else {
              payload.push(response.body.data);
              resolve(payload);
            }
          }
        });
      }
    }

    getPages(baseUrl, startAt, maxResults);
  });
}

module.exports = pagination;
<commit_msg>modified comments<commit_after>'use strict';
let request = require('request');

const PAGE_SIZE = 20;

/**
 * Requests to the Jama API are paginated, so this function collects a set of paged data, beginning at a
 * given page from a given endpoint into an array of response data. Collection continues until either the
 * end of the paged data is reached or the number of items collected is equal to a given number of maximum
 * results, whichever comes first.
 *
 * @param baseUrl Endpoint that data is pulled from
 * @param startAt Numeric value used to mark the starting point of each page (interval is set to 20)
 * @param maxResults Maximum number of items to collect in the array of response data
 * @returns {Promise} If resolved, the payload that contains all data from the pages is returned. Else, an
 * error object is returned.
 */
function pagination (baseUrl, startAt = 0, maxResults = Number.MAX_SAFE_INTEGER) {
  return new Promise(function (resolve, reject) {
    let payload = [];
    let resultCount = -1;
    let counter = 0;

    // Recursively retrieves all the pages and stores them in payload
    function getPages (baseUrl, start, max) {
      ++counter;
      if (resultCount === 0) {
        resolve(payload);
      } else {
        let maxResultsParam = 'maxResults=' + PAGE_SIZE;
        let startAtParam = 'startAt=' + start;
        let url;
        if (baseUrl.indexOf('?') !== -1) {
          url = baseUrl + '&' + startAtParam + '&' + maxResultsParam;
        } else {
          url = baseUrl + '?' + startAtParam + '&' + maxResultsParam;
        }
        request({url: url, json: true}, function (error, response, body) {
          if (response.statusCode !== 200 || error) {
            // The non-200 response needs to be made into an error before it may be rejected as an error
            if (!error) {
              error = {'statusCode': response.statusCode, 'status': response.body.meta.status};
            }
            reject(error);
          } else {
            // When only a single item is returned from Jama, it is not stored in a list (handled by else case)
            if (response.body.data instanceof Array) {
              response.body.data.forEach(function (item) {
                if (payload.length < max) {
                  payload.push(item);
                }
              });
              let pageInfo = response.body.meta.pageInfo;
              start = pageInfo.startIndex + PAGE_SIZE;
              resultCount = (payload.length <= max) ? pageInfo.resultCount : 0;
              return getPages(baseUrl, start, max);
            } else {
              payload.push(response.body.data);
              resolve(payload);
            }
          }
        });
      }
    }

    getPages(baseUrl, startAt, maxResults);
  });
}

module.exports = pagination;
<|endoftext|>


<commit_before>const fs = require('fs')
const util = require('util')

const parseDirectory = require('./parsers/directory')
const parseName = require('./parsers/name')
const parseType = require('./parsers/type')
const parseArchive = require('./parsers/archive')
const parseFile = require('./parsers/file')

const stat = util.promisify(fs.stat)

async function parsePath(token, options) {
  if (token.parsed) return false

  options.logger.log('path:analyze:start', token)

  token.stats = await stat(token.path)

  try {
    if (token.stats.isDirectory()) {
      await parseDirectory(token, options)
    } else if (token.stats.isFile()) {
      parseName(token, options)
      parseType(token, options)

      await parseArchive(token, options)
      await parseFile(token, options)
    }
  } catch (err) {
    throw err
  } finally {
    delete token.stats
  }

  options.logger.log('path:analyze:end', token)
}

module.exports = parsePath
<commit_msg>Use lstat instead of stat to ignore symlinks<commit_after>const fs = require('fs')
const util = require('util')

const parseDirectory = require('./parsers/directory')
const parseName = require('./parsers/name')
const parseType = require('./parsers/type')
const parseArchive = require('./parsers/archive')
const parseFile = require('./parsers/file')

const lstat = util.promisify(fs.lstat)

async function parsePath(token, options) {
  if (token.parsed) return false

  options.logger.log('path:analyze:start', token)

  token.stats = await lstat(token.path)

  try {
    if (token.stats.isDirectory()) {
      await parseDirectory(token, options)
    } else if (token.stats.isFile()) {
      parseName(token, options)
      parseType(token, options)

      await parseArchive(token, options)
      await parseFile(token, options)
    } else {
      throw new Error('Unsupported file type')
    }
  } catch (err) {
    throw err
  } finally {
    delete token.stats
  }

  options.logger.log('path:analyze:end', token)
}

module.exports = parsePath
<|endoftext|>