<commit_before>import Component from 'ember-component';
import get from 'ember-metal/get';
import set from 'ember-metal/set';
import { scheduleOnce } from 'ember-runloop';
import { invokeAction } from 'ember-invoke-action';
import layout from '../templates/components/star-rating';

const RatingComponent = Component.extend({
  layout,

  fillColor: 'yellow',
  baseColor: 'lightgrey',
  numStars: 5,
  anyPercent: false,
  rating: 0,
  readOnly: false,
  width: 26,
  height: 26,
  useHalfStars: true,
  svgPath: 'M25.326,10.137c-0.117-0.361-0.431-0.625-0.807-0.68l-7.34-1.066l-3.283-6.651 c-0.337-0.683-1.456-0.683-1.793,0L8.82,8.391L1.48,9.457c-0.376,0.055-0.689,0.318-0.807,0.68c-0.117,0.363-0.02,0.76,0.253,1.025 l5.312,5.178l-1.254,7.31c-0.064,0.375,0.09,0.755,0.397,0.978c0.309,0.225,0.717,0.254,1.054,0.076L13,21.252l6.564,3.451 c0.146,0.077,0.307,0.115,0.466,0.115c0.207,0,0.413-0.064,0.588-0.191c0.308-0.223,0.462-0.603,0.397-0.978l-1.254-7.31 l5.312-5.178C25.346,10.896,25.443,10.5,25.326,10.137z',
  viewBox: '0 0 26 26',

  init() {
    this._super(...arguments);
    const num = get(this, 'numStars');
    const stars = Array.apply(null, { length: num }).map(() => 1);
    set(this, 'stars', stars);
  },

  didReceiveAttrs() {
    this._super(...arguments);
    scheduleOnce('afterRender', () => this.$().removeClass('has-rating'));
    if (get(this, 'rating') > 0) {
      scheduleOnce('afterRender', () => this.$().addClass('has-rating'));
    }
    scheduleOnce('afterRender', () => {
      const rating = get(this, 'rating');
      this._updateStars(rating);
    });
  },

  didInsertElement() {
    this._super(...arguments);
    this.$().css('display', 'inline-block');
    if (get(this, 'readOnly') === false) {
      this.$().css('cursor', 'pointer');
    }
  },

  mouseMove(event) {
    this._render(event);
  },

  mouseLeave() {
    this._reset();
  },

  click(event) {
    this._update(event);
  },

  _render(event) {
    if (get(this, 'readOnly')) {
      return;
    }
    const pageX = event.pageX;
    const target = this._getTarget(pageX);
    const rating = Math.floor(target * 2) / 2;
    this._updateStars(rating);
    this.$().removeClass('has-rating').addClass('is-rating');
  },

  _reset() {
    if (get(this, 'readOnly')) {
      return;
    }
    const rating = get(this, 'rating');
    this._updateStars(Math.floor(rating * 2) / 2);
    this.$().removeClass('is-rating');
    if (rating > 0) {
      this.$().addClass('has-rating');
    }
  },

  _update(event) {
    if (get(this, 'readOnly')) {
      return;
    }
    const pageX = event.pageX;
    const target = this._getTarget(pageX);
    const rating = Math.floor(target * 2) / 2;
    invokeAction(this, 'onClick', rating);
  },

  _getTarget(x) {
    const numStars = get(this, 'numStars');
    const numStarsFilled = (numStars * (x - this.$().offset().left) / this.$().width() + 0.5);
    if (get(this, 'useHalfStars')) {
      return numStarsFilled;
    }
    return Math.ceil(numStarsFilled - 0.5);
  },

  _getStarOffset(rating, index) {
    const result = rating - index;
    if (get(this, 'useHalfStars')) {
      if (result > -0.01) {
        return '100%';
      } else if (result > -0.51) {
        return '50%';
      } else {
        return '0%';
      }
    } else {
      if (result > -0.51) {
        return '100%';
      } else {
        return '0%';
      }
    }
  },

  _updateStars(rating) {
    this.$().find('> svg').each((index, elem) => {
      let offset = 0;
      if (get(this, 'anyPercent') === true) {
        offset = (rating - index) > 0 ? ((rating - index) > 1 ? '100%' : `${((rating - index) * 100).toFixed(0)}%`) : '0%';
      } else {
        offset = this._getStarOffset(rating, index + 1);
      }
      this.$(elem).find('stop').eq(0).attr('offset', offset);
      let klass = offset === '100%' ? 'star-full' : (offset === '50%' ? 'star-half' : 'star-empty');
      if (get(this, 'anyPercent') === true && klass === 'star-empty' && offset !== '0%') {
        klass = 'star-variable';
      }
      this.$(elem).attr('class', '').attr('class', klass);
    });
  }
});

RatingComponent.reopenClass({
  positionalParams: ['rating']
});

export default RatingComponent;
<commit_msg>Add action which returns the hovered value on mouse move (#3)<commit_after>import Component from 'ember-component';
import get from 'ember-metal/get';
import set from 'ember-metal/set';
import { scheduleOnce } from 'ember-runloop';
import { invokeAction } from 'ember-invoke-action';
import layout from '../templates/components/star-rating';

const RatingComponent = Component.extend({
  layout,

  fillColor: 'yellow',
  baseColor: 'lightgrey',
  numStars: 5,
  anyPercent: false,
  rating: 0,
  readOnly: false,
  width: 26,
  height: 26,
  useHalfStars: true,
  svgPath: 'M25.326,10.137c-0.117-0.361-0.431-0.625-0.807-0.68l-7.34-1.066l-3.283-6.651 c-0.337-0.683-1.456-0.683-1.793,0L8.82,8.391L1.48,9.457c-0.376,0.055-0.689,0.318-0.807,0.68c-0.117,0.363-0.02,0.76,0.253,1.025 l5.312,5.178l-1.254,7.31c-0.064,0.375,0.09,0.755,0.397,0.978c0.309,0.225,0.717,0.254,1.054,0.076L13,21.252l6.564,3.451 c0.146,0.077,0.307,0.115,0.466,0.115c0.207,0,0.413-0.064,0.588-0.191c0.308-0.223,0.462-0.603,0.397-0.978l-1.254-7.31 l5.312-5.178C25.346,10.896,25.443,10.5,25.326,10.137z',
  viewBox: '0 0 26 26',

  init() {
    this._super(...arguments);
    const num = get(this, 'numStars');
    const stars = Array.apply(null, { length: num }).map(() => 1);
    set(this, 'stars', stars);
  },

  didReceiveAttrs() {
    this._super(...arguments);
    scheduleOnce('afterRender', () => this.$().removeClass('has-rating'));
    if (get(this, 'rating') > 0) {
      scheduleOnce('afterRender', () => this.$().addClass('has-rating'));
    }
    scheduleOnce('afterRender', () => {
      const rating = get(this, 'rating');
      this._updateStars(rating);
    });
  },

  didInsertElement() {
    this._super(...arguments);
    this.$().css('display', 'inline-block');
    if (get(this, 'readOnly') === false) {
      this.$().css('cursor', 'pointer');
    }
  },

  mouseMove(event) {
    const rating = this._render(event);
    invokeAction(this, 'onHover', rating || 0);
  },

  mouseLeave() {
    const rating = this._reset();
    invokeAction(this, 'onHover', rating || 0);
  },

  click(event) {
    const rating = this._update(event);
    invokeAction(this, 'onClick', rating || 0);
  },

  _render(event) {
    if (get(this, 'readOnly')) {
      return;
    }
    const pageX = event.pageX;
    const target = this._getTarget(pageX);
    const rating = Math.floor(target * 2) / 2;
    this._updateStars(rating);
    this.$().removeClass('has-rating').addClass('is-rating');
    return rating;
  },

  _reset() {
    if (get(this, 'readOnly')) {
      return;
    }
    const rating = get(this, 'rating');
    this._updateStars(Math.floor(rating * 2) / 2);
    this.$().removeClass('is-rating');
    if (rating > 0) {
      this.$().addClass('has-rating');
    }
    return rating;
  },

  _update(event) {
    if (get(this, 'readOnly')) {
      return;
    }
    const pageX = event.pageX;
    const target = this._getTarget(pageX);
    const rating = Math.floor(target * 2) / 2;
    return rating;
  },

  _getTarget(x) {
    const numStars = get(this, 'numStars');
    const numStarsFilled = (numStars * (x - this.$().offset().left) / this.$().width() + 0.5);
    if (get(this, 'useHalfStars')) {
      return numStarsFilled;
    }
    return Math.ceil(numStarsFilled - 0.5);
  },

  _getStarOffset(rating, index) {
    const result = rating - index;
    if (get(this, 'useHalfStars')) {
      if (result > -0.01) {
        return '100%';
      } else if (result > -0.51) {
        return '50%';
      } else {
        return '0%';
      }
    } else {
      if (result > -0.51) {
        return '100%';
      } else {
        return '0%';
      }
    }
  },

  _updateStars(rating) {
    this.$().find('> svg').each((index, elem) => {
      let offset = 0;
      if (get(this, 'anyPercent') === true) {
        offset = (rating - index) > 0 ? ((rating - index) > 1 ? '100%' : `${((rating - index) * 100).toFixed(0)}%`) : '0%';
      } else {
        offset = this._getStarOffset(rating, index + 1);
      }
      this.$(elem).find('stop').eq(0).attr('offset', offset);
      let klass = offset === '100%' ? 'star-full' : (offset === '50%' ? 'star-half' : 'star-empty');
      if (get(this, 'anyPercent') === true && klass === 'star-empty' && offset !== '0%') {
        klass = 'star-variable';
      }
      this.$(elem).attr('class', '').attr('class', klass);
    });
  }
});

RatingComponent.reopenClass({
  positionalParams: ['rating']
});

export default RatingComponent;
<|endoftext|>


<commit_before>import Color from "./Color.js";
import defaultValue from "./defaultValue.js";
import defined from "./defined.js";
import DeveloperError from "./DeveloperError.js";

function measureText(context2D, textString, font, stroke, fill) {
  var metrics = context2D.measureText(textString);
  var isSpace = !/\S/.test(textString);

  if (!isSpace) {
    var fontSize = document.defaultView
      .getComputedStyle(context2D.canvas)
      .getPropertyValue("font-size")
      .replace("px", "");
    var canvas = document.createElement("canvas");
    var padding = 100;
    var width = (metrics.width + padding) | 0;
    var height = 3 * fontSize;
    var baseline = height / 2;
    canvas.width = width;
    canvas.height = height;

    var ctx = canvas.getContext("2d");
    ctx.font = font;
    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, canvas.width + 1, canvas.height + 1);

    if (stroke) {
      ctx.strokeStyle = "black";
      ctx.lineWidth = context2D.lineWidth;
      ctx.strokeText(textString, padding / 2, baseline);
    }

    if (fill) {
      ctx.fillStyle = "black";
      ctx.fillText(textString, padding / 2, baseline);
    }

    // Context image data has width * height * 4 elements, because
    // each pixel's R, G, B and A are consecutive values in the array.
    var pixelData = ctx.getImageData(0, 0, width, height).data;
    var length = pixelData.length;
    var width4 = width * 4;
    var i, j;

    var ascent, descent;
    // Find the number of rows (from the top) until the first non-white pixel
    for (i = 0; i < length; ++i) {
      if (pixelData[i] !== 255) {
        ascent = (i / width4) | 0;
        break;
      }
    }

    // Find the number of rows (from the bottom) until the first non-white pixel
    for (i = length - 1; i > 0; --i) {
      if (pixelData[i] !== 255) {
        descent = (i / width4) | 0;
        break;
      }
    }

    var minx = -1;
    // For each column, for each row, check for first non-white pixel
    for (i = 0; i < width && minx === -1; ++i) {
      for (j = 0; j < height; ++j) {
        if (
          pixelData[i * 4 + j * width4] !== 255 ||
          pixelData[i * 4 + j * width4 + 1] !== 255 ||
          pixelData[i * 4 + j * width4 + 2] !== 255 ||
          pixelData[i * 4 + j * width4 + 3] !== 255
        ) {
          minx = i;
          break;
        }
      }
    }

    metrics.ascent = baseline - ascent;
    metrics.descent = descent - baseline;
    metrics.minx = minx - padding / 2;
    metrics.height = metrics.descent + metrics.ascent;
  } else {
    metrics.ascent = 0;
    metrics.descent = 0;
    metrics.minx = 0;
    metrics.height = 0;
  }

  return metrics;
}

var imageSmoothingEnabledName;

/**
 * Writes the given text into a new canvas.  The canvas will be sized to fit the text.
 * If text is blank, returns undefined.
 *
 * @param {String} text The text to write.
 * @param {Object} [options] Object with the following properties:
 * @param {String} [options.font='10px sans-serif'] The CSS font to use.
 * @param {String} [options.textBaseline='bottom'] The baseline of the text.
 * @param {Boolean} [options.fill=true] Whether to fill the text.
 * @param {Boolean} [options.stroke=false] Whether to stroke the text.
 * @param {Color} [options.fillColor=Color.WHITE] The fill color.
 * @param {Color} [options.strokeColor=Color.BLACK] The stroke color.
 * @param {Number} [options.strokeWidth=1] The stroke width.
 * @param {Color} [options.backgroundColor=Color.TRANSPARENT] The background color of the canvas.
 * @param {Number} [options.padding=0] The pixel size of the padding to add around the text.
 * @returns {HTMLCanvasElement|undefined} A new canvas with the given text drawn into it.  The dimensions object
 *                   from measureText will also be added to the returned canvas. If text is
 *                   blank, returns undefined.
 * @function writeTextToCanvas
 */
function writeTextToCanvas(text, options) {
  //>>includeStart('debug', pragmas.debug);
  if (!defined(text)) {
    throw new DeveloperError("text is required.");
  }
  //>>includeEnd('debug');
  if (text === "") {
    return undefined;
  }

  options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  var font = defaultValue(options.font, "10px sans-serif");
  var stroke = defaultValue(options.stroke, false);
  var fill = defaultValue(options.fill, true);
  var strokeWidth = defaultValue(options.strokeWidth, 1);
  var backgroundColor = defaultValue(
    options.backgroundColor,
    Color.TRANSPARENT
  );
  var padding = defaultValue(options.padding, 0);
  var doublePadding = padding * 2.0;

  var canvas = document.createElement("canvas");
  canvas.width = 1;
  canvas.height = 1;
  canvas.style.font = font;
  var context2D = canvas.getContext("2d");

  if (!defined(imageSmoothingEnabledName)) {
    if (defined(context2D.imageSmoothingEnabled)) {
      imageSmoothingEnabledName = "imageSmoothingEnabled";
    } else if (defined(context2D.mozImageSmoothingEnabled)) {
      imageSmoothingEnabledName = "mozImageSmoothingEnabled";
    } else if (defined(context2D.webkitImageSmoothingEnabled)) {
      imageSmoothingEnabledName = "webkitImageSmoothingEnabled";
    } else if (defined(context2D.msImageSmoothingEnabled)) {
      imageSmoothingEnabledName = "msImageSmoothingEnabled";
    }
  }

  context2D.font = font;
  context2D.lineJoin = "round";
  context2D.lineWidth = strokeWidth;
  context2D[imageSmoothingEnabledName] = false;

  // in order for measureText to calculate style, the canvas has to be
  // (temporarily) added to the DOM.
  canvas.style.visibility = "hidden";
  document.body.appendChild(canvas);

  var dimensions = measureText(context2D, text, font, stroke, fill);
  canvas.dimensions = dimensions;

  document.body.removeChild(canvas);
  canvas.style.visibility = "";

  // Some characters, such as the letter j, have a non-zero starting position.
  // This value is used for kerning later, but we need to take it into account
  // now in order to draw the text completely on the canvas
  var x = -dimensions.minx;

  // Expand the width to include the starting position.
  var width = Math.ceil(dimensions.width) + x + doublePadding;

  // While the height of the letter is correct, we need to adjust
  // where we start drawing it so that letters like j and y properly dip
  // below the line.

  var height = dimensions.height + doublePadding;
  var baseline = height - dimensions.ascent + padding;
  var y = height - baseline + doublePadding;

  canvas.width = width;
  canvas.height = height;

  // Properties must be explicitly set again after changing width and height
  context2D.font = font;
  context2D.lineJoin = "round";
  context2D.lineWidth = strokeWidth;
  context2D[imageSmoothingEnabledName] = false;

  // Draw background
  if (backgroundColor !== Color.TRANSPARENT) {
    context2D.fillStyle = backgroundColor.toCssColorString();
    context2D.fillRect(0, 0, canvas.width, canvas.height);
  }

  if (stroke) {
    var strokeColor = defaultValue(options.strokeColor, Color.BLACK);
    context2D.strokeStyle = strokeColor.toCssColorString();
    context2D.strokeText(text, x + padding, y);
  }

  if (fill) {
    var fillColor = defaultValue(options.fillColor, Color.WHITE);
    context2D.fillStyle = fillColor.toCssColorString();
    context2D.fillText(text, x + padding, y);
  }

  return canvas;
}
export default writeTextToCanvas;
<commit_msg>PR feedback<commit_after>import Color from "./Color.js";
import defaultValue from "./defaultValue.js";
import defined from "./defined.js";
import DeveloperError from "./DeveloperError.js";

function measureText(context2D, textString, font, stroke, fill) {
  var metrics = context2D.measureText(textString);
  var isSpace = !/\S/.test(textString);

  if (!isSpace) {
    var fontSize = document.defaultView
      .getComputedStyle(context2D.canvas)
      .getPropertyValue("font-size")
      .replace("px", "");
    var canvas = document.createElement("canvas");
    var padding = 100;
    var width = (metrics.width + padding) | 0;
    var height = 3 * fontSize;
    var baseline = height / 2;
    canvas.width = width;
    canvas.height = height;

    var ctx = canvas.getContext("2d");
    ctx.font = font;
    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, canvas.width + 1, canvas.height + 1);

    if (stroke) {
      ctx.strokeStyle = "black";
      ctx.lineWidth = context2D.lineWidth;
      ctx.strokeText(textString, padding / 2, baseline);
    }

    if (fill) {
      ctx.fillStyle = "black";
      ctx.fillText(textString, padding / 2, baseline);
    }

    // Context image data has width * height * 4 elements, because
    // each pixel's R, G, B and A are consecutive values in the array.
    var pixelData = ctx.getImageData(0, 0, width, height).data;
    var length = pixelData.length;
    var width4 = width * 4;
    var i, j;

    var ascent, descent;
    // Find the number of rows (from the top) until the first non-white pixel
    for (i = 0; i < length; ++i) {
      if (pixelData[i] !== 255) {
        ascent = (i / width4) | 0;
        break;
      }
    }

    // Find the number of rows (from the bottom) until the first non-white pixel
    for (i = length - 1; i >= 0; --i) {
      if (pixelData[i] !== 255) {
        descent = (i / width4) | 0;
        break;
      }
    }

    var minx = -1;
    // For each column, for each row, check for first non-white pixel
    for (i = 0; i < width && minx === -1; ++i) {
      for (j = 0; j < height; ++j) {
        var pixelIndex = i * 4 + j * width4;
        if (
          pixelData[pixelIndex] !== 255 ||
          pixelData[pixelIndex + 1] !== 255 ||
          pixelData[pixelIndex + 2] !== 255 ||
          pixelData[pixelIndex + 3] !== 255
        ) {
          minx = i;
          break;
        }
      }
    }

    return {
      width: metrics.width,
      height: descent - ascent,
      ascent: baseline - ascent,
      descent: descent - baseline,
      minx: minx - padding / 2,
    };
  }

  return {
    ascent: 0,
    descent: 0,
    minx: 0,
    width: 0,
    height: 0,
  };
}

var imageSmoothingEnabledName;

/**
 * Writes the given text into a new canvas.  The canvas will be sized to fit the text.
 * If text is blank, returns undefined.
 *
 * @param {String} text The text to write.
 * @param {Object} [options] Object with the following properties:
 * @param {String} [options.font='10px sans-serif'] The CSS font to use.
 * @param {String} [options.textBaseline='bottom'] The baseline of the text.
 * @param {Boolean} [options.fill=true] Whether to fill the text.
 * @param {Boolean} [options.stroke=false] Whether to stroke the text.
 * @param {Color} [options.fillColor=Color.WHITE] The fill color.
 * @param {Color} [options.strokeColor=Color.BLACK] The stroke color.
 * @param {Number} [options.strokeWidth=1] The stroke width.
 * @param {Color} [options.backgroundColor=Color.TRANSPARENT] The background color of the canvas.
 * @param {Number} [options.padding=0] The pixel size of the padding to add around the text.
 * @returns {HTMLCanvasElement|undefined} A new canvas with the given text drawn into it.  The dimensions object
 *                   from measureText will also be added to the returned canvas. If text is
 *                   blank, returns undefined.
 * @function writeTextToCanvas
 */
function writeTextToCanvas(text, options) {
  //>>includeStart('debug', pragmas.debug);
  if (!defined(text)) {
    throw new DeveloperError("text is required.");
  }
  //>>includeEnd('debug');
  if (text === "") {
    return undefined;
  }

  options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  var font = defaultValue(options.font, "10px sans-serif");
  var stroke = defaultValue(options.stroke, false);
  var fill = defaultValue(options.fill, true);
  var strokeWidth = defaultValue(options.strokeWidth, 1);
  var backgroundColor = defaultValue(
    options.backgroundColor,
    Color.TRANSPARENT
  );
  var padding = defaultValue(options.padding, 0);
  var doublePadding = padding * 2.0;

  var canvas = document.createElement("canvas");
  canvas.width = 1;
  canvas.height = 1;
  canvas.style.font = font;
  var context2D = canvas.getContext("2d");

  if (!defined(imageSmoothingEnabledName)) {
    if (defined(context2D.imageSmoothingEnabled)) {
      imageSmoothingEnabledName = "imageSmoothingEnabled";
    } else if (defined(context2D.mozImageSmoothingEnabled)) {
      imageSmoothingEnabledName = "mozImageSmoothingEnabled";
    } else if (defined(context2D.webkitImageSmoothingEnabled)) {
      imageSmoothingEnabledName = "webkitImageSmoothingEnabled";
    } else if (defined(context2D.msImageSmoothingEnabled)) {
      imageSmoothingEnabledName = "msImageSmoothingEnabled";
    }
  }

  context2D.font = font;
  context2D.lineJoin = "round";
  context2D.lineWidth = strokeWidth;
  context2D[imageSmoothingEnabledName] = false;

  // in order for measureText to calculate style, the canvas has to be
  // (temporarily) added to the DOM.
  canvas.style.visibility = "hidden";
  document.body.appendChild(canvas);

  var dimensions = measureText(context2D, text, font, stroke, fill);
  // Set canvas.dimensions to be accessed in LabelCollection
  canvas.dimensions = dimensions;

  document.body.removeChild(canvas);
  canvas.style.visibility = "";

  // Some characters, such as the letter j, have a non-zero starting position.
  // This value is used for kerning later, but we need to take it into account
  // now in order to draw the text completely on the canvas
  var x = -dimensions.minx;

  // Expand the width to include the starting position.
  var width = Math.ceil(dimensions.width) + x + doublePadding;

  // While the height of the letter is correct, we need to adjust
  // where we start drawing it so that letters like j and y properly dip
  // below the line.

  var height = dimensions.height + doublePadding;
  var baseline = height - dimensions.ascent + padding;
  var y = height - baseline + doublePadding;

  canvas.width = width;
  canvas.height = height;

  // Properties must be explicitly set again after changing width and height
  context2D.font = font;
  context2D.lineJoin = "round";
  context2D.lineWidth = strokeWidth;
  context2D[imageSmoothingEnabledName] = false;

  // Draw background
  if (backgroundColor !== Color.TRANSPARENT) {
    context2D.fillStyle = backgroundColor.toCssColorString();
    context2D.fillRect(0, 0, canvas.width, canvas.height);
  }

  if (stroke) {
    var strokeColor = defaultValue(options.strokeColor, Color.BLACK);
    context2D.strokeStyle = strokeColor.toCssColorString();
    context2D.strokeText(text, x + padding, y);
  }

  if (fill) {
    var fillColor = defaultValue(options.fillColor, Color.WHITE);
    context2D.fillStyle = fillColor.toCssColorString();
    context2D.fillText(text, x + padding, y);
  }

  return canvas;
}
export default writeTextToCanvas;
<|endoftext|>


<commit_before>/* global Keen */
import Ember from 'ember';
import config from 'ember-get-config';

const {
  Service,
  Logger,
  RSVP,
  computed,
  typeOf
  } = Ember;

// See keen-js SDK's query events docs for more info:
// https://github.com/keen/keen-js/blob/master/docs/query.md#run-multiple-analyses-at-once

export default Service.extend({
  env: computed(function () {
    return config;
  }),

  projectId: computed('env', function () {   // String (required always)
    var projectId = this.get('env').KEEN_PROJECT_ID || Ember.$('meta[property="keen:project_id"]').attr('content') || window.KEEN_PROJECT_ID;
    if (!projectId) {
      Logger.info('Ember Keen Querying: Missing Keen project id, please set `ENV.KEEN_PROJECT_ID` in config.environment.js');
    }
    return projectId;
  }),

  readKey: computed('env', function () {   // String (required for sending data)
    var readKey = this.get('env').KEEN_READ_KEY || Ember.$('meta[property="keen:read_key"]').attr('content') || window.KEEN_READ_KEY;
    if (!readKey) {
      Logger.info('Ember Keen Querying: Missing Keen read key, please set `ENV.KEEN_READ_KEY` in config.environment.js');
    }
    return readKey;
  }),

  protocol: "auto",         // String (optional: https | http | auto)
  host: "api.keen.io/3.0",  // String (optional)
  requestType: null,        // String (optional: jsonp, xhr, beacon)

  client: computed('projectId', 'readKey', 'protocol', 'host', 'requestType', function () {
    return new Keen({
      projectId: this.get('projectId'),
      readKey: this.get('readKey'),
      protocol: this.get('protocol'),
      host: this.get('host'),
      requestType: this.get('requestType')
    });
  }),

  query: function (analysisType, eventOrParams) {
    var analysis = this._prepareAnalysis(analysisType, eventOrParams);
    return new RSVP.Promise((resolve, reject) => {
      this.get('client').run(analysis, (err, res) => {
        if (err) {
          reject(err);
        }
        else {
          resolve(res);
        }
      });
    });
  },

  // argument structure = {{analysisType1: eventOrParams1}, {analysisType2: eventOrParams2}, ...}
  // https://github.com/keen/keen-js/blob/master/docs/query.md#run-multiple-analyses-at-once
  multiQuery: function (queriesData) {
    var analyses = [];
    for (var key in queriesData) {
      var newAnalysis = this._prepareAnalysis(key, queriesData[key]);
      analyses.push(newAnalysis);
    }
    return new RSVP.Promise((resolve, reject) => {
      this.get('client').run(analyses, (err, res) => {
        if (err) {
          reject(err);
        }
        else {
          resolve(res);
        }
      });
    });
  },

  _prepareAnalysis: function (analysisType, eventOrParams) {
    var params = eventOrParams;
    if (typeOf(eventOrParams) === 'string') {
      params = {eventCollection: eventOrParams};
    }
    return new Keen.Query(analysisType, params);
  }
});
<commit_msg>Add documentation and fix jshint warnings<commit_after>/* global Keen */
import Ember from 'ember';
import config from 'ember-get-config';

const {
  Service,
  Logger,
  RSVP,
  computed,
  typeOf,
  isBlank
  } = Ember;

/**
 *  An Ember service for Keen.io that exposes querying and extraction APIs using the keen.js library.
 *
 * See [keen-js SDK's docs](https://github.com/keen/keen-js) for more info.
 *
 * @module keen-querying
 * @namespace Service
 * @class KeenQuerying
 * @extends Ember.Service
 */
export default Service.extend({
  env: computed(function () {
    return config;
  }),

  /**
   * The Keen Project ID
   * @required
   * @property
   * @type String
   */
  projectId: computed('env', function () {
    let projectId = this.get('env').KEEN_PROJECT_ID || Ember.$('meta[property="keen:project_id"]').attr('content') || window.KEEN_PROJECT_ID;
    if (isBlank(projectId)) {
      Logger.info('Ember Keen Querying: Missing Keen project id, please set ENV.KEEN_PROJECT_ID in config.environment.js');
    }
    return projectId;
  }),

  readKey: computed('env', function () {   // String (required for sending data)
    var readKey = this.get('env').KEEN_READ_KEY || Ember.$('meta[property="keen:read_key"]').attr('content') || window.KEEN_READ_KEY;
    if (isBlank(readKey)) {
      Logger.info('Ember Keen Querying: Missing Keen read key, please set ENV.KEEN_READ_KEY in config.environment.js');
    }
    return readKey;
  }),

  /**
   * Allowd values: https | http | auto
   * @property protocol
   * @default "auto"
   * @optional
   * @type String
   */
  protocol: "auto",
  /**
   * @property host
   * @default "api.keen.io/3.0"
   * @optional
   * @type String
   */
  host: "api.keen.io/3.0",
  /**
   * Allowd values: null, jsonp, xhr, beacon
   * @property requestType
   * @default null, decided by the Keen library
   * @optional
   * @type null|String
   */
  requestType: null,

  /**
   * The Keen client object, configured and ready to go.
   * @property client
   */
  client: computed('projectId', 'readKey', 'protocol', 'host', 'requestType', function () {
    return new Keen({
      projectId: this.get('projectId'),
      readKey: this.get('readKey'),
      protocol: this.get('protocol'),
      host: this.get('host'),
      requestType: this.get('requestType')
    });
  }),

  /**
   * Query a single event collection or extraction.
   *
   * @example
   *     keenQuerying.query('count', {
   *         event_collection: "pageviews",
   *         timeframe: {
   *           "start":"2015-07-01T07:00:00.000Z",
   *           "end":"2015-08-01T07:00:00.000Z"
   *      }).then(...)
   *
   * @param analysisType
   * @param eventOrParams
   * @returns {RSVP.Promise}
   */
  query: function (analysisType, eventOrParams) {
    var analysis = this._prepareAnalysis(analysisType, eventOrParams);
    return new RSVP.Promise((resolve, reject) => {
      this.get('client').run(analysis, (err, res) => {
        if (err) {
          reject(err);
        }
        else {
          resolve(res);
        }
      });
    });
  },

  //
  /**
   * TODO : fix these docs
   *  See [keen-js SDK's query events docs](https://github.com/keen/keen-js/blob/master/docs/query.md#run-multiple-analyses-at-once) for more info.
   *
   * argument structure = {{analysisType1: eventOrParams1}, {analysisType2: eventOrParams2}, ...}
   * @param queriesData a nested object of
   * @returns {RSVP.Promise}
     */
  multiQuery: function (queriesData) {
    var analyses = [];
    for (var key in queriesData) {
      var newAnalysis = this._prepareAnalysis(key, queriesData[key]);
      analyses.push(newAnalysis);
    }
    return new RSVP.Promise((resolve, reject) => {
      this.get('client').run(analyses, (err, res) => {
        if (err) {
          reject(err);
        }
        else {
          resolve(res);
        }
      });
    });
  },

  /**
   * Creates the Keen.Query object from parameters
   * @param analysisType
   * @param eventOrParams a bare event string or collection of params.
   * @returns {Keen.Query}
   * @private
   */
  _prepareAnalysis: function (analysisType, eventOrParams) {
    var params = eventOrParams;
    if (typeOf(eventOrParams) === 'string') {
      params = {eventCollection: eventOrParams};
    }
    return new Keen.Query(analysisType, params);
  }
});

<|endoftext|>


<commit_before>var inject = function() {

  if (!Array.prototype.find) {
    Array.prototype.find = function(predicate) {
      if (this == null) {
        throw new TypeError('Array.prototype.find called on null or undefined');
      }
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }
      var list = Object(this);
      var length = list.length >>> 0;
      var thisArg = arguments[1];
      var value;

      for (var i = 0; i < length; i++) {
        value = list[i];
        if (predicate.call(thisArg, value, i, list)) {
          return value;
        }
      }
      return undefined;
    };
  }

  document.head.appendChild((function() {

    var fn = function bootstrap(window) {

      function disablePlugin(reason) {
        console.log(arguments);
        console.log(reason);
      }

      var angular = window.angular;

      // Helper to determine if the root 'ng' module has been loaded
      // window.angular may be available if the app is bootstrapped asynchronously, but 'ng' might
      // finish loading later.
      function ngLoaded() {
        if (!window.angular) {
          return false;
        }
        try {
          window.angular.module('ng');
        } catch (e) {
          return false;
        }
        return true;
      }

      if (!ngLoaded()) {
        (function() {
          // TODO: var name
          var areWeThereYet = function(ev) {

            if (ev.srcElement.tagName === 'SCRIPT') {
              console.log(ev.srcElement);
              var oldOnload = ev.srcElement.onload;
              ev.srcElement.onload = function() {
                if (ngLoaded()) {

                  document.removeEventListener('DOMNodeInserted', areWeThereYet);
                  bootstrap(window);
                }
                if (oldOnload) {
                  oldOnload.apply(this, arguments);
                }
              };
            }
          };
          document.addEventListener('DOMNodeInserted', areWeThereYet);
        }());
        return;
      }

      // do not patch twice
      if (window.__ngDependencyGraph) {
        return;
      }

      // helper to extract dependencies from function arguments
      // not all versions of AngularJS expose annotate
      var annotate; // = angular.injector().annotate;
      if (!annotate) {
        annotate = (function() {

          var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
          var FN_ARG_SPLIT = /,/;
          var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
          var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;

          // TODO: should I keep these assertions?
          function assertArg(arg, name, reason) {
            if (!arg) {
              throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required"));
            }
            return arg;
          }

          function assertArgFn(arg, name, acceptArrayAnnotation) {
            if (acceptArrayAnnotation && angular.isArray(arg)) {
              arg = arg[arg.length - 1];
            }

            assertArg(angular.isFunction(arg), name, 'not a function, got ' +
              (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
            return arg;
          }

          return function(fn) {
            var $inject,
              fnText,
              argDecl,
              last;

            if (typeof fn == 'function') {
              if (!($inject = fn.$inject)) {
                $inject = [];
                fnText = fn.toString().replace(STRIP_COMMENTS, '');
                argDecl = fnText.match(FN_ARGS);
                argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
                  arg.replace(FN_ARG, function(all, underscore, name) {
                    $inject.push(name);
                  });
                });
                fn.$inject = $inject;
              }
            } else if (angular.isArray(fn)) {
              last = fn.length - 1;
              assertArgFn(fn[last], 'fn');
              $inject = fn.slice(0, last);
            } else {
              console.log('ble!');
              console.log(fn);

              assertArgFn(fn, 'fn', true);
            }
            return $inject;
          };
        }());
      }

      var api = window.__ngDependencyGraph = {
        getMetadata: function() {
          return metadata;
        }
      };

      var metadata = {
        angularVersion: null,
        apps: [],
        modules: []
      };

      angular.forEach(document.querySelectorAll('[ng-app]'),
        function(elm) {
          var appName = elm.getAttribute('ng-app');
          if (metadata.apps.indexOf(appName) === -1) {
            console.log(appName);
            metadata.apps.push(appName);
            createModule(appName);
          }
        });

      function createModule(name) {
        var exist = _.find(metadata.modules, {name: name});
        if (exist || name === undefined) return;

        var module = angular.module(name);

        var moduleData = {
          name: name,
          deps: module.requires,
          components: []
        };

        processModule(moduleData);
        metadata.modules.push(moduleData);

        angular.forEach(module.requires, function(mod) {
          createModule(mod);
        });

      }

      function addDeps(moduleData, name, fn, type) {
        if (fn.constructor !== Function) {
          moduleData.components.push({
            name: name,
            type: type
          });
        } else {
          moduleData.components.push({
            name: name,
            deps: annotate(fn),
            type: type
          });
        }
      }

      function processModule(moduleData) {
        var moduleName = moduleData.name;
        console.log('Processing: ' + moduleName);
        var module = angular.module(moduleName);

        angular.forEach(module._invokeQueue, function(item) {
          var compArgs = item[2];
          if (typeof item[2][1] == 'string') {
            debugger;
          }
          switch (item[0]) {
            case '$provide':
              switch (item[1]) {
                case 'value':
                  addDeps(moduleData, compArgs[0], compArgs[1], 'value');
                  addDeps(moduleData, compArgs[0], compArgs[1], 'constant');
                  break;

                default:
                  addDeps(moduleData, compArgs[0], compArgs[1], 'service');

                  break;
              }

              break;

            case '$filterProvider':
              addDeps(moduleData, compArgs[0], compArgs[1], 'filter');
              break;
            case '$animateProvider':
              addDeps(moduleData, compArgs[0], compArgs[1], 'animation');
              break;
            case '$controllerProvider':
              addDeps(moduleData, compArgs[0], compArgs[1], 'controller');
              break;
            case '$compileProvider':
              if (compArgs[1].constructor === Object) {
                angular.forEach(compArgs[1], function(key, value) {
                  addDeps(moduleData, key, value, 'directive');
                });
              }

              addDeps(moduleData, compArgs[0], compArgs[1], 'directive');
              break;
            default:
              disablePlugin('unknown dendency type', item[0]);
              break;
          }

        });

      }
    };

    // Return a script element with the above code embedded in it
    var script = window.document.createElement('script');
    script.innerHTML = '(' + fn.toString() + '(window))';

    return script;
  }()));
};

// first sniff out
// inject();

// only inject if cookie is set
// if (document.cookie.indexOf('__ngDependencyGraph=true') != -1) {
document.addEventListener('DOMContentLoaded', inject);
// }
<commit_msg>debug, clean up<commit_after>var inject = function() {

  document.head.appendChild((function() {

    var fn = function bootstrap(window) {

      if (!Array.prototype.find) {
        Array.prototype.find = function(predicate) {
          if (this == null) {
            throw new TypeError('Array.prototype.find called on null or undefined');
          }
          if (typeof predicate !== 'function') {
            throw new TypeError('predicate must be a function');
          }
          var list = Object(this);
          var length = list.length >>> 0;
          var thisArg = arguments[1];
          var value;

          for (var i = 0; i < length; i++) {
            value = list[i];
            if (predicate.call(thisArg, value, i, list)) {
              return value;
            }
          }
          return undefined;
        };
      }

      function disablePlugin(reason) {
        console.log(arguments);
        console.log(reason);
      }

      var angular = window.angular;

      // Helper to determine if the root 'ng' module has been loaded
      // window.angular may be available if the app is bootstrapped asynchronously, but 'ng' might
      // finish loading later.
      function ngLoaded() {
        if (!window.angular) {
          return false;
        }
        try {
          window.angular.module('ng');
        } catch (e) {
          return false;
        }
        return true;
      }

      if (!ngLoaded()) {
        (function() {
          // TODO: var name
          var areWeThereYet = function(ev) {

            if (ev.srcElement.tagName === 'SCRIPT') {
              var oldOnload = ev.srcElement.onload;
              ev.srcElement.onload = function() {
                if (ngLoaded()) {

                  document.removeEventListener('DOMNodeInserted', areWeThereYet);
                  bootstrap(window);
                }
                if (oldOnload) {
                  oldOnload.apply(this, arguments);
                }
              };
            }
          };
          document.addEventListener('DOMNodeInserted', areWeThereYet);
        }());
        return;
      }

      // do not patch twice
      if (window.__ngDependencyGraph) {
        return;
      }

      // helper to extract dependencies from function arguments
      // not all versions of AngularJS expose annotate
      var annotate; // = angular.injector().annotate;
      if (!annotate) {
        annotate = (function() {

          var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
          var FN_ARG_SPLIT = /,/;
          var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
          var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;

          // TODO: should I keep these assertions?
          function assertArg(arg, name, reason) {
            if (!arg) {
              throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required"));
            }
            return arg;
          }

          function assertArgFn(arg, name, acceptArrayAnnotation) {
            if (acceptArrayAnnotation && angular.isArray(arg)) {
              arg = arg[arg.length - 1];
            }

            assertArg(angular.isFunction(arg), name, 'not a function, got ' +
              (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
            return arg;
          }

          return function(fn) {
            var $inject,
              fnText,
              argDecl,
              last;

            if (typeof fn == 'function') {
              if (!($inject = fn.$inject)) {
                $inject = [];
                fnText = fn.toString().replace(STRIP_COMMENTS, '');
                argDecl = fnText.match(FN_ARGS);
                argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
                  arg.replace(FN_ARG, function(all, underscore, name) {
                    $inject.push(name);
                  });
                });
                fn.$inject = $inject;
              }
            } else if (angular.isArray(fn)) {
              last = fn.length - 1;
              assertArgFn(fn[last], 'fn');
              $inject = fn.slice(0, last);
            } else {
              assertArgFn(fn, 'fn', true);
            }
            return $inject;
          };
        }());
      }

      window.__ngDependencyGraph = {
        getMetadata: function() {
          return metadata;
        }
      };

      var metadata = {
        angularVersion: angular.version,
        apps: [],
        modules: []
      };

      angular.forEach(document.querySelectorAll('[ng-app]'),
        function(elm) {
          var appName = elm.getAttribute('ng-app');
          if (metadata.apps.indexOf(appName) === -1) {
            metadata.apps.push(appName);
            createModule(appName);
            console.log('oj!');
          }
        });

      function createModule(name) {
        var exist = metadata.modules.find(function(mod) {
          return mod.name === name;
        });
        if (exist || name === undefined) return;

        var module = angular.module(name);

        var moduleData = {
          name: name,
          deps: module.requires,
          components: []
        };

        console.log(moduleData);

        processModule(moduleData);
        metadata.modules.push(moduleData);

        angular.forEach(module.requires, function(mod) {
          createModule(mod);
        });

      }

      function addDeps(moduleData, name, fn, type) {
        if (fn.constructor !== Function) {
          moduleData.components.push({
            name: name,
            type: type
          });
        } else {
          moduleData.components.push({
            name: name,
            deps: annotate(fn),
            type: type
          });
        }
      }

      function processModule(moduleData) {
        var moduleName = moduleData.name;
        console.log('Processing: ' + moduleName);
        var module = angular.module(moduleName);

        angular.forEach(module._invokeQueue, function(item) {
          var compArgs = item[2];
          // console.log(item);
          // if (typeof item[2][1] == 'string') {
          //   debugger;
          // }
          switch (item[0]) {
            case '$provide':
              switch (item[1]) {
                case 'value':
                  addDeps(moduleData, compArgs[0], compArgs[1], 'value');
                  addDeps(moduleData, compArgs[0], compArgs[1], 'constant');
                  break;

                default:
                  addDeps(moduleData, compArgs[0], compArgs[1], 'service');

                  break;
              }

              break;

            case '$filterProvider':
              addDeps(moduleData, compArgs[0], compArgs[1], 'filter');
              break;
            case '$animateProvider':
              addDeps(moduleData, compArgs[0], compArgs[1], 'animation');
              break;
            case '$controllerProvider':
              addDeps(moduleData, compArgs[0], compArgs[1], 'controller');
              break;
            case '$compileProvider':
              if (compArgs[1].constructor === Object) {
                angular.forEach(compArgs[1], function(key, value) {
                  addDeps(moduleData, key, value, 'directive');
                });
              }

              addDeps(moduleData, compArgs[0], compArgs[1], 'directive');
              break;
            default:
              disablePlugin('unknown dendency type', item[0]);
              break;
          }

        });

      }
    };

    // Return a script element with the above code embedded in it
    var script = window.document.createElement('script');
    script.innerHTML = '(' + fn.toString() + '(window))';

    return script;
  }()));
};

// first sniff out
// inject();

// only inject if cookie is set
// if (document.cookie.indexOf('__ngDependencyGraph=true') != -1) {
document.addEventListener('DOMContentLoaded', inject);
// }
<|endoftext|>


<commit_before>import Transform from './Transform';
import Stats from '../server/Stats';

export default class StatsTransform extends Transform {
  constructor(opts, config, logger) {
    super(opts, config, logger);

    this._stats = new Stats(config, logger);
    this._type = this.getOption('type', 'increment');
    this._name = this.getOption('name');
    this._value = this.getOption('value', '1');
  }

  close() {
    this._stats.close();
  }

  process(event) {
    try {
      const value = parseInt(this._value.render(event), 10);
      const type = this._type.render(event);
      const name = this._name.render(event);

      switch (type) {
        case 'increment':
          this._stats.increment(key, value);
          break;
        case 'gauge':
          this._stats.gauge(name, value);
          break;
      }

      return this.emit(null);
    } catch (e) {
      return this.fail(e);
    }
  }
}
<commit_msg>Fixed incorrect name for stats increment transform.<commit_after>import Transform from './Transform';
import Stats from '../server/Stats';

export default class StatsTransform extends Transform {
  constructor(opts, config, logger) {
    super(opts, config, logger);

    this._stats = new Stats(config, logger);
    this._type = this.getOption('type', 'increment');
    this._name = this.getOption('name');
    this._value = this.getOption('value', '1');
  }

  close() {
    this._stats.close();
  }

  process(event) {
    try {
      const value = parseInt(this._value.render(event), 10);
      const type = this._type.render(event);
      const name = this._name.render(event);

      switch (type) {
        case 'increment':
          this._stats.increment(name, value);
          break;
        case 'gauge':
          this._stats.gauge(name, value);
          break;
      }

      return this.emit(null);
    } catch (e) {
      return this.fail(e);
    }
  }
}
<|endoftext|>


<commit_before>'use strict';

const log = require('server/util/logapp.js');
const storage = require('server/storage');
const preload = require('server/storage/preload.js');
const sttsubmission = require('server/stt/sttsubmission.js');

module.exports = () => {
  const preloadMetadata = storage.db.sync()
  .then(() => [
    {
      filename: 'riders.csv',
      handler: sttsubmission.metaPeople,
      attributes: {key: 'rider_key', value: 'rider'}
    }, {
      filename: 'conditions.csv',
      handler: sttsubmission.metaStatuses,
      attributes: {key: 'cond_key', value: 'cond'}
    }, {
      filename: 'districts.csv',
      handler: sttsubmission.metaDistricts,
      attributes: {key: 'district_key', value: 'district'}
    }, {
      filename: 'labs.csv',
      handler: sttsubmission.metaLabs,
      attributes: {key: 'lab_key', value: 'lab', district: 'district'}
    }, {
      filename: 'facilities.csv',
      handler: sttsubmission.metaFacilities,
      attributes: {key: 'facility_key', value: 'facility', region: 'lab'}
    }, {
      filename: 'stypes.csv',
      handler: sttsubmission.metaArtifacts,
      attributes: {key: 'stype_key', value: 'stype'}
    }, {
      filename: 'stages.csv',
      handler: sttsubmission.metaStages,
      attributes: {key: 'stages_key', value: 'stage'}
    }
  ])
  .mapSeries(preload.metadata)
  .then(() => log.info('Metadata preload completed'))
  .catch(err => log.error(err, err.stack));
  return preloadMetadata;
};
<commit_msg>preload labstatus data<commit_after>'use strict';

const log = require('server/util/logapp.js');
const storage = require('server/storage');
const preload = require('server/storage/preload.js');
const sttsubmission = require('server/stt/sttsubmission.js');

module.exports = () => {
  const preloadMetadata = storage.db.sync()
  .then(() => [
    {
      filename: 'riders.csv',
      handler: sttsubmission.metaPeople,
      attributes: {key: 'rider_key', value: 'rider'}
    }, {
      filename: 'conditions.csv',
      handler: sttsubmission.metaStatuses,
      attributes: {key: 'cond_key', value: 'cond'}
    }, {
      filename: 'labstatus.csv',
      handler: sttsubmission.metaStatuses,
      attributes: {key: 'status_key', value: 'status'}
    }, {
      filename: 'districts.csv',
      handler: sttsubmission.metaDistricts,
      attributes: {key: 'district_key', value: 'district'}
    }, {
      filename: 'labs.csv',
      handler: sttsubmission.metaLabs,
      attributes: {key: 'lab_key', value: 'lab', district: 'district'}
    }, {
      filename: 'facilities.csv',
      handler: sttsubmission.metaFacilities,
      attributes: {key: 'facility_key', value: 'facility', region: 'lab'}
    }, {
      filename: 'stypes.csv',
      handler: sttsubmission.metaArtifacts,
      attributes: {key: 'stype_key', value: 'stype'}
    }, {
      filename: 'stages.csv',
      handler: sttsubmission.metaStages,
      attributes: {key: 'stages_key', value: 'stage'}
    }
  ])
  .mapSeries(preload.metadata)
  .then(() => log.info('Metadata preload completed'))
  .catch(err => log.error(err, err.stack));
  return preloadMetadata;
};
<|endoftext|>


<commit_before>/*-
 * Copyright (c) 2016 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

graphTypes = [ {
    id : 'isz',
    title : 'Install size',
    index : 3
}, {
    id : 'dsz',
    title : 'Download size',
    index : 4
}, {
    id : 'dcn',
    title : 'Dependency count',
    index : 5
}, {
    id : 'fcn',
    title : 'File count',
    index : 6
} ];

var selectedId;

function findInstallationIdByTimestamp(collData, timestamp) {
    for (var i = 0; i < collData.length; i++) {
        var inst = collData[i];
        if (inst[1] == timestamp) {
            return inst[0];
        }
    }
    return undefined;
}

function graphClickHandler(collData, e, id) {
    if (e.shiftKey && selectedId) {
        location.href = "installation/diff/" + selectedId + "/" + id;
    } else if (e.ctrlKey) {
        location.href = "installation/" + id;
    } else {
        selectedId = id;
    }
}

function createGraph(domElement, collData, graphType) {
    var options = {
        labels : [ 'Timestamp', graphType.title ],
        clickCallback : function(e, x, pts) {
            var id = findInstallationIdByTimestamp(collData, x);
            if (id) {
                graphClickHandler(collData, e, id);
            }
        }
    };
    var graphData = [];
    collData.forEach(function(inst) {
        var timestamp = new Date(inst[1]);
        var value = inst[graphType.index];
        graphData.push([ timestamp, value ]);
    });
    new Dygraph(domElement, graphData, options);
}

function loadGraphs(data) {
    var bar = {};
    for ( var collName in data) {
        if (data.hasOwnProperty(collName)) {
            var collData = data[collName];
            graphTypes
                    .forEach(function(graphType) {
                        $(".coll-" + collName).find(".chart-" + graphType.id)
                                .each(function() {
                                    createGraph(this, collData, graphType);
                                });
                        if (!bar[graphType.id]) {
                            bar[graphType.id] = {
                                labels : [],
                                datasets : [ {
                                    data : []
                                } ]
                            };
                        }
                        if (collData.length > 0) {
                            bar[graphType.id]['labels'].push(collName);
                            bar[graphType.id]['datasets'][0]['data']
                                    .push(collData[collData.length - 1][graphType.index]);
                        }
                    });
        }
    }
    graphTypes.forEach(function(graphType) {
        $("#bar-" + graphType.id).each(function() {
            var dataWidth = bar[graphType.id]['datasets'][0]['data'].length;
            // XXX don't hardcode sizes here
            $(this).width(150 + 40 * dataWidth);
            var ctx = this.getContext('2d');
            var chart = new Chart(ctx).Bar(bar[graphType.id]);
            this.onclick = function(e) {
                var activeBars = chart.getBarsAtEvent(e);
                if (activeBars.length > 0) {
                    var collName = activeBars[0]['label'];
                    var collData = data[collName];
                    var id = collData[collData.length - 1][0];
                    graphClickHandler(collData, e, id);
                }
            };
        });
    });
}

$(document).ready(function() {
    $.getJSON('/insim/api/data/installations/' + jsf.packageName, loadGraphs)
});
<commit_msg>Improve line chart sizing<commit_after>/*-
 * Copyright (c) 2016 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

graphTypes = [ {
    id : 'isz',
    title : 'Install size',
    index : 3
}, {
    id : 'dsz',
    title : 'Download size',
    index : 4
}, {
    id : 'dcn',
    title : 'Dependency count',
    index : 5
}, {
    id : 'fcn',
    title : 'File count',
    index : 6
} ];

var selectedId;

function findInstallationIdByTimestamp(collData, timestamp) {
    for (var i = 0; i < collData.length; i++) {
        var inst = collData[i];
        if (inst[1] == timestamp) {
            return inst[0];
        }
    }
    return undefined;
}

function graphClickHandler(collData, e, id) {
    if (e.shiftKey && selectedId) {
        location.href = "installation/diff/" + selectedId + "/" + id;
    } else if (e.ctrlKey) {
        location.href = "installation/" + id;
    } else {
        selectedId = id;
    }
}

function createGraph(domElement, collData, graphType) {
    var dataWidth = collData.length;
    var maxWidth = $(domElement).parent().width();
    // XXX don't hardcode sizes here
    var width = Math.min(100 + 20 * dataWidth, maxWidth);
    var options = {
        width : width,
        labels : [ 'Timestamp', graphType.title ],
        clickCallback : function(e, x, pts) {
            var id = findInstallationIdByTimestamp(collData, x);
            if (id) {
                graphClickHandler(collData, e, id);
            }
        }
    };
    var graphData = [];
    collData.forEach(function(inst) {
        var timestamp = new Date(inst[1]);
        var value = inst[graphType.index];
        graphData.push([ timestamp, value ]);
    });
    new Dygraph(domElement, graphData, options);
}

function loadGraphs(data) {
    var bar = {};
    for ( var collName in data) {
        if (data.hasOwnProperty(collName)) {
            var collData = data[collName];
            graphTypes
                    .forEach(function(graphType) {
                        $(".coll-" + collName).find(".chart-" + graphType.id)
                                .each(function() {
                                    createGraph(this, collData, graphType);
                                });
                        if (!bar[graphType.id]) {
                            bar[graphType.id] = {
                                labels : [],
                                datasets : [ {
                                    data : []
                                } ]
                            };
                        }
                        if (collData.length > 0) {
                            bar[graphType.id]['labels'].push(collName);
                            bar[graphType.id]['datasets'][0]['data']
                                    .push(collData[collData.length - 1][graphType.index]);
                        }
                    });
        }
    }
    graphTypes.forEach(function(graphType) {
        $("#bar-" + graphType.id).each(function() {
            var dataWidth = bar[graphType.id]['datasets'][0]['data'].length;
            // XXX don't hardcode sizes here
            $(this).width(150 + 40 * dataWidth);
            var ctx = this.getContext('2d');
            var chart = new Chart(ctx).Bar(bar[graphType.id]);
            this.onclick = function(e) {
                var activeBars = chart.getBarsAtEvent(e);
                if (activeBars.length > 0) {
                    var collName = activeBars[0]['label'];
                    var collData = data[collName];
                    var id = collData[collData.length - 1][0];
                    graphClickHandler(collData, e, id);
                }
            };
        });
    });
}

$(document).ready(function() {
    $.getJSON('/insim/api/data/installations/' + jsf.packageName, loadGraphs)
});
<|endoftext|>


<commit_before>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

YUI.add('charmstore-api', function(Y) {

  /**
    Implementation of the charmstore v4 api.

    @class APIv4
  */
  function APIv4(config) {
    this.charmstoreURL = config.charmstoreURL;
    this.apiPath = 'v4';
    // We are using the webHandler class included in our source as a wrapper
    // around XHR. In the future if we would like to provide this class
    // as a public module for people to interact with the charmstore v4 api
    // then we should accept a requestHandler class being passed in on
    // instantiation as well as a different _makeRequest method for the
    // prototype.
    this.requestHandler = new Y.juju.environments.web.WebHandler();
  }

  APIv4.prototype = {
    /**
      Takes the path supplied by the caller and makes a request to the
      requestHandler instance.

      @method _makeRequest
      @param {String} The path to make the api request to.
      @param {Function} successCallback Called when the api request completes
        successfully.
      @param {Function} failureCallback Called when the api request fails
        with a response of >= 400.
    */
    _makeRequest: function(path, successCallback, failureCallback) {
      this.requestHandler.sendGetRequest(
          path,
          // The WebHandler methods allow you to pass in headers, username,
          // password, progressCallback which we do not need.
          null, null, null, null,
          this._requestHandler.bind(this, successCallback, failureCallback));
    },

    /**
      Handles the request response from the _makeRequest method, calling the
      supplied failure callback if the response status was >= 400 or passing the
      response object to the supplied success callback.

      @method _requestHandler
      @param {Function} successCallback Called when the api request completes
        successfully.
      @param {Function} failureCallback Called when the api request fails
        with a response of >= 400.
      @param {Object} response The XHR response object.
    */
    _requestHandler: function(successCallback, failureCallback, response) {
      var target = response.target;
      if (target.status >= 400) {
        failureCallback(response);
        return;
      }
      successCallback(response);
    },

    /**
      Generates a path to the charmstore apiv4 based on the query and endpoint
      params passed in.

      @method _generatePath
      @param {String} endpoint The endpoint to call at the charmstore.
      @param {Object} query The query parameters that are required for the
        request.
      @return {String} A charmstore url based on the query and endpoint params
        passed in.
    */
    _generatePath: function(endpoint, query) {
      query = query ? '?' + query : '';
      return this.charmstoreURL + this.apiPath + '/' + endpoint + query;
    },

    /**
      Transforms the results from a charmstore query into model objects.

      @method _transformQueryResults
      @param {Function} successCallback Called when the api request completes
        successfully.
      @param {Object} response Thre XHR response object.
    */
    _transformQueryResults: function(successCallback, response) {
      var data = JSON.parse(response.target.responseText);
    },

    /**
      Makes a search request using the supplied filters and returns the
      results to the supplied callback.

      @method search
      @param {Object} filters The additional filters to use to make the
        search request such as { text: 'apache' }.
      @param {Function} successCallback Called when the api request completes
        successfully.
      @param {Function} failureCallback Called when the api request fails
        with a response of >= 400.
    */
    search: function(filters, successCallback, failureCallback) {
      var defaultFilters =
                        '&limit=20&' +
                        'include=charm-metadata&' +
                        'include=bundle-metadata&' +
                        'include=extra-info&' +
                        'include=stats';

      var path = this._generatePath(
          'search', Y.QueryString.stringify(filters) + defaultFilters);
      this._makeRequest(
          path,
          this._transformQueryResults.bind(this, successCallback),
          failureCallback);
    },

    /**
      Returns the correct path for a charm or bundle icon provided an id and
      whether or not it is a bundle.

      This method should not be called directly from within the application.
      Instead use utils.getIconPath() as it handles local charms as well and
      then defaults to this method if it's not local.

      @method getIconPath
      @param {String} charmId The id of the charm to fetch the icon for.
      @param {Boolean} isBundle Whether or not this is an icon for a bundle.
      @return {String} The URL of the charm's icon.
    */
    getIconPath: function(charmId, isBundle) {
      var path;
      if (typeof isBundle === 'boolean' && isBundle) {
        path = '/juju-ui/assets/images/non-sprites/bundle.svg';
      } else {
        // Get the charm ID from the service.  In some cases, this will be
        // the charm URL with a protocol, which will need to be removed.
        // The following regular expression removes everything up to the
        // colon portion of the quote and leaves behind a charm ID.
        charmId = charmId.replace(/^[^:]+:/, '');
        // Note that we make sure isBundle is Boolean. It's coming from a
        // handlebars template helper which will make the second argument the
        // context object when it's not supplied. We want it optional for
        // normal use to default to the charm version, but if it's a boolean,
        // then check that boolean because the author cares specifically if
        // it's a bundle or not.
        path = this.charmstoreURL + [
          this.apiPath, charmId, 'icon.svg'].join('/');
      }
      return path;
    }
  };

  Y.namespace('juju.charmstore').APIv4 = APIv4;

}, '', {
  requires: [
    'juju-env-web-handler',
    'querystring-stringify'
  ]
});
<commit_msg>Transform and process the results from a charmstore search query into models for the rest of the app to work with<commit_after>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

YUI.add('charmstore-api', function(Y) {

  var jujuModels = Y.juju.models;

  /**
    Implementation of the charmstore v4 api.

    @class APIv4
  */
  function APIv4(config) {
    this.charmstoreURL = config.charmstoreURL;
    this.apiPath = 'v4';
    // We are using the webHandler class included in our source as a wrapper
    // around XHR. In the future if we would like to provide this class
    // as a public module for people to interact with the charmstore v4 api
    // then we should accept a requestHandler class being passed in on
    // instantiation as well as a different _makeRequest method for the
    // prototype.
    this.requestHandler = new Y.juju.environments.web.WebHandler();
  }

  APIv4.prototype = {
    /**
      Takes the path supplied by the caller and makes a request to the
      requestHandler instance.

      @method _makeRequest
      @param {String} The path to make the api request to.
      @param {Function} successCallback Called when the api request completes
        successfully.
      @param {Function} failureCallback Called when the api request fails
        with a response of >= 400.
    */
    _makeRequest: function(path, successCallback, failureCallback) {
      this.requestHandler.sendGetRequest(
          path,
          // The WebHandler methods allow you to pass in headers, username,
          // password, progressCallback which we do not need.
          null, null, null, null,
          this._requestHandler.bind(this, successCallback, failureCallback));
    },

    /**
      Handles the request response from the _makeRequest method, calling the
      supplied failure callback if the response status was >= 400 or passing the
      response object to the supplied success callback.

      @method _requestHandler
      @param {Function} successCallback Called when the api request completes
        successfully.
      @param {Function} failureCallback Called when the api request fails
        with a response of >= 400.
      @param {Object} response The XHR response object.
    */
    _requestHandler: function(successCallback, failureCallback, response) {
      var target = response.target;
      if (target.status >= 400) {
        failureCallback(response);
        return;
      }
      successCallback(response);
    },

    /**
      Generates a path to the charmstore apiv4 based on the query and endpoint
      params passed in.

      @method _generatePath
      @param {String} endpoint The endpoint to call at the charmstore.
      @param {Object} query The query parameters that are required for the
        request.
      @return {String} A charmstore url based on the query and endpoint params
        passed in.
    */
    _generatePath: function(endpoint, query) {
      query = query ? '?' + query : '';
      return this.charmstoreURL + this.apiPath + '/' + endpoint + query;
    },

    /**
      Transforms the results from a charmstore query into model objects.

      @method _transformQueryResults
      @param {Function} successCallback Called when the api request completes
        successfully.
      @param {Object} response Thre XHR response object.
    */
    _transformQueryResults: function(successCallback, response) {
      var data = JSON.parse(response.target.responseText).Results;
      var models = data.map(function(entity) {
        var entityData = this._processEntityQueryData(entity);
        if (entityData.entityType === 'charm') {
          return new jujuModels.Charm(entityData);
        } else {
          return new jujuModels.Bundle(entityData);
        }
      }, this);
      successCallback(models);
    },

    /**
      The response object returned from the apiv4 search endpoint is a complex
      object with golang style keys. This parses the complex object and
      returns something that we use to instantiate new charm and bundle models.

      @method _processEntityQueryData
      @param {Object} data The entities data from the charmstore search api.
      @return {Object} The processed data structure.
    */
    _processEntityQueryData: function(data) {
      var meta = data.Meta,
          extraInfo = meta['extra-info'],
          charmMeta = meta['charm-metadata'],
          bundleMeta = meta['bundle-metadata'];
      // Singletons and keys which are outside of the common structure
      var processed = {
        id: data.Id,
        downloads: meta.stats.ArchiveDownloadCount,
        entityType: (charmMeta) ? 'charm' : 'bundle',
        // If the id has a user segment then it has not been promulgated.
        is_approved: data.Id.indexOf('~') > 0 ? false : true,
        owner: extraInfo['bzr-owner'],
        revisions: extraInfo['bzr-revisions']
      };
      // An entity will only have one or the other.
      var metadata = (charmMeta) ? charmMeta : bundleMeta;
      Object.keys(metadata).forEach(function(key) {
        processed[key.toLowerCase()] = metadata[key];
      });
      // Bundles do not have a provided name from the api so we need to parse
      // the name from the id to match the model.
      if (!processed.name) {
        var idParts = data.Id.split('/');
        // The last section will have the name of the bundle.
        idParts = idParts[idParts.length - 1];
        // Need to strip the revision number off of the end.
        idParts = idParts.split('-').slice(0, -1);
        processed.name = idParts.join('-');
      }
      return processed;
    },

    /**
      Makes a search request using the supplied filters and returns the
      results to the supplied callback.

      @method search
      @param {Object} filters The additional filters to use to make the
        search request such as { text: 'apache' }.
      @param {Function} successCallback Called when the api request completes
        successfully.
      @param {Function} failureCallback Called when the api request fails
        with a response of >= 400.
    */
    search: function(filters, successCallback, failureCallback) {
      var defaultFilters =
                        '&limit=30&' +
                        'include=charm-metadata&' +
                        'include=bundle-metadata&' +
                        'include=extra-info&' +
                        'include=stats';

      var path = this._generatePath(
          'search', Y.QueryString.stringify(filters) + defaultFilters);
      this._makeRequest(
          path,
          this._transformQueryResults.bind(this, successCallback),
          failureCallback);
    },

    /**
      Returns the correct path for a charm or bundle icon provided an id and
      whether or not it is a bundle.

      This method should not be called directly from within the application.
      Instead use utils.getIconPath() as it handles local charms as well and
      then defaults to this method if it's not local.

      @method getIconPath
      @param {String} charmId The id of the charm to fetch the icon for.
      @param {Boolean} isBundle Whether or not this is an icon for a bundle.
      @return {String} The URL of the charm's icon.
    */
    getIconPath: function(charmId, isBundle) {
      var path;
      if (typeof isBundle === 'boolean' && isBundle) {
        path = '/juju-ui/assets/images/non-sprites/bundle.svg';
      } else {
        // Get the charm ID from the service.  In some cases, this will be
        // the charm URL with a protocol, which will need to be removed.
        // The following regular expression removes everything up to the
        // colon portion of the quote and leaves behind a charm ID.
        charmId = charmId.replace(/^[^:]+:/, '');
        // Note that we make sure isBundle is Boolean. It's coming from a
        // handlebars template helper which will make the second argument the
        // context object when it's not supplied. We want it optional for
        // normal use to default to the charm version, but if it's a boolean,
        // then check that boolean because the author cares specifically if
        // it's a bundle or not.
        path = this.charmstoreURL + [
          this.apiPath, charmId, 'icon.svg'].join('/');
      }
      return path;
    }
  };

  Y.namespace('juju.charmstore').APIv4 = APIv4;

}, '', {
  requires: [
    'juju-env-web-handler',
    'querystring-stringify',
    'juju-charm-models',
    'juju-bundle-models'
  ]
});
<|endoftext|>


<commit_before>// Dependencies
var helpers = require('atom-linter')
var linter = require('./utils/linter')

module.exports = function () {
  var self = this

  return {
    grammarScopes: self.scope,
    scope: 'file',
    lintOnFly: true,
    regex:
      '^(?<file>.*?\\..*?(?=:))' +
      ':(?<line>[0-9]+):(?<col>[0-9]+):' +
      '((?<message>.*?(?=\\())((?<error>.+undefined.*?)|(?<warning>.*?)))$',
    lint: function (textEditor) {
      var filePath = textEditor.getPath()
      var fileContent = textEditor.getText()
      var settings = self.cache.get(filePath)

      return helpers.execNode(settings.styleObj.execPath, settings.args).then(linter.bind({
        regex: this.regex,
        file: {
          path: filePath,
          content: fileContent
        }
      }))
    }
  }
}
<commit_msg>atom-linter helpers will modify args array, make a workaround<commit_after>// Dependencies
var helpers = require('atom-linter')
var linter = require('./utils/linter')

module.exports = function () {
  var self = this

  return {
    grammarScopes: self.scope,
    scope: 'file',
    lintOnFly: true,
    regex:
      '^(?<file>.*?\\..*?(?=:))' +
      ':(?<line>[0-9]+):(?<col>[0-9]+):' +
      '((?<message>.*?(?=\\())((?<error>.+undefined.*?)|(?<warning>.*?)))$',
    lint: function (textEditor) {
      var filePath = textEditor.getPath()
      var fileContent = textEditor.getText()
      var settings = self.cache.get(filePath)
      var args = settings.args.filter(function () { return true })

      return helpers.execNode(settings.styleObj.execPath, args).then(linter.bind({
        regex: this.regex,
        file: {
          path: filePath,
          content: fileContent
        }
      }))
    }
  }
}
<|endoftext|>


<commit_before>module.exports = function(grunt) {
  var pkg = grunt.file.readJSON('package.json');
  // Configuration goes here
  grunt.initConfig({

        // Supprime le répertoire target
    clean: {
      files: ['prod']
    },
    compass: {
      dev: {
        options: {
          basePath: 'dev/',
          config: 'dev/config.rb'
        }
      }
    },
    concat: {
      options: {
        separator: ';',
      },
      appjs: {
        src: ['dev/src/plugins.js', 'dev/src/main.js'],
        dest: 'dev/js/app.js',
      },
      total: {
        src: ['bower_components/jquery/jquery.min.js', 'prod/js/app.js'],
        dest: 'prod/js/app.js',
      }
    },
    uglify: {
      minify: {
        files: [{
            expand: true,
            cwd: 'prod/js',
            src: ['*.js'],
            dest: 'prod/js',
            ext: '.js'
          }]
      }
    },
    copy: {
      // Copie les fichiers HTML vers target
      html: {
        files: [
          {
            expand: true,
            dot: true,
            cwd: 'dev/',
            src: ['*.{ico,png,txt,xml,html}',
                  '.htaccess'],
            dest: 'prod/'

          }
        ]
      },
      font: {
        files: [
          {
            expand: true,
            cwd: 'dev/font',
            src: ['*.eot'],
            dest: 'prod/font/',
            ext: '.eot'
          },
          {
            expand: true,
            cwd: 'dev/font',
            src: ['*.svg'],
            dest: 'prod/font/',
            ext: '.svg'
          },
          {
            expand: true,
            cwd: 'dev/font',
            src: ['*.ttf'],
            dest: 'prod/font/',
            ext: '.ttf'
          },
          {
            expand: true,
            cwd: 'dev/font',
            src: ['*.woff'],
            dest: 'prod/font/',
            ext: '.woff'
          },
          {
            expand: true,
            cwd: 'dev/font',
            src: ['*.txt'],
            dest: 'prod/font/',
            ext: '.txt'
          }
        ]
      },
      // Copie les fichiers JS vers target
      js: {
        files: [
          {
            expand: true,
            cwd: 'dev/js',
            src: ['*.js'],
            dest: 'prod/js/',
            ext: '.js'
          }
        ]
      },
      jscustom: {
        files: [
          {
            expand: true,
            cwd: 'dev/src/custom',
            src: ['*.js'],
            dest: 'prod/js/',
            ext: '.js'
          }
        ]
      },
      // Copie les fichiers CSS vers target
      css: {
        files: [
          {
            expand: true,
            cwd: 'dev/css/',
            src: ['*.css'],
            dest: 'prod/css/',
            ext: '.css'
          }
        ]
      },

      // Copie les resources
      resources: {
        files: [
          {
            expand: true,
            cwd: 'dev/img',
            src: ['**/*'],
            dest: 'prod/img/'
          }
        ]
      }
    },

    watch: {
      sass: {
        files: ['dev/scss/**/*.scss'],
        tasks: ['compass:dev']
      },
      html: {
        files: ['dev/**/*.html'],
        tasks: ['copy:html','template:process']
      },
      css: {
        files: ['dev/css/*.css'],
        tasks: ['copy:css']
      },
      /* watch our files for change, reload */
      livereload: {
        files: ['dev/*.html', 'dev/css/*.css', 'dev/img/*', 'dev/src/**/*.js'],
        options: {
          livereload: true
        }
      },
    },
    connect: {
      server: {
        options: {
          hostname: '*',
          port: 9001,
          base: 'prod/'
        }
      }
    },
    modernizr: {

      // [REQUIRED] Path to the build you're using for development.
      "devFile" : "bower_components//modernizr/modernizr.js",

      // [REQUIRED] Path to save out the built file.
      "outputFile" : "prod/js/modernizr.min.js",

      // Based on default settings on http://modernizr.com/download/
      "extra" : {
          "shiv" : true,
          "printshiv" : false,
          "load" : true,
          "mq" : false,
          "cssclasses" : true
      },

      // Based on default settings on http://modernizr.com/download/
      "extensibility" : {
          "addtest" : false,
          "prefixed" : false,
          "teststyles" : false,
          "testprops" : false,
          "testallprops" : false,
          "hasevents" : false,
          "prefixes" : false,
          "domprefixes" : false
      },

      // By default, source is uglified before saving
      "uglify" : true,

      // Define any tests you want to impliticly include.
      "tests" : [],

      // By default, this task will crawl your project for references to Modernizr tests.
      // Set to false to disable.
      "parseFiles" : true,

      // When parseFiles = true, this task will crawl all *.js, *.css, *.scss files, except files that are in node_modules/.
      // You can override this by defining a "files" array below.
      // "files" : [],

      // When parseFiles = true, matchCommunityTests = true will attempt to
      // match user-contributed tests.
      "matchCommunityTests" : false,

      // Have custom Modernizr tests? Add paths to their location here.
      "customTests" : []
    },
    prompt: {
      prep: {
        options: {
          questions: [
            {
              config: 'template.options.data.gAnalytics',
              type: 'input', // list, checkbox, confirm, input, password
              message: 'Would you like to set the Google Analytics account',
              default: pkg.analytics, // default value if nothing is entered
            }
          ]
        }
      },
    },
    template: {
      options: {
        data : {
          'appName': pkg.fullname,
          'gAnalytics': pkg.analytics
        }
      },
      process: {
        files: [{expand: true,
            cwd: 'prod/',
            src: ['*.html'],
            dest: 'prod/',
            ext: '.html'}]
      }
    },
    imagemin: {                          // Task
      dynamic: {                         // Another target
        files: [{
          expand: true,                  // Enable dynamic expansion
          cwd: 'prod/img/',                   // Src matches are relative to this path
          src: ['**/*.{png,jpg,gif}'],   // Actual patterns to match
          dest: 'prod/img/'                  // Destination path prefix
        }]
      }
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        eqnull: true,
        browser: true,
        globals: {
          jQuery: true
        },
      },
      use_defaults: ['dev/src/*.js'],
    }
  });

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-modernizr');
  grunt.loadNpmTasks('grunt-template');
  grunt.loadNpmTasks('grunt-prompt');
  grunt.loadNpmTasks('grunt-contrib-imagemin');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  // Dev : copy, compile, lance le serveur
  grunt.registerTask('dev', [
    'clean',
    'prompt:prep',
    'compass:dev',
    'modernizr',
    'jshint:use_defaults',
    'concat:appjs',
    'copy:js',
    'copy:jscustom',
    'concat:total',
    'copy:html',
    'template:process',
    'copy:css',
    'copy:font',
    'copy:resources',
    'connect:server',
    'watch'
  ])
  // Prod : copy, compile, minify
  grunt.registerTask('production', [
    'clean',
    'prompt:prep',
    'compass:dev',
    'jshint:use_defaults',
    'concat:appjs',
    'copy:js',
    'copy:jscustom',
    'uglify:minify',
    'modernizr',
    'concat:total',
    'copy:css',
    'copy:font',
    'copy:html',
    'template:process',
    'copy:resources',
    'imagemin:dynamic'
  ]);

  grunt.registerTask('default', ['dev']);

};
<commit_msg>Optimisation compilation compass prod<commit_after>module.exports = function(grunt) {
  var pkg = grunt.file.readJSON('package.json');
  // Configuration goes here
  grunt.initConfig({

        // Supprime le répertoire target
    clean: {
      files: ['prod','dev/css']
    },
    compass: {
      dev: {
        options: {
          basePath: 'dev/',
          config: 'dev/config.rb'
        }
      },
      prod: {
        options: {
          basePath: 'dev/',
          config: 'dev/config.rb',
          environment: 'production'
        }
      }
    },
    concat: {
      options: {
        separator: ';',
      },
      appjs: {
        src: ['dev/src/plugins.js', 'dev/src/main.js'],
        dest: 'dev/js/app.js',
      },
      total: {
        src: ['bower_components/jquery/jquery.min.js', 'prod/js/app.js'],
        dest: 'prod/js/app.js',
      }
    },
    uglify: {
      minify: {
        files: [{
            expand: true,
            cwd: 'prod/js',
            src: ['*.js'],
            dest: 'prod/js',
            ext: '.js'
          }]
      }
    },
    copy: {
      // Copie les fichiers HTML vers target
      html: {
        files: [
          {
            expand: true,
            dot: true,
            cwd: 'dev/',
            src: ['*.{ico,png,txt,xml,html}',
                  '.htaccess'],
            dest: 'prod/'

          }
        ]
      },
      font: {
        files: [
          {
            expand: true,
            cwd: 'dev/font',
            src: ['*.eot'],
            dest: 'prod/font/',
            ext: '.eot'
          },
          {
            expand: true,
            cwd: 'dev/font',
            src: ['*.svg'],
            dest: 'prod/font/',
            ext: '.svg'
          },
          {
            expand: true,
            cwd: 'dev/font',
            src: ['*.ttf'],
            dest: 'prod/font/',
            ext: '.ttf'
          },
          {
            expand: true,
            cwd: 'dev/font',
            src: ['*.woff'],
            dest: 'prod/font/',
            ext: '.woff'
          },
          {
            expand: true,
            cwd: 'dev/font',
            src: ['*.txt'],
            dest: 'prod/font/',
            ext: '.txt'
          }
        ]
      },
      // Copie les fichiers JS vers target
      js: {
        files: [
          {
            expand: true,
            cwd: 'dev/js',
            src: ['*.js'],
            dest: 'prod/js/',
            ext: '.js'
          }
        ]
      },
      jscustom: {
        files: [
          {
            expand: true,
            cwd: 'dev/src/custom',
            src: ['*.js'],
            dest: 'prod/js/',
            ext: '.js'
          }
        ]
      },
      // Copie les fichiers CSS vers target
      css: {
        files: [
          {
            expand: true,
            cwd: 'dev/css/',
            src: ['*.css'],
            dest: 'prod/css/',
            ext: '.css'
          }
        ]
      },

      // Copie les resources
      resources: {
        files: [
          {
            expand: true,
            cwd: 'dev/img',
            src: ['**/*'],
            dest: 'prod/img/'
          }
        ]
      }
    },

    watch: {
      sass: {
        files: ['dev/scss/**/*.scss'],
        tasks: ['compass:dev']
      },
      html: {
        files: ['dev/**/*.html'],
        tasks: ['copy:html','template:process']
      },
      css: {
        files: ['dev/css/*.css'],
        tasks: ['copy:css']
      },
      /* watch our files for change, reload */
      livereload: {
        files: ['dev/*.html', 'dev/css/*.css', 'dev/img/*', 'dev/src/**/*.js'],
        options: {
          livereload: true
        }
      },
    },
    connect: {
      server: {
        options: {
          hostname: '*',
          port: 9001,
          base: 'prod/'
        }
      }
    },
    modernizr: {

      // [REQUIRED] Path to the build you're using for development.
      "devFile" : "bower_components//modernizr/modernizr.js",

      // [REQUIRED] Path to save out the built file.
      "outputFile" : "prod/js/modernizr.min.js",

      // Based on default settings on http://modernizr.com/download/
      "extra" : {
          "shiv" : true,
          "printshiv" : false,
          "load" : true,
          "mq" : false,
          "cssclasses" : true
      },

      // Based on default settings on http://modernizr.com/download/
      "extensibility" : {
          "addtest" : false,
          "prefixed" : false,
          "teststyles" : false,
          "testprops" : false,
          "testallprops" : false,
          "hasevents" : false,
          "prefixes" : false,
          "domprefixes" : false
      },

      // By default, source is uglified before saving
      "uglify" : true,

      // Define any tests you want to impliticly include.
      "tests" : [],

      // By default, this task will crawl your project for references to Modernizr tests.
      // Set to false to disable.
      "parseFiles" : true,

      // When parseFiles = true, this task will crawl all *.js, *.css, *.scss files, except files that are in node_modules/.
      // You can override this by defining a "files" array below.
      // "files" : [],

      // When parseFiles = true, matchCommunityTests = true will attempt to
      // match user-contributed tests.
      "matchCommunityTests" : false,

      // Have custom Modernizr tests? Add paths to their location here.
      "customTests" : []
    },
    prompt: {
      prep: {
        options: {
          questions: [
            {
              config: 'template.options.data.gAnalytics',
              type: 'input', // list, checkbox, confirm, input, password
              message: 'Would you like to set the Google Analytics account',
              default: pkg.analytics, // default value if nothing is entered
            }
          ]
        }
      },
    },
    template: {
      options: {
        data : {
          'appName': pkg.fullname,
          'gAnalytics': pkg.analytics
        }
      },
      process: {
        files: [{expand: true,
            cwd: 'prod/',
            src: ['*.html'],
            dest: 'prod/',
            ext: '.html'}]
      }
    },
    imagemin: {                          // Task
      dynamic: {                         // Another target
        files: [{
          expand: true,                  // Enable dynamic expansion
          cwd: 'prod/img/',                   // Src matches are relative to this path
          src: ['**/*.{png,jpg,gif}'],   // Actual patterns to match
          dest: 'prod/img/'                  // Destination path prefix
        }]
      }
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        eqnull: true,
        browser: true,
        globals: {
          jQuery: true
        },
      },
      use_defaults: ['dev/src/*.js'],
    }
  });

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-compass');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-modernizr');
  grunt.loadNpmTasks('grunt-template');
  grunt.loadNpmTasks('grunt-prompt');
  grunt.loadNpmTasks('grunt-contrib-imagemin');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  // Dev : copy, compile, lance le serveur
  grunt.registerTask('dev', [
    'clean',
    'prompt:prep',
    'compass:dev',
    'modernizr',
    'jshint:use_defaults',
    'concat:appjs',
    'copy:js',
    'copy:jscustom',
    'concat:total',
    'copy:html',
    'template:process',
    'copy:css',
    'copy:font',
    'copy:resources',
    'connect:server',
    'watch'
  ])
  // Prod : copy, compile, minify
  grunt.registerTask('production', [
    'clean',
    'prompt:prep',
    'compass:dev',
    'jshint:use_defaults',
    'concat:appjs',
    'copy:js',
    'copy:jscustom',
    'uglify:minify',
    'modernizr',
    'concat:total',
    'copy:css',
    'copy:font',
    'copy:html',
    'template:process',
    'copy:resources',
    'imagemin:dynamic'
  ]);

  grunt.registerTask('default', ['dev']);

};
<|endoftext|>