<commit_before>// awcoordinates by Anthony Neace

var awRegex = require('./awregex');
var awLocation = require('./awlocation');

// If pSize is not specified, set '32750' -- the maximum pSize allowed by AW
// software.
var setPSize = function(pSize) {
    return (typeof pSize) === 'number'
        ? pSize
        : 32750;
};

var setWhitespaceChar = function(whiteSpaceChar) {
    return (typeof whiteSpaceChar) !== 'undefined'
        ? whiteSpaceChar
        : ' ';
};

// If worldname is not specified, set 'aw' as the default.
var setWorldName = function(worldName) {
    return (typeof worldName) !== 'undefined'
        ? worldName
        : 'aw';
};

function randomFloat (low, high) {
    return (Math.random() * (high - low) + low).toFixed(1);
}

function chooseAxis(option1, option2) {
    return (Math.floor(Math.random() * 2) == 0)
        ? option1
        : option2;
}

var find = function(str, whitespaceChar) {
    whitespaceChar = setWhitespaceChar(whitespaceChar);

    // This regex captures a collection of all strings matching ActiveWorlds
    // plaintext coordinate syntax.
    var coordinateRegex = new RegExp('(' +
        awRegex.buildAwCoordinateMatchingRegex(whitespaceChar) +
        ')+', 'gi');

    var m = [];
    var output = [];

    if(str !== null)
    {
        while ((m = coordinateRegex.exec(str)) !== null) {

            if (m.index === coordinateRegex.lastIndex) {
                coordinateRegex.lastIndex++;
            }

            // Sanity check to make sure value isn't null. If not, push to
            // output collection.
            if(m[0] !== null)
            {
                // Push to output, and cleanup some edge cases that the
                // regex doesn't get.
                output.push(m[0].trim());
            }
        }
    }

    return output;
};

var validate = function(str, whitespaceChar) {
    whitespaceChar = setWhitespaceChar(whitespaceChar);

    // This regex captures a collection of all strings matching ActiveWorlds
    // plaintext coordinate syntax.
    var regex = new RegExp('^(' +
        awRegex.buildAwCoordinateMatchingRegex(whitespaceChar) +
        ')+$', 'i');

    return regex.test(str.trim());
};

var normalize = function(str, whitespaceChar) {
    whitespaceChar = setWhitespaceChar(whitespaceChar);

    if(validate(str, whitespaceChar) == false)
    {
        throw new Error('Invalid coordinates.');
    }

    var coordinateRegex = new RegExp(
        awRegex.buildAwCoordinatePartsMatchingRegex(whitespaceChar), 'i');

    var m;

    if ((m = coordinateRegex.exec(str)) !== null) {
        if (m.index === coordinateRegex.lastIndex) {
            coordinateRegex.lastIndex++;
        }
    }

    var coords = awLocation.toAwLocation(m);

    return JSON.stringify(coords);
};

var teleport = function(str, whitespaceChar) {
    whitespaceChar = setWhitespaceChar(whitespaceChar);

    validate(str, whitespaceChar);

    var coordinatesString = awLocation.toCoordinatesString(
        JSON.parse(normalize(str, whitespaceChar)), ' ');

    return 'teleport '+coordinatesString+'\r\n';
};

var random = function(worldName, pSize, whitespaceChar) {
    worldName = setWorldName(worldName);
    whitespaceChar = setWhitespaceChar(whitespaceChar);
    pSize = setPSize(pSize);
    return awLocation.buildCoordinatesString(worldName,
        randomFloat(0, pSize)+chooseAxis('n','s'),
        randomFloat(0, pSize)+chooseAxis('e','w'),
        '0a',
        randomFloat(0,360),
        whitespaceChar);
};

module.exports = {
  /**
   * Find aw coordinates in a given, arbitrary string.
   *
   * @param  {String} str - Arbitrary string content.
   * @param  {String} whitespaceChar - Whitespace character for the regex. Will
   *                                   be set to ' ' by default.
   * @return {String[]} Collection of identified aw coordinates.
   */
  find: find,
  /**
   * Validate a string exactly as aw coordinates. Trims whitespace before
   * attempting validation.
   *
   * @param  {String} str - Input string intended for validation.
   * @param  {String} whitespaceChar - Whitespace character for the regex. Will
   *                                   be set to ' ' by default.
   * @return {bool} True/False depending on result.
   */
  validate: validate,
  /**
   * Return a normalized object.
   *
   * @param  {String} str - Input string intended for normalization.
   * @param  {String} whitespaceChar - Whitespace character for the regex. Will
   *                                   be set to ' ' by default.
   * @return {object} returns an object.
   */
  normalize: normalize,
  /**
   * Return a teleport command string. The AW browser can read this command
   * from a file (for example, a file downloaded from a URL) to teleport
   * the user to the given location.
   *
   * @param  {String} str - Input string of the intended teleport destination.
   * @param  {String} whitespaceChar - Whitespace character for the regex. Will
   *                                   be set to ' ' by default.
   * @return {String} returns the teleport command.
   */
  teleport: teleport,
  /**
   * Return a random position and direction as a teleport string.
   *
   * @param  {String} worldName - Input string of the intended teleport
   *                              destination.
   * @param  {String} pSize - The world's pSize -- the maximum coordinate in
   *                          any cardinal direction that can be built upon.
   *                          This is effectively the 'edge' of the world,
   *                          although there is no hardware limitation to keep
   *                          you from running out past the world limit.
   * @param  {String} whitespaceChar - Whitespace character for the regex. Will be set to ' ' by default.
   * @return {String} returns the teleport command.
   */
  random: random,
  //translate: translate
};<commit_msg>Removing redundant code<commit_after>// awcoordinates by Anthony Neace

var awRegex = require('./awregex');
var awLocation = require('./awlocation');

// If pSize is not specified, set '32750' -- the maximum pSize allowed by AW
// software.
var setPSize = function(pSize) {
    return (typeof pSize) === 'number'
        ? pSize
        : 32750;
};

var setWhitespaceChar = function(whiteSpaceChar) {
    return (typeof whiteSpaceChar) !== 'undefined'
        ? whiteSpaceChar
        : ' ';
};

// If worldname is not specified, set 'aw' as the default.
var setWorldName = function(worldName) {
    return (typeof worldName) !== 'undefined'
        ? worldName
        : 'aw';
};

function randomFloat (low, high) {
    return (Math.random() * (high - low) + low).toFixed(1);
}

function chooseAxis(option1, option2) {
    return (Math.floor(Math.random() * 2) == 0)
        ? option1
        : option2;
}

var find = function(str, whitespaceChar) {
    whitespaceChar = setWhitespaceChar(whitespaceChar);

    // This regex captures a collection of all strings matching ActiveWorlds
    // plaintext coordinate syntax.
    var coordinateRegex = new RegExp('(' +
        awRegex.buildAwCoordinateMatchingRegex(whitespaceChar) +
        ')+', 'gi');

    var m = [];
    var output = [];

    if(str !== null)
    {
        while ((m = coordinateRegex.exec(str)) !== null) {

            if (m.index === coordinateRegex.lastIndex) {
                coordinateRegex.lastIndex++;
            }

            // Sanity check to make sure value isn't null. If not, push to
            // output collection.
            if(m[0] !== null)
            {
                // Push to output, and cleanup some edge cases that the
                // regex doesn't get.
                output.push(m[0].trim());
            }
        }
    }

    return output;
};

var validate = function(str, whitespaceChar) {
    whitespaceChar = setWhitespaceChar(whitespaceChar);

    // This regex captures a collection of all strings matching ActiveWorlds
    // plaintext coordinate syntax.
    var regex = new RegExp('^(' +
        awRegex.buildAwCoordinateMatchingRegex(whitespaceChar) +
        ')+$', 'i');

    return regex.test(str.trim());
};

var normalize = function(str, whitespaceChar) {
    whitespaceChar = setWhitespaceChar(whitespaceChar);

    if(validate(str, whitespaceChar) == false)
    {
        throw new Error('Invalid coordinates.');
    }

    var coordinateRegex = new RegExp(
        awRegex.buildAwCoordinatePartsMatchingRegex(whitespaceChar), 'i');

    var m;

    if ((m = coordinateRegex.exec(str)) !== null) {
        if (m.index === coordinateRegex.lastIndex) {
            coordinateRegex.lastIndex++;
        }
    }

    var coords = awLocation.toAwLocation(m);

    return JSON.stringify(coords);
};

var teleport = function(str, whitespaceChar) {
    whitespaceChar = setWhitespaceChar(whitespaceChar);

    var coordinatesString = awLocation.toCoordinatesString(
        JSON.parse(normalize(str, whitespaceChar)), ' ');

    return 'teleport '+coordinatesString+'\r\n';
};

var random = function(worldName, pSize, whitespaceChar) {
    worldName = setWorldName(worldName);
    whitespaceChar = setWhitespaceChar(whitespaceChar);
    pSize = setPSize(pSize);
    return awLocation.buildCoordinatesString(worldName,
        randomFloat(0, pSize)+chooseAxis('n','s'),
        randomFloat(0, pSize)+chooseAxis('e','w'),
        '0a',
        randomFloat(0,360),
        whitespaceChar);
};

module.exports = {
  /**
   * Find aw coordinates in a given, arbitrary string.
   *
   * @param  {String} str - Arbitrary string content.
   * @param  {String} whitespaceChar - Whitespace character for the regex. Will
   *                                   be set to ' ' by default.
   * @return {String[]} Collection of identified aw coordinates.
   */
  find: find,
  /**
   * Validate a string exactly as aw coordinates. Trims whitespace before
   * attempting validation.
   *
   * @param  {String} str - Input string intended for validation.
   * @param  {String} whitespaceChar - Whitespace character for the regex. Will
   *                                   be set to ' ' by default.
   * @return {bool} True/False depending on result.
   */
  validate: validate,
  /**
   * Return a normalized object.
   *
   * @param  {String} str - Input string intended for normalization.
   * @param  {String} whitespaceChar - Whitespace character for the regex. Will
   *                                   be set to ' ' by default.
   * @return {object} returns an object.
   */
  normalize: normalize,
  /**
   * Return a teleport command string. The AW browser can read this command
   * from a file (for example, a file downloaded from a URL) to teleport
   * the user to the given location.
   *
   * @param  {String} str - Input string of the intended teleport destination.
   * @param  {String} whitespaceChar - Whitespace character for the regex. Will
   *                                   be set to ' ' by default.
   * @return {String} returns the teleport command.
   */
  teleport: teleport,
  /**
   * Return a random position and direction as a teleport string.
   *
   * @param  {String} worldName - Input string of the intended teleport
   *                              destination.
   * @param  {String} pSize - The world's pSize -- the maximum coordinate in
   *                          any cardinal direction that can be built upon.
   *                          This is effectively the 'edge' of the world,
   *                          although there is no hardware limitation to keep
   *                          you from running out past the world limit.
   * @param  {String} whitespaceChar - Whitespace character for the regex. Will be set to ' ' by default.
   * @return {String} returns the teleport command.
   */
  random: random,
  //translate: translate
};<|endoftext|>


<commit_before>/*
 * Simple Bar chart
 */

import * as d3 from "d3";

export default function(config) {

  function Bars(config) {
    var vm = this;
    vm._config = config ? config : {};
    vm._data = [];
    vm._config.colorScale = d3.schemeCategory20c;
    vm._config._format = d3.format(",.1f");
    vm._scales = {};
    vm._axes = {};
    //vm._tip = d3.tip().attr('class', 'd3-tip tip-bars').html(vm._config.data.tip || function(d){ return d;});
    vm._tip = d3.tip()
      .attr('class', 'd3-tip tip-treemap')
      .direction('n')
      .html(vm._config.tip || function(d){ return vm._config._format(d[vm._config.y])});
  }

  //-------------------------------
  //User config functions
  Bars.prototype.x = function(columnName) {
    var vm = this;
    vm._config.x = columnName;
    return vm;
  }

  Bars.prototype.y = function(columnName) {
    var vm = this;
    vm._config.y = columnName;
    return vm;
  }

  Bars.prototype.color = function(columnName) {
    var vm = this;
    vm._config.color = columnName;
    return vm;
  }

  Bars.prototype.end = function() {
    var vm = this;
    return vm._chart;
  }

  Bars.prototype.colorScale = function(colorScale) {
    var vm = this;
    if(Array.isArray(colorScale)) {
      vm._config.colorScale = colorScale;
    } else {
      vm._scales.color = colorScale;
      vm._config.colorScale = colorScale.range();
    }
    return vm;
  }

  //-------------------------------
  //Triggered by the chart.js;
  Bars.prototype.chart = function(chart) {
    var vm = this;
    vm._chart = chart;
    return vm;
  }

  Bars.prototype.data = function(data) {
    var vm = this;
    vm._data = data.map(function(d) {
      if(d[vm._config.x] == Number(d[vm._config.x]))
        d[vm._config.x] = +d[vm._config.x];
      if(d[vm._config.y] == Number(d[vm._config.y]))
        d[vm._config.y] = +d[vm._config.y];
      return d;
    });
    return vm;
  }

  Bars.prototype.scales = function(s) {
    var vm = this;
    //vm._scales = s;
    /* Use
    * vm._config.x
    * vm._config.xAxis.scale
    * vm._config.y
    * vm._config.yAxis.scale
    * vm._data
    */
    /* Generate x scale */
    var config = {
        column: vm._config.x,
        type: vm._config.xAxis.scale,
        range: [0, vm._chart._width],
        minZero: true
    };
    vm._scales.x = vm._chart.generateScale(vm._data, config);

    /* Generate y scale */
    config = {
        column: vm._config.y,
        type: vm._config.yAxis.scale,
        range: [vm._chart._height, 0],
        minZero: true
    };
    vm._scales.y = vm._chart.generateScale(vm._data, config);
    vm._chart._scales.x = vm._scales.x;
    vm._chart._scales.y = vm._scales.y;

    if(!vm._scales.color)
      vm._scales.color = d3.scaleOrdinal(vm._config.colorScale);
    return vm;
  }

  Bars.prototype.axes = function(a) {
    var vm = this;
    vm._axes = a;
    return vm;
  }

  Bars.prototype.domains = function() {
    var vm = this;
    return vm;
  };

  Bars.prototype.draw = function() {
    var vm = this;
    vm._chart._svg.call(vm._tip);

    if(vm._config.xAxis.enabled) {
       vm._chart._svg.append("g")
          .attr("class", "xAxis axis")
          .attr("transform", "translate(0," + vm._chart._height + ")")
          .call(d3.axisBottom(vm._scales.x)
            .tickValues(vm._config.xAxis.tickValues)
            .tickFormat(vm._config.xAxis.tickFormat)
          );
        vm._chart._svg.selectAll(".xAxis.axis text").attr("transform", "translate(0,10)rotate(-20)");
    }

    if(vm._config.yAxis.enabled) {
      var yAxis = d3.axisLeft(vm._scales.y)
              .ticks(vm._config.yAxis.ticks)
              .tickValues(vm._config.yAxis.tickValues)
              .tickFormat(vm._config.yAxis.tickFormat);

      vm._chart._svg.append("g")
          .attr("class", "yAxis axis")
          .call(yAxis);
        /*
        Axis Title
        .append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", "0.71em")
          .attr("text-anchor", "end")
          .text("Frequency");
        */
    }

    vm._chart._svg.selectAll(".bar")
        .data(vm._data)
        .enter().append("rect")
          .attr("class", "bar")
          .attr("x", function(d) { return vm._config.xAxis.scale == 'linear' && vm._config.yAxis.scale == 'linear'? 0 : vm._scales.x(d[vm._config.x]); })
          .attr("y", function(d) { return vm._scales.y(d[vm._config.y]);})
          .attr("width", function(d){ return vm._scales.x.bandwidth ? vm._scales.x.bandwidth() : vm._scales.x(d[vm._config.x]) })
          .attr("height", function(d) { return vm._chart._height - vm._scales.y(d[vm._config.y]); })
          .attr("fill", function(d){ return vm._scales.color(d[vm._config.color])})
          .on('mouseover', function(d) {
            vm._tip.show(d, d3.select(this).node());
          })
          .on('mouseout', function() {
            vm._tip.hide();
          })
          .on('click', function() {

          });
    return vm;
  }

  return new Bars(config);
}
<commit_msg>Add opacity<commit_after>/*
 * Simple Bar chart
 */

import * as d3 from "d3";

export default function(config) {

  function Bars(config) {
    var vm = this;
    vm._config = config ? config : {};
    vm._data = [];
    vm._config.colorScale = d3.schemeCategory20c;
    vm._config._format = d3.format(",.1f");
    vm._scales = {};
    vm._axes = {};
    //vm._tip = d3.tip().attr('class', 'd3-tip tip-bars').html(vm._config.data.tip || function(d){ return d;});
    vm._tip = d3.tip()
      .attr('class', 'd3-tip tip-treemap')
      .direction('n')
      .html(vm._config.tip || function(d){ return vm._config._format(d[vm._config.y])});
  }

  //-------------------------------
  //User config functions
  Bars.prototype.x = function(columnName) {
    var vm = this;
    vm._config.x = columnName;
    return vm;
  }

  Bars.prototype.y = function(columnName) {
    var vm = this;
    vm._config.y = columnName;
    return vm;
  }

  Bars.prototype.color = function(columnName) {
    var vm = this;
    vm._config.color = columnName;
    return vm;
  }

  Bars.prototype.end = function() {
    var vm = this;
    return vm._chart;
  }

  Bars.prototype.colorScale = function(colorScale) {
    var vm = this;
    if(Array.isArray(colorScale)) {
      vm._config.colorScale = colorScale;
    } else {
      vm._scales.color = colorScale;
      vm._config.colorScale = colorScale.range();
    }
    return vm;
  }

  //-------------------------------
  //Triggered by the chart.js;
  Bars.prototype.chart = function(chart) {
    var vm = this;
    vm._chart = chart;
    return vm;
  }

  Bars.prototype.data = function(data) {
    var vm = this;
    vm._data = data.map(function(d) {
      if(d[vm._config.x] == Number(d[vm._config.x]))
        d[vm._config.x] = +d[vm._config.x];
      if(d[vm._config.y] == Number(d[vm._config.y]))
        d[vm._config.y] = +d[vm._config.y];
      return d;
    });
    return vm;
  }

  Bars.prototype.scales = function(s) {
    var vm = this;
    //vm._scales = s;
    /* Use
    * vm._config.x
    * vm._config.xAxis.scale
    * vm._config.y
    * vm._config.yAxis.scale
    * vm._data
    */
    /* Generate x scale */
    var config = {
        column: vm._config.x,
        type: vm._config.xAxis.scale,
        range: [0, vm._chart._width],
        minZero: true
    };
    vm._scales.x = vm._chart.generateScale(vm._data, config);

    /* Generate y scale */
    config = {
        column: vm._config.y,
        type: vm._config.yAxis.scale,
        range: [vm._chart._height, 0],
        minZero: true
    };
    vm._scales.y = vm._chart.generateScale(vm._data, config);
    vm._chart._scales.x = vm._scales.x;
    vm._chart._scales.y = vm._scales.y;

    if(!vm._scales.color)
      vm._scales.color = d3.scaleOrdinal(vm._config.colorScale);
    return vm;
  }

  Bars.prototype.axes = function(a) {
    var vm = this;
    vm._axes = a;
    return vm;
  }

  Bars.prototype.domains = function() {
    var vm = this;
    return vm;
  };

  Bars.prototype.draw = function() {
    var vm = this;
    vm._chart._svg.call(vm._tip);

    if(vm._config.xAxis.enabled) {
       vm._chart._svg.append("g")
          .attr("class", "xAxis axis")
          .attr("transform", "translate(0," + vm._chart._height + ")")
          .call(d3.axisBottom(vm._scales.x)
            .tickValues(vm._config.xAxis.tickValues)
            .tickFormat(vm._config.xAxis.tickFormat)
          );
        vm._chart._svg.selectAll(".xAxis.axis text").attr("transform", "translate(0,10)rotate(-20)");
    }

    if(vm._config.yAxis.enabled) {
      var yAxis = d3.axisLeft(vm._scales.y)
              .ticks(vm._config.yAxis.ticks)
              .tickValues(vm._config.yAxis.tickValues)
              .tickFormat(vm._config.yAxis.tickFormat);

      vm._chart._svg.append("g")
          .attr("class", "yAxis axis")
          .call(yAxis);
        /*
        Axis Title
        .append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", "0.71em")
          .attr("text-anchor", "end")
          .text("Frequency");
        */
    }

    vm._chart._svg.selectAll(".bar")
        .data(vm._data)
        .enter().append("rect")
          .attr("class", "bar")
          .attr("x", function(d) { return vm._config.xAxis.scale == 'linear' && vm._config.yAxis.scale == 'linear'? 0 : vm._scales.x(d[vm._config.x]); })
          .attr("y", function(d) { return vm._scales.y(d[vm._config.y]);})
          .attr("width", function(d){ return vm._scales.x.bandwidth ? vm._scales.x.bandwidth() : vm._scales.x(d[vm._config.x]) })
          .attr("height", function(d) { return vm._chart._height - vm._scales.y(d[vm._config.y]); })
          .attr("fill", function(d){ return vm._scales.color(d[vm._config.color])})
          .style("opacity", 0.9)
          .on('mouseover', function(d) {
            vm._tip.show(d, d3.select(this).node());
          })
          .on('mouseout', function() {
            vm._tip.hide();
          })
          .on('click', function() {

          });
    return vm;
  }

  return new Bars(config);
}
<|endoftext|>


<commit_before>/*
 * Simple Bar chart
 */

import * as d3 from "d3";

export default function(config) {

  function Bars(config) {
    var vm = this;
    vm._config = config ? config : {};
    vm._data = [];
    vm._config.colorScale = d3.schemeCategory20c;
    vm._scales = {color: d3.scaleOrdinal(vm._config.colorScale)};
    vm._axes = {};
    //vm._tip = d3.tip().attr('class', 'd3-tip').html(vm._config.data.tip);
  }

  //-------------------------------
  //User config functions
  Bars.prototype.x = function(columnName) {
    var vm = this;
    vm._config.x = columnName;
    return vm;
  }

  Bars.prototype.y = function(columnName) {
    var vm = this;
    vm._config.y = columnName;
    return vm;
  }

  Bars.prototype.color = function(columnName) {
    var vm = this;
    vm._config.color = columnName;
    return vm;
  }

  Bars.prototype.end = function() {
    var vm = this;
    return vm._chart;
  }

  Bars.prototype.colorScale = function(arrayOfColors) {
    var vm = this;
    vm._config.colorScale = arrayOfColors;
    return vm;
  }

  //-------------------------------
  //Triggered by the chart.js;
  Bars.prototype.chart = function(chart) {
    var vm = this;
    vm._chart = chart;
    return vm;
  }

  Bars.prototype.data = function(data) {
    var vm = this;
    vm._data = data.map(function(d) {
      if(d[vm._config.x] == Number(d[vm._config.x]))
        d[vm._config.x] = +d[vm._config.x];
      if(d[vm._config.y] == Number(d[vm._config.y]))
        d[vm._config.y] = +d[vm._config.y];
      return d;
    });
    return vm;
  }

  Bars.prototype.scales = function(s) {
    var vm = this;
    vm._scales = s;
    /* Use
    * vm._config.x
    * vm._config.xAxis.scale
    * vm._config.y
    * vm._config.yAxis.scale
    * vm._data
    */
    /* Generate x scale */
    var config = {
        column: vm._config.x,
        type: vm._config.xAxis.scale,
        range: [0, vm._chart._width],
        minZero: true
    };
    vm._scales.x = vm._chart.generateScale(vm._data, config);

    /* Generate y scale */
    config = {
        column: vm._config.y,
        type: vm._config.yAxis.scale,
        range: [vm._chart._height, 0],
        minZero: true
    };
    vm._scales.y = vm._chart.generateScale(vm._data, config);
    vm._chart._scales.x = vm._scales.x;
    vm._chart._scales.y = vm._scales.y;
    vm._scales.color = d3.scaleOrdinal(vm._config.colorScale);
    return vm;
  }

  Bars.prototype.axes = function(a) {
    var vm = this;
    vm._axes = a;
    return vm;
  }

  Bars.prototype.domains = function() {
    var vm = this;
    return vm;
  };

  Bars.prototype.draw = function() {
    var vm = this;
    //vm._chart._svg.call(vm.tip);

    if(vm._config.xAxis.enabled) {
       vm._chart._svg.append("g")
          .attr("class", "xAxis axis")
          .attr("transform", "translate(0," + vm._chart._height + ")")
          .call(d3.axisBottom(vm._scales.x));
    }

    if(vm._config.yAxis.enabled) {
      var yAxis = d3.axisLeft(vm._scales.y)
              .ticks(vm._config.yAxis.ticks || 10);

      vm._chart._svg.append("g")
          .attr("class", "yAxis axis")
          .call(yAxis);
        /*
        Axis Title
        .append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", "0.71em")
          .attr("text-anchor", "end")
          .text("Frequency");
        */
    }

    vm._chart._svg.selectAll(".bar")
        .data(vm._data)
        .enter().append("rect")
          .attr("class", "bar")
          .attr("x", function(d) { return vm._config.xAxis.scale == 'linear' && vm._config.yAxis.scale == 'linear'? 0 : vm._scales.x(d[vm._config.x]); })
          .attr("y", function(d) { return vm._scales.y(d[vm._config.y]);})
          .attr("width", function(d){ return vm._scales.x.bandwidth ? vm._scales.x.bandwidth() : vm._scales.x(d[vm._config.x]) })
          .attr("height", function(d) { return vm._chart._height - vm._scales.y(d[vm._config.y]); })
          .attr("fill", function(d){ return vm._scales.color(d[vm._config.color])})
          .on('mouseover', function() {

          })
          .on('mouseout', function() {

          })
          .on('click', function() {

          });
    return vm;
  }

  return new Bars(config);
}
<commit_msg>Support color scale as funcion<commit_after>/*
 * Simple Bar chart
 */

import * as d3 from "d3";

export default function(config) {

  function Bars(config) {
    var vm = this;
    vm._config = config ? config : {};
    vm._data = [];
    vm._config.colorScale = d3.schemeCategory20c;
    vm._scales = {};
    vm._axes = {};
    //vm._tip = d3.tip().attr('class', 'd3-tip').html(vm._config.data.tip);
  }

  //-------------------------------
  //User config functions
  Bars.prototype.x = function(columnName) {
    var vm = this;
    vm._config.x = columnName;
    return vm;
  }

  Bars.prototype.y = function(columnName) {
    var vm = this;
    vm._config.y = columnName;
    return vm;
  }

  Bars.prototype.color = function(columnName) {
    var vm = this;
    vm._config.color = columnName;
    return vm;
  }

  Bars.prototype.end = function() {
    var vm = this;
    return vm._chart;
  }

  Bars.prototype.colorScale = function(colorScale) {
    var vm = this;
    if(Array.isArray(colorScale)) {
      vm._config.colorScale = colorScale;
    } else {
      vm._scales.color = colorScale;
      vm._config.colorScale = colorScale.range();
    }
    return vm;
  }

  //-------------------------------
  //Triggered by the chart.js;
  Bars.prototype.chart = function(chart) {
    var vm = this;
    vm._chart = chart;
    return vm;
  }

  Bars.prototype.data = function(data) {
    var vm = this;
    vm._data = data.map(function(d) {
      if(d[vm._config.x] == Number(d[vm._config.x]))
        d[vm._config.x] = +d[vm._config.x];
      if(d[vm._config.y] == Number(d[vm._config.y]))
        d[vm._config.y] = +d[vm._config.y];
      return d;
    });
    return vm;
  }

  Bars.prototype.scales = function(s) {
    var vm = this;
    //vm._scales = s;
    /* Use
    * vm._config.x
    * vm._config.xAxis.scale
    * vm._config.y
    * vm._config.yAxis.scale
    * vm._data
    */
    /* Generate x scale */
    var config = {
        column: vm._config.x,
        type: vm._config.xAxis.scale,
        range: [0, vm._chart._width],
        minZero: true
    };
    vm._scales.x = vm._chart.generateScale(vm._data, config);

    /* Generate y scale */
    config = {
        column: vm._config.y,
        type: vm._config.yAxis.scale,
        range: [vm._chart._height, 0],
        minZero: true
    };
    vm._scales.y = vm._chart.generateScale(vm._data, config);
    vm._chart._scales.x = vm._scales.x;
    vm._chart._scales.y = vm._scales.y;

    if(!vm._scales.color)
      vm._scales.color = d3.scaleOrdinal(vm._config.colorScale);
    return vm;
  }

  Bars.prototype.axes = function(a) {
    var vm = this;
    vm._axes = a;
    return vm;
  }

  Bars.prototype.domains = function() {
    var vm = this;
    return vm;
  };

  Bars.prototype.draw = function() {
    var vm = this;
    //vm._chart._svg.call(vm.tip);

    if(vm._config.xAxis.enabled) {
       vm._chart._svg.append("g")
          .attr("class", "xAxis axis")
          .attr("transform", "translate(0," + vm._chart._height + ")")
          .call(d3.axisBottom(vm._scales.x));
    }

    if(vm._config.yAxis.enabled) {
      var yAxis = d3.axisLeft(vm._scales.y)
              .ticks(vm._config.yAxis.ticks || 10);

      vm._chart._svg.append("g")
          .attr("class", "yAxis axis")
          .call(yAxis);
        /*
        Axis Title
        .append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", "0.71em")
          .attr("text-anchor", "end")
          .text("Frequency");
        */
    }

    vm._chart._svg.selectAll(".bar")
        .data(vm._data)
        .enter().append("rect")
          .attr("class", "bar")
          .attr("x", function(d) { return vm._config.xAxis.scale == 'linear' && vm._config.yAxis.scale == 'linear'? 0 : vm._scales.x(d[vm._config.x]); })
          .attr("y", function(d) { return vm._scales.y(d[vm._config.y]);})
          .attr("width", function(d){ return vm._scales.x.bandwidth ? vm._scales.x.bandwidth() : vm._scales.x(d[vm._config.x]) })
          .attr("height", function(d) { return vm._chart._height - vm._scales.y(d[vm._config.y]); })
          .attr("fill", function(d){ return vm._scales.color(d[vm._config.color])})
          .on('mouseover', function() {

          })
          .on('mouseout', function() {

          })
          .on('click', function() {

          });
    return vm;
  }

  return new Bars(config);
}
<|endoftext|>


<commit_before>var CachingWriter = require('broccoli-caching-writer');
var pathSearcher  = require('include-path-searcher');
var defaults      = require('lodash.defaults');
var mkdirp        = require('mkdirp');
var path          = require('path');
var myth          = require('myth');
var RSVP          = require('rsvp');
var fs            = require('fs');

module.exports = MythCompiler;

MythCompiler.prototype = Object.create(CachingWriter.prototype)
MythCompiler.prototype.constructor = MythCompiler

function MythCompiler (sourceTrees, inputFile, outputFile, options) {
	if (!(this instanceof MythCompiler)) {
		return new MythCompiler(sourceTrees, inputFile, outputFile, options)
	}

	CachingWriter.apply(this, [arguments[0]].concat(arguments[3]))

	if (inputFile.charAt(0) === '/') {
		inputFile = inputFile.substr(1);
	}

	this.sourceTrees = sourceTrees;
	this.outputFile  = outputFile;
	this.inputFile   = inputFile;
	this.mythOptions = options;
}

MythCompiler.prototype.updateCache = function (srcDir, destDir) {
	var destFile = destDir + '/' + this.outputFile;
	mkdirp.sync(path.dirname(destFile));

	var mythOptions = defaults({}, this.mythOptions, {
		filename:  pathSearcher.findFileSync(this.inputFile, srcDir)
	});

	return new RSVP.Promise(function(resolve, reject) {
		fs.readFile(mythOptions.filename, { encoding: 'utf8' }, function (readError, input) {
			if (readError) {
				return reject(readError);
			}

			var css = myth(input, mythOptions).trim();

			fs.writeFile(destFile, css, { encoding: 'utf8' }, function (writeError) {
				if (writeError) {
					return reject(writeError);
				}

				return resolve(css);
			});
		});
	});
}
<commit_msg>using rsvp.denodeify<commit_after>var CachingWriter = require('broccoli-caching-writer');
var pathSearcher  = require('include-path-searcher');
var defaults      = require('lodash.defaults');
var mkdirp        = require('mkdirp');
var path          = require('path');
var myth          = require('myth');
var RSVP          = require('rsvp');
var fs            = require('fs');

var writeFile     = RSVP.denodeify(fs.writeFile);
var readFile      = RSVP.denodeify(fs.readFile);

module.exports = MythCompiler;

MythCompiler.prototype = Object.create(CachingWriter.prototype)
MythCompiler.prototype.constructor = MythCompiler

function MythCompiler (sourceTrees, inputFile, outputFile, options) {
	if (!(this instanceof MythCompiler)) {
		return new MythCompiler(sourceTrees, inputFile, outputFile, options)
	}

	CachingWriter.apply(this, [arguments[0]].concat(arguments[3]))

	if (inputFile.charAt(0) === '/') {
		inputFile = inputFile.substr(1);
	}

	this.sourceTrees = sourceTrees;
	this.outputFile  = outputFile;
	this.inputFile   = inputFile;
	this.mythOptions = options;
}

MythCompiler.prototype.updateCache = function (srcDir, destDir) {
	var destFile = destDir + '/' + this.outputFile;
	var mythOptions = defaults({}, this.mythOptions, {
		filename:  pathSearcher.findFileSync(this.inputFile, srcDir)
	});

	mkdirp.sync(path.dirname(destFile));

	return readFile(mythOptions.filename, { encoding: 'utf8' }).then(function (input) {
		return writeFile(destFile, myth(input, mythOptions).trim(), { encoding: 'utf8' });
	});
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm 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.
//
////////////////////////////////////////////////////////////////////////////

'use strict';

import { NativeModules } from 'react-native';
import { keys, objectTypes } from './constants';
import Collection, * as collections from './collections';
import List, { createList } from './lists';
import Results, { createResults } from './results';
import RealmObject, * as objects from './objects';
import User, { createUser } from './user';
import Session, { createSession } from './session';
import * as rpc from './rpc';
import * as util from './util';
import { static as staticUserMethods } from '../user-methods';

const {debugHosts, debugPort} = NativeModules.Realm;

rpc.registerTypeConverter(objectTypes.LIST, createList);
rpc.registerTypeConverter(objectTypes.RESULTS, createResults);
rpc.registerTypeConverter(objectTypes.OBJECT, objects.createObject);
rpc.registerTypeConverter(objectTypes.REALM, createRealm);
rpc.registerTypeConverter(objectTypes.USER, createUser);
rpc.registerTypeConverter(objectTypes.SESSION, createSession);

function createRealm(_, info) {
    let realm = Object.create(Realm.prototype);

    setupRealm(realm, info.id);
    return realm;
}

function setupRealm(realm, realmId) {
    realm[keys.id] = realmId;
    realm[keys.realm] = realmId;
    realm[keys.type] = objectTypes.REALM;

    [
        'path',
        'readOnly',
        'schema',
        'schemaVersion',
        'syncSession',
    ].forEach((name) => {
        Object.defineProperty(realm, name, {get: util.getterForProperty(name)});
    });
}

function getObjectType(realm, type) {
    if (typeof type == 'function') {
        return objects.typeForConstructor(realm[keys.realm], type);
    }
    return type;
}

export default class Realm {
    constructor(config) {
        let schemas = typeof config == 'object' && config.schema;
        let constructors = schemas ? {} : null;

        for (let i = 0, len = schemas ? schemas.length : 0; i < len; i++) {
            let item = schemas[i];

            if (typeof item == 'function') {
                let schema = item.schema;
                if (!schema || typeof schema != 'object') {
                    throw new Error("Realm object constructor must have 'schema' property");
                }

                let {name, properties} = schema;
                if (!name || typeof name != 'string') {
                    throw new Error("Realm object schema must have 'name' property");
                } else if (!properties || typeof properties != 'object') {
                    throw new Error("Realm object schema must have 'properties' property");
                }

                schemas.splice(i, 1, schema);
                constructors[name] = item;
            }
        }

        let realmId = rpc.createRealm(Array.from(arguments));
        setupRealm(this, realmId);

        // This will create mappings between the id, path, and potential constructors.
        objects.registerConstructors(realmId, this.path, constructors);
    }

    create(type, ...args) {
        let method = util.createMethod(objectTypes.REALM, 'create', true);
        return method.apply(this, [getObjectType(this, type), ...args]);
    }

    objects(type, ...args) {
        let method = util.createMethod(objectTypes.REALM, 'objects');
        return method.apply(this, [getObjectType(this, type), ...args]);
    }

    objectForPrimaryKey(type, ...args) {
        let method = util.createMethod(objectTypes.REALM, 'objectForPrimaryKey');
        return method.apply(this, [getObjectType(this, type), ...args]);
    }
}

// Non-mutating methods:
util.createMethods(Realm.prototype, objectTypes.REALM, [
    'addListener',
    'removeListener',
    'removeAllListeners',
    'close',
]);

// Mutating methods:
util.createMethods(Realm.prototype, objectTypes.REALM, [
    'delete',
    'deleteAll',
    'write',
], true);

const Sync = {
    User,
    Session
};

Object.defineProperties(Realm, {
    Collection: {
        value: Collection,
    },
    List: {
        value: List,
    },
    Results: {
        value: Results,
    },
    Object: {
        value: RealmObject,
    },
    Sync: {
        value: Sync,
    },
    defaultPath: {
        get: util.getterForProperty('defaultPath'),
        set: util.setterForProperty('defaultPath'),
    },
    schemaVersion: {
        value: function(_path, _encryptionKey) {
            return rpc.callMethod(undefined, Realm[keys.id], 'schemaVersion', Array.from(arguments));
        }
    },
    copyBundledRealmFiles: {
        value: function() {
            return rpc.callMethod(undefined, Realm[keys.id], 'copyBundledRealmFiles', []);
        }
    },
    clearTestState: {
        value: function() {
            collections.clearMutationListeners();
            objects.clearRegisteredConstructors();
            rpc.clearTestState();
        },
    },
});

for (let i = 0, len = debugHosts.length; i < len; i++) {
    try {
        let refreshAccessTokenCallback = staticUserMethods._refreshAccessToken.bind(User);
        // The session ID refers to the Realm constructor object in the RPC server.
        Realm[keys.id] = rpc.createSession(refreshAccessTokenCallback, debugHosts[i] + ':' + debugPort);
        break;
    } catch (e) {
        // Only throw exception after all hosts have been tried.
        if (i < len - 1) {
            continue;
        }

        // Log the original exception for debugging purposes.
        console.error(e);

        throw new Error(
            'Realm failed to connect to the embedded debug server inside the app. ' +
            'If attempting to use Chrome debugging from a device, ensure the device is ' +
            'reachable on the same network as this machine.'
        );
    }
}
<commit_msg>Fix for react-tests in Debug<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 Realm 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.
//
////////////////////////////////////////////////////////////////////////////

'use strict';

import { NativeModules } from 'react-native';
import { keys, objectTypes } from './constants';
import Collection, * as collections from './collections';
import List, { createList } from './lists';
import Results, { createResults } from './results';
import RealmObject, * as objects from './objects';
import User, { createUser } from './user';
import Session, { createSession } from './session';
import * as rpc from './rpc';
import * as util from './util';
import { static as staticUserMethods } from '../user-methods';

const {debugHosts, debugPort} = NativeModules.Realm;

rpc.registerTypeConverter(objectTypes.LIST, createList);
rpc.registerTypeConverter(objectTypes.RESULTS, createResults);
rpc.registerTypeConverter(objectTypes.OBJECT, objects.createObject);
rpc.registerTypeConverter(objectTypes.REALM, createRealm);
rpc.registerTypeConverter(objectTypes.USER, createUser);
rpc.registerTypeConverter(objectTypes.SESSION, createSession);

function createRealm(_, info) {
    let realm = Object.create(Realm.prototype);

    setupRealm(realm, info.id);
    return realm;
}

function setupRealm(realm, realmId) {
    realm[keys.id] = realmId;
    realm[keys.realm] = realmId;
    realm[keys.type] = objectTypes.REALM;

    [
        'path',
        'readOnly',
        'schema',
        'schemaVersion',
        'syncSession',
    ].forEach((name) => {
        Object.defineProperty(realm, name, {get: util.getterForProperty(name)});
    });
}

function getObjectType(realm, type) {
    if (typeof type == 'function') {
        return objects.typeForConstructor(realm[keys.realm], type);
    }
    return type;
}

export default class Realm {
    constructor(config) {
        let schemas = typeof config == 'object' && config.schema;
        let constructors = schemas ? {} : null;

        for (let i = 0, len = schemas ? schemas.length : 0; i < len; i++) {
            let item = schemas[i];

            if (typeof item == 'function') {
                let schema = item.schema;
                if (!schema || typeof schema != 'object') {
                    throw new Error("Realm object constructor must have 'schema' property");
                }

                let {name, properties} = schema;
                if (!name || typeof name != 'string') {
                    throw new Error("Realm object schema must have 'name' property");
                } else if (!properties || typeof properties != 'object') {
                    throw new Error("Realm object schema must have 'properties' property");
                }

                schemas.splice(i, 1, schema);
                constructors[name] = item;
            }
        }

        let realmId = rpc.createRealm(Array.from(arguments));
        setupRealm(this, realmId);

        // This will create mappings between the id, path, and potential constructors.
        objects.registerConstructors(realmId, this.path, constructors);
    }

    create(type, ...args) {
        let method = util.createMethod(objectTypes.REALM, 'create', true);
        return method.apply(this, [getObjectType(this, type), ...args]);
    }

    objects(type, ...args) {
        let method = util.createMethod(objectTypes.REALM, 'objects');
        return method.apply(this, [getObjectType(this, type), ...args]);
    }

    objectForPrimaryKey(type, ...args) {
        let method = util.createMethod(objectTypes.REALM, 'objectForPrimaryKey');
        return method.apply(this, [getObjectType(this, type), ...args]);
    }
}

// Non-mutating methods:
util.createMethods(Realm.prototype, objectTypes.REALM, [
    'addListener',
    'removeListener',
    'removeAllListeners',
    'close',
]);

// Mutating methods:
util.createMethods(Realm.prototype, objectTypes.REALM, [
    'delete',
    'deleteAll',
    'write',
], true);

const Sync = {
    User,
    Session
};

Object.defineProperties(Realm, {
    Collection: {
        value: Collection,
    },
    List: {
        value: List,
    },
    Results: {
        value: Results,
    },
    Object: {
        value: RealmObject,
    },
    Sync: {
        value: Sync,
    },
    defaultPath: {
        get: util.getterForProperty('defaultPath'),
        set: util.setterForProperty('defaultPath'),
    },
    schemaVersion: {
        value: function(_path, _encryptionKey) {
            return rpc.callMethod(undefined, Realm[keys.id], 'schemaVersion', Array.from(arguments));
        }
    },
    copyBundledRealmFiles: {
        value: function() {
            return rpc.callMethod(undefined, Realm[keys.id], 'copyBundledRealmFiles', []);
        }
    },
    clearTestState: {
        value: function() {
            collections.clearMutationListeners();
            objects.clearRegisteredConstructors();
            rpc.clearTestState();
        },
    },
    _waitForDownload: {
        value: function(_config) {
            return rpc.callMethod(undefined, Realm[keys.id], '_waitForDownload', Array.from(arguments));
        }
    },
});

for (let i = 0, len = debugHosts.length; i < len; i++) {
    try {
        let refreshAccessTokenCallback = staticUserMethods._refreshAccessToken.bind(User);
        // The session ID refers to the Realm constructor object in the RPC server.
        Realm[keys.id] = rpc.createSession(refreshAccessTokenCallback, debugHosts[i] + ':' + debugPort);
        break;
    } catch (e) {
        // Only throw exception after all hosts have been tried.
        if (i < len - 1) {
            continue;
        }

        // Log the original exception for debugging purposes.
        console.error(e);

        throw new Error(
            'Realm failed to connect to the embedded debug server inside the app. ' +
            'If attempting to use Chrome debugging from a device, ensure the device is ' +
            'reachable on the same network as this machine.'
        );
    }
}
<|endoftext|>


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

var fs = require('fs');
var path = require('path');

var sprintf = require('sprintf').sprintf;
var async = require('async');

var crypto = require('crypto');
var manifest = require('manifest');
var config = require('util/config');
var Errorf = require('util/misc').Errorf;
var fsutil = require('util/fs');
var extractTarball = require('util/tarball').extractTarball;
var HashedStream = require('util/hashedstream').HashedStream;
var jobs = require('jobs');
var managers = require('cast-agent/managers');

/**
 * Manage application bundles.
 * @constructor
 */
function BundleManager() {
  var conf = config.get();
  this.bundleRoot = conf['bundle_dir'];
  this.extractedRoot = conf['extracted_dir'];
  this.inProgress = {};
}

/**
 * Initialize directories used by the BundleManager.
 * @param {Function} callback A callback fired with (err).
 */
BundleManager.prototype.init = function(callback) {
  async.parallel([
    async.apply(fsutil.ensureDirectory, this.bundleRoot),
    async.apply(fsutil.ensureDirectory, this.extractedRoot)
  ], callback);
};

/**
 * Retrieve an application's bundle path.
 * @param {String} name The name of the application.
 * @returns {String} The application's bundle path.
 */
BundleManager.prototype.getAppBundlePath = function(name) {
  return path.join(this.bundleRoot, name);
};

/**
 * Retrieve an application's extracted path.
 * @param {String} name The name of the application.
 * @returns {String} The application's extracted path.
 */
BundleManager.prototype.getAppExtractedPath = function(name) {
  return path.join(this.extractedRoot, name);
};

/**
 * Retrieve the name of a bundle.
 * @param {String} name The name of the application.
 * @param {String} version The version of the bundle.
 * @returns {String} The name of the bundle.
 */
BundleManager.prototype.getBundleName = function(name, version) {
  return sprintf('%s@%s', name, version);
};

/**
 * Retrieve the file name of a bundle.
 * @param {String} name The name of the application.
 * @param {String} version The version of the bundle.
 * @returns {String} The name of the bundle file.
 */
BundleManager.prototype.getBundleFileName = function(name, version) {
  return sprintf('%s.tar.gz', this.getBundleName(name, version));
};

/**
 * Retrieve the path to a bundle file.
 * @param {String} name The name of the application.
 * @param {String} version The version of the bundle.
 * @returns {String} The path to the bundle file.
 */
BundleManager.prototype.getBundleFilePath = function(name, version) {
  var appBundlePath = this.getAppBundlePath(name);
  var bundleFileName = this.getBundleFileName(name, version);
  return path.join(appBundlePath, bundleFileName);
};

/**
 * Retrieve the path to an extracted bundle.
 * @param {String} name The name of the application.
 * @param {String} version The version of the bundle.
 * @returns {String} The path to the extracted bundle.
 */
BundleManager.prototype.getExtractedDirPath = function(name, version) {
  var appExtractedPath = this.getAppExtractedPath(name);
  var bundleName = this.getBundleName(name, version);
  return path.join(appExtractedPath, bundleName);
};

/**
 * Check whether a bundle exists.
 * @param {String} name The name of the application to check.
 * @param {String} version The version of the bundle to check.
 * @param {Function} callback A callback fired with (exists).
 */
BundleManager.prototype.bundleExists = function(name, version, callback) {
  path.exists(this.getBundleFilePath(name, version), callback);
};

/**
 * Ensure the directories necessary to accept bundles for an application
 * with the specified name.
 * @param {String} name The name of the application to ensure.
 * @param {Function} callback A callback fired with (err).
 */
BundleManager.prototype.ensureApplication = function(name, callback) {
  var self = this;

  function ensureAppBundleDir(callback) {
    fsutil.ensureDirectory(self.getAppBundlePath(name), callback);
  }

  function ensureAppExtractedDir(callback) {
    fsutil.ensureDirectory(self.getAppExtractedPath(name), callback);
  }

  async.parallel([ensureAppBundleDir, ensureAppExtractedDir], callback);
};

/**
 * Add a bundle from a streamed tarball.
 * @param {String} name The name of the bundle's application.
 * @param {String} version The version of the bundle.
 * @param {Object} opts An (optional) object that may contain a 'getSHA1'
 *    'getSHA1' property, which is a function taking a callback that takes
 *    (err, sha1) - make sense?
 * @param {stream.Stream} iStream A stream to read the bundle from.
 */
BundleManager.prototype.add = function(name, version, iStream, opts, callback) {
  if (!callback) {
    callback = opts;
    opts = {};
  }

  var self = this;
  var tmpFileManager = managers.getManager('TempFileManager');
  var bundleName = this.getBundleName(name, version);

  if (this.inProgress[bundleName]) {
    callback(new Errorf('Upload already in progress for %s', bundleName));
    return;
  }

  // Permanent paths for bundle and extracted
  var bundleFilePath = this.getBundleFilePath(name, version);
  var extractedDirPath = this.getExtractedDirPath(name, version);

  // Temporary paths for bundle and extracted
  var tmpBundle = tmpFileManager.allocate('.tar.gz');
  var tmpExtracted = tmpFileManager.allocate('');
  var tmpManifest = path.join(tmpExtracted, 'cast.json');

  this.inProgress[bundleName] = true;

  // Pipe the incoming stream to a paused HashedStream
  var hs = new HashedStream('sha1');
  hs.pause();
  iStream.pipe(hs);

  async.series([
    // Make sure the application directories exist
    self.ensureApplication.bind(self, name),

    // Make sure no such bundle already exists
    function checkExists(callback) {
      self.bundleExists(name, version, function(exists) {
        if (exists) {
          callback(new jobs.AlreadyExistsError('Bundle', bundleName));
        } else {
          callback();
        }
      });
    },

    // Receive the actual stream
    function receiveStream(callback) {
      var fstream = fs.createWriteStream(tmpBundle);
      var received;

      hs.on('hash', function(sha1) {
        received = sha1.digest('base64');
      });

      fstream.on('error', function(err) {
        callback(err);
      });

      fstream.on('close', function() {
        if (opts.getSHA1) {
          opts.getSHA1(function(err, expected) {
            if (!err && received !== expected) {
              err = new Error('SHA1 mismatch');
              err.code = 400;
            }
            callback(err);
            return;
          });
        } else {
          callback();
        }
      });

      hs.pipe(fstream);
      hs.resume();
    },

    // Extract the tarball to a temporary directory
    async.apply(extractTarball, tmpBundle, tmpExtracted, 0755),

    // Validate the manifest
    function(callback) {
      manifest.validateManifest(tmpManifest, function(err, manifestObject) {
        if (err) {
          err.code = 400;
        }
        callback(err);
        return;
      });
    },

    // Swap the new tarball into place
    async.apply(fs.rename, tmpBundle, bundleFilePath),

    // Swap the new extracted directory into place
    async.apply(fs.rename, tmpExtracted, extractedDirPath)
  ],
  function(err) {
    tmpFileManager.free(tmpBundle);
    tmpFileManager.free(tmpExtracted);
    delete self.inProgress[bundleName];
    callback(err);
  });
};

exports.BundleManager = BundleManager;
<commit_msg>add bundle-removing to BundleManager<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var fs = require('fs');
var path = require('path');

var sprintf = require('sprintf').sprintf;
var async = require('async');

var crypto = require('crypto');
var manifest = require('manifest');
var config = require('util/config');
var Errorf = require('util/misc').Errorf;
var fsutil = require('util/fs');
var extractTarball = require('util/tarball').extractTarball;
var HashedStream = require('util/hashedstream').HashedStream;
var jobs = require('jobs');
var managers = require('cast-agent/managers');

/**
 * Manage application bundles.
 * @constructor
 */
function BundleManager() {
  var conf = config.get();
  this.bundleRoot = conf['bundle_dir'];
  this.extractedRoot = conf['extracted_dir'];
  this.inProgress = {};
}

/**
 * Initialize directories used by the BundleManager.
 * @param {Function} callback A callback fired with (err).
 */
BundleManager.prototype.init = function(callback) {
  async.parallel([
    async.apply(fsutil.ensureDirectory, this.bundleRoot),
    async.apply(fsutil.ensureDirectory, this.extractedRoot)
  ], callback);
};

/**
 * Retrieve an application's bundle path.
 * @param {String} name The name of the application.
 * @returns {String} The application's bundle path.
 */
BundleManager.prototype.getAppBundlePath = function(name) {
  return path.join(this.bundleRoot, name);
};

/**
 * Retrieve an application's extracted path.
 * @param {String} name The name of the application.
 * @returns {String} The application's extracted path.
 */
BundleManager.prototype.getAppExtractedPath = function(name) {
  return path.join(this.extractedRoot, name);
};

/**
 * Retrieve the name of a bundle.
 * @param {String} name The name of the application.
 * @param {String} version The version of the bundle.
 * @returns {String} The name of the bundle.
 */
BundleManager.prototype.getBundleName = function(name, version) {
  return sprintf('%s@%s', name, version);
};

/**
 * Retrieve the file name of a bundle.
 * @param {String} name The name of the application.
 * @param {String} version The version of the bundle.
 * @returns {String} The name of the bundle file.
 */
BundleManager.prototype.getBundleFileName = function(name, version) {
  return sprintf('%s.tar.gz', this.getBundleName(name, version));
};

/**
 * Retrieve the path to a bundle file.
 * @param {String} name The name of the application.
 * @param {String} version The version of the bundle.
 * @returns {String} The path to the bundle file.
 */
BundleManager.prototype.getBundleFilePath = function(name, version) {
  var appBundlePath = this.getAppBundlePath(name);
  var bundleFileName = this.getBundleFileName(name, version);
  return path.join(appBundlePath, bundleFileName);
};

/**
 * Retrieve the path to an extracted bundle.
 * @param {String} name The name of the application.
 * @param {String} version The version of the bundle.
 * @returns {String} The path to the extracted bundle.
 */
BundleManager.prototype.getExtractedDirPath = function(name, version) {
  var appExtractedPath = this.getAppExtractedPath(name);
  var bundleName = this.getBundleName(name, version);
  return path.join(appExtractedPath, bundleName);
};

/**
 * Check whether a bundle exists.
 * @param {String} name The name of the application to check.
 * @param {String} version The version of the bundle to check.
 * @param {Function} callback A callback fired with (exists).
 */
BundleManager.prototype.bundleExists = function(name, version, callback) {
  path.exists(this.getBundleFilePath(name, version), callback);
};

/**
 * Ensure the directories necessary to accept bundles for an application
 * with the specified name.
 * @param {String} name The name of the application to ensure.
 * @param {Function} callback A callback fired with (err).
 */
BundleManager.prototype.ensureApplication = function(name, callback) {
  var self = this;

  function ensureAppBundleDir(callback) {
    fsutil.ensureDirectory(self.getAppBundlePath(name), callback);
  }

  function ensureAppExtractedDir(callback) {
    fsutil.ensureDirectory(self.getAppExtractedPath(name), callback);
  }

  async.parallel([ensureAppBundleDir, ensureAppExtractedDir], callback);
};

/**
 * Add a bundle from a streamed tarball.
 * @param {String} name The name of the bundle's application.
 * @param {String} version The version of the bundle.
 * @param {Object} opts An (optional) object that may contain a 'getSHA1'
 *    'getSHA1' property, which is a function taking a callback that takes
 *    (err, sha1) - make sense?
 * @param {stream.Stream} iStream A stream to read the bundle from.
 */
BundleManager.prototype.add = function(name, version, iStream, opts, callback) {
  if (!callback) {
    callback = opts;
    opts = {};
  }

  var self = this;
  var tmpFileManager = managers.getManager('TempFileManager');
  var bundleName = this.getBundleName(name, version);

  if (this.inProgress[bundleName]) {
    callback(new Errorf('Upload already in progress for %s', bundleName));
    return;
  }

  // Permanent paths for bundle and extracted
  var bundleFilePath = this.getBundleFilePath(name, version);
  var extractedDirPath = this.getExtractedDirPath(name, version);

  // Temporary paths for bundle and extracted
  var tmpBundle = tmpFileManager.allocate('.tar.gz');
  var tmpExtracted = tmpFileManager.allocate('');
  var tmpManifest = path.join(tmpExtracted, 'cast.json');

  this.inProgress[bundleName] = true;

  // Pipe the incoming stream to a paused HashedStream
  var hs = new HashedStream('sha1');
  hs.pause();
  iStream.pipe(hs);

  async.series([
    // Make sure the application directories exist
    self.ensureApplication.bind(self, name),

    // Make sure no such bundle already exists
    function checkExists(callback) {
      self.bundleExists(name, version, function(exists) {
        if (exists) {
          callback(new jobs.AlreadyExistsError('Bundle', bundleName));
        } else {
          callback();
        }
      });
    },

    // Receive the actual stream
    function receiveStream(callback) {
      var fstream = fs.createWriteStream(tmpBundle);
      var received;

      hs.on('hash', function(sha1) {
        received = sha1.digest('base64');
      });

      fstream.on('error', function(err) {
        callback(err);
      });

      fstream.on('close', function() {
        if (opts.getSHA1) {
          opts.getSHA1(function(err, expected) {
            if (!err && received !== expected) {
              err = new Error('SHA1 mismatch');
              err.code = 400;
            }
            callback(err);
            return;
          });
        } else {
          callback();
        }
      });

      hs.pipe(fstream);
      hs.resume();
    },

    // Extract the tarball to a temporary directory
    async.apply(extractTarball, tmpBundle, tmpExtracted, 0755),

    // Validate the manifest
    function(callback) {
      manifest.validateManifest(tmpManifest, function(err, manifestObject) {
        if (err) {
          err.code = 400;
        }
        callback(err);
        return;
      });
    },

    // Swap the new tarball into place
    async.apply(fs.rename, tmpBundle, bundleFilePath),

    // Swap the new extracted directory into place
    async.apply(fs.rename, tmpExtracted, extractedDirPath)
  ],
  function(err) {
    tmpFileManager.free(tmpBundle);
    tmpFileManager.free(tmpExtracted);
    delete self.inProgress[bundleName];
    callback(err);
  });
};

/**
 * Remove a bundle.
 * @param {String} name The name of the application to remove the bundle for.
 * @param {String} version The version of the bundle to remove.
 * @param {Function} callback A callback fired with (err).
 */
BundleManager.prototype.remove = function(name, version, callback) {
  var tmpFileManager = managers.getManager('TempFileManager');
  var tmpExtractedPath = tmpFileManager.allocate('');
  var bundleFilePath = this.getBundleFilePath(name, version);
  var extractedDirPath = this.getExtractedDirPath(name, version);

  // Note: we rename() the extracted bundle into the temporary directory before
  // we remove it so that there will never be a half-removed extracted bundle.
  async.series([
    async.apply(fs.rename, extractedDirPath, tmpExtractedPath),
    async.apply(fs.unlink, bundleFilePath),
    async.apply(fsutil.rmtree, tmpExtractedPath)
  ], callback);
};

exports.BundleManager = BundleManager;
<|endoftext|>


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

var groups = {};
var packages = {};

// save us calls if at all possible
var checkGroups = [];

// hash of vocab name's to id's
var vocabMap = {};

var options, ckan;

exports.run = function(o, c) {
	options = o;
	ckan = c;
	if( !options ) options = {};

	if( options.key ) ckan.setKey(options.key);
	if( options.server ) ckan.setServer(options.server);

	ready();
}

/*function getKnownVocab(callback) {
	if(options.debug) console.log("CKAN IMPORT: gathering list on known vocabulary\n");

	ckan.exec("vocabulary_list", function(err, resp) {
		if( err ) {
			return callback();
			if(options.debug) console.log("CKAN IMPORT: failed to get vocabulary\n");
		}

		knownVocabulary = [];
		for( var i = 0; i < resp.result.length; i++ ) {
			knownVocabulary.push(resp.result[i].name);
		}

		callback();
	});
}*/

function ready() {
	if( !options.groups ) {
		var index = 0;
		if( options.packageStartIndex ) index = options.packageStartIndex;
		createPackages(options.packages);
	} else {
		createGroups(options.groups, options.packages);
	}
}

function createGroups(groupList, packageList) {
	async.eachSeries(groupsList,
		function(group, callback) {
			createGroup(group, callback);
		},
		function(err) {
			if( err ) error(err);
			createPackages(packageList);
		}
	);
}

/*function createGroups(index, groupList, packageList) {
	createGroup(groupList[index], function(){
		index++;
		if( index == groupList.length ) {
			var index = 0;
			if( options.packageStartIndex ) index = options.packageStartIndex;
			createPackages(index, packageList);
		} else {
			createGroups(index, groupList, packageList);
		}
	});
}*/

function createPackages(packageList) {
	var index = 0;

	async.eachSeries(packageList,
		function(pkg, next) {
			var resources = pkg.resources;
			delete pkg.resources;

			createPackage(pkg, function(pkgId){
				if( resources && resources.length > 0 ) {
					// now create the resources
					// this is done one at a time in case of files

					createResources(pkg.name, pkgId, resources, function(){
						if(options.debug) console.log("CKAN IMPORT: finished package index: "+index+" of "+packageList.length+"\n");
						index++;
						next();
					});
				} else {
					if(options.debug) console.log("CKAN IMPORT: finished package index: "+index+" of "+packageList.length+"\n");
					index++;
					next();
				}
			});
		},
		function(err) {
			if( err ) {
				error(err);
			} else {
				if( options.debug ) console.log("CKAN IMPORT: Done.");
				if( options.callback ) options.callback();
			}
		}
	);
}

/*function createPackages(index, packageList) {
	var resources = packageList[index].resources;
	delete packageList[index].resources;

	createPackage(packageList[index], function(pkgId){
		if( resources && resources.length > 0 ) {
			// now create the resources
			// this is done one at a time in case of files

			createResources(0, packageList[index].name, pkgId, resources, function(){
				onPackageComplete(index, packageList);
			});
		} else {
			onPackageComplete(index, packageList);
		}
	});
}*/

/*function onPackageComplete(index, packageList) {
	if(options.debug) console.log("CKAN IMPORT: finished package index: "+index+" of "+packageList.length+"\n");

	index++;
	if( !done(index, packageList) ) {
		createPackages(index, packageList);
	}
}*/

function createResources(pkgName, pkgId, resourceList, callback) {
	async.eachSeries(resourceList,
		function(resource, callback) {
			resource.package_id = pkgId;
			createResource(pkgName, resource, callback);
		},
		function(err) {
			if( err ) error(err);
			callback();
		}
	);
}

/*function createResources(index, pkgName, pkgId, resourceList, callback) {
	resourceList[index].package_id = pkgId;

	createResource(pkgName, resourceList[index], function(){
		index++;
		if( index == resourceList.length ) {
			callback();
		} else {
			createResources(index, pkgName, pkgId, resourceList, callback);
		}
	});
}*/

function createGroup(group, callback) {
	if( !group.name ) error("Attempting to create a group w/o a name: "+JSON.stringify(group));

	if( checkGroups.indexOf(group.name) > -1 ) return callback();
	checkGroups.push(group.name);

	ckan.exec("group_show", {id:group.name}, function(err, resp) {
		if( !err && !resp.error ) return callback();

		create("group", group, function(resp){
			callback();
		});
	});
}

function createPackage(pkg, callback) {
	if( !pkg.name ) error("Attempting to create a package w/o a name: "+JSON.stringify(pkg));
	if( packages[pkg.name] ) return callback(packages[pkg.name].id);

	checkPackage(pkg, callback);
}

function checkPackage(pkg, callback) {
	ckan.exec("package_show", {id:pkg.name}, function(err, resp) {
		// already exists
		if( !err && !resp.error ) {
			if( options.debug ) console.log("CKAN IMPORT: "+pkg.name+" already created");
			packages[resp.result.name] = resp.result;

			if( options.update ) {

				pkg.resources = resp.result.resources;
				setVocabIds(0, pkg, function(){
					update("package", resp.result.id, pkg, function(resp){
						callback(resp.result.id);
					});
				});
			/*} else if ( options.replace ) {
				replace("package", resp.result.id, pkg, function(resp){
					packages[resp.result.name] = resp.result;
					callback(resp.result.id);
				});*/
			} else {
				callback(resp.result.id);
			}
			return;
		}

		setVocabIds(0, pkg, function(){
			create("package", pkg, function(resp){
				packages[resp.result.name] = resp.result;
				callback(resp.result.id);
			});
		});

	});
}

// we are going to assume people pass names in the vocabulary_id column
// to which point we need to look up the id from the name so package_create
// does the correct association
function setVocabIds(index, pkg, callback) {
	if(!pkg.tags) return callback();

	if( index == pkg.tags.length ) {
		callback();
	} else {
		getVocabId(pkg.tags[index].vocabulary_id, function(id) {
			pkg.tags[index].vocabulary_id = id;
			index++;
			setVocabIds(index, pkg, callback);
		});
	}
}

// if the id doesn't exist, create it
function getVocabId(name, callback) {
	if( vocabMap[name] ) return callback(vocabMap[name]);

	ckan.exec("vocabulary_show", {id: name}, function(err, resp) {
		if( err ) error("Unable to access vocabulary");

		if( !resp.success ) {
			if( name.match(/.*-.*-.*-.*-.*/) ) {
				if( err ) error("No vocabulary found for passed id");

				create("vocabulary", {name: name, tags: []}, function(err, resp){
					if( err ) error("Unable to create vocabulary: "+name);
					vocabMap[name] = resp.result.id;
					callback(resp.result.id);
				});
			}
		} else {
			vocabMap[name] = resp.result.id;
			callback(resp.result.id);
		}
	});
}

function createResource(pkgName, resource, callback) {
	if( !resource.name &&  !resource.url ) error("Attempting to create a resource w/o a name or url: "+JSON.stringify(resource));

	// first check this resource has not already been created
	if( packages[pkgName].resources ) {
		for( var i = 0; i < packages[pkgName].resources.length; i++ ) {

			if( (resource.name && packages[pkgName].resources[i].name == resource.name ) ||
				(resource.url && packages[pkgName].resources[i].url == resource.url) ) {

				if( options.update && !packages[pkgName].resources[i].file ) {
					update("resource", packages[pkgName].resources[i].id, resource, function(resp){
						callback();
					});
				} else if ( options.update && packages[pkgName].resources[i].file &&
							(options.updateFile === true || options.updateFile == null) ) {

					update("resource", packages[pkgName].resources[i].id, resource, function(resp){
						callback();
					});
				/*} else if ( options.replace ) {
					replace("resource", packages[pkgName].resources[i].id, resource, function(resp){
						callback();
					});*/
				} else {
					callback();
				}
				return;
			}

		}
	}

	create("resource", resource, function(resp){
		callback();
	});
}

function update(type, id, obj, callback) {
	if( options.debug ) console.log("CKAN IMPORT: Updating "+type+" '"+(obj.name ? obj.name : obj.url)+"'");
	obj.id = id;
	var t = new Date().getTime();

	ckan.exec(type+"_update", obj, function(err, resp) {
		if( options.debug ) console.log("  --"+(new Date().getTime()-t)+"ms");
		if( err ) return error(err);
		if( resp.error ) return error(resp.error);
		callback(resp);
	});
}

// does a full delete an insert of the object
// Currently there is no package purge... can this even be done?
/*function replace(type, id, obj, callback) {
	if( options.debug ) console.log("CKAN IMPORT: Replacing "+type+" '"+obj.name+"'");

	ckan.exec(type+"_delete",{id:id}, function(err, resp){
		if( err ) return error(err);
		if( resp.error ) return error(resp.error);

		create(type, obj, callback);
	});
}*/

function create(type, obj, callback) {
	if( options.debug ) console.log("CKAN IMPORT: Creating "+type+" '"+(obj.name ? obj.name : obj.url)+"'");
	var t = new Date().getTime();

	ckan.exec(type+"_create", obj, function(err, resp) {
		if( options.debug ) console.log("  --"+(new Date().getTime()-t)+"ms");
		if( err ) return error(err);
		if( resp.error ) return error(resp.error);

		callback(resp);
	});
}

/*function done(index, pkgList) {
	if( index == pkgList.length ) {
		if( options.debug ) console.log("CKAN IMPORT: Done.");
		if( options.callback ) options.callback();
		return true;
	}
	return false;
}*/

function error(msg) {
	console.log(msg);
	process.exit(1);
}<commit_msg>switching to async library<commit_after>var async = require('async');

var groups = {};
var packages = {};

// save us calls if at all possible
var checkGroups = [];

// hash of vocab name's to id's
var vocabMap = {};

var options, ckan;

exports.run = function(o, c) {
	options = o;
	ckan = c;
	if( !options ) options = {};

	if( options.key ) ckan.setKey(options.key);
	if( options.server ) ckan.setServer(options.server);

	ready();
}

function ready() {
	if( !options.groups ) {
		var index = 0;
		if( options.packageStartIndex ) index = options.packageStartIndex;
		createPackages(options.packages);
	} else {
		createGroups(options.groups, options.packages);
	}
}

function createGroups(groupList, packageList) {
	async.eachSeries(groupsList,
		function(group, callback) {
			createGroup(group, callback);
		},
		function(err) {
			if( err ) error(err);
			createPackages(packageList);
		}
	);
}

function createPackages(packageList) {
	var index = 0;

	async.eachSeries(packageList,
		function(pkg, next) {
			var resources = pkg.resources;
			delete pkg.resources;

			createPackage(pkg, function(pkgId){
				if( resources && resources.length > 0 ) {
					// now create the resources
					// this is done one at a time in case of files

					createResources(pkg.name, pkgId, resources, function(){
						if(options.debug) console.log("CKAN IMPORT: finished package index: "+index+" of "+packageList.length+"\n");
						index++;
						next();
					});
				} else {
					if(options.debug) console.log("CKAN IMPORT: finished package index: "+index+" of "+packageList.length+"\n");
					index++;
					next();
				}
			});
		},
		function(err) {
			if( err ) {
				error(err);
			} else {
				if( options.debug ) console.log("CKAN IMPORT: Done.");
				if( options.callback ) options.callback();
			}
		}
	);
}

function createResources(pkgName, pkgId, resourceList, callback) {
	async.eachSeries(resourceList,
		function(resource, callback) {
			resource.package_id = pkgId;
			createResource(pkgName, resource, callback);
		},
		function(err) {
			if( err ) error(err);
			callback();
		}
	);
}

function createGroup(group, callback) {
	if( !group.name ) error("Attempting to create a group w/o a name: "+JSON.stringify(group));

	if( checkGroups.indexOf(group.name) > -1 ) return callback();
	checkGroups.push(group.name);

	ckan.exec("group_show", {id:group.name}, function(err, resp) {
		if( !err && !resp.error ) return callback();

		create("group", group, function(resp){
			callback();
		});
	});
}

function createPackage(pkg, callback) {
	if( !pkg.name ) error("Attempting to create a package w/o a name: "+JSON.stringify(pkg));
	if( packages[pkg.name] ) return callback(packages[pkg.name].id);

	checkPackage(pkg, callback);
}

function checkPackage(pkg, callback) {
	ckan.exec("package_show", {id:pkg.name}, function(err, resp) {
		// already exists
		if( !err && !resp.error ) {
			if( options.debug ) console.log("CKAN IMPORT: "+pkg.name+" already created");
			packages[resp.result.name] = resp.result;

			if( options.update ) {

				pkg.resources = resp.result.resources;
				setVocabIds(0, pkg, function(){
					update("package", resp.result.id, pkg, function(resp){
						callback(resp.result.id);
					});
				});
			/*} else if ( options.replace ) {
				replace("package", resp.result.id, pkg, function(resp){
					packages[resp.result.name] = resp.result;
					callback(resp.result.id);
				});*/
			} else {
				callback(resp.result.id);
			}
			return;
		}

		setVocabIds(0, pkg, function(){
			create("package", pkg, function(resp){
				packages[resp.result.name] = resp.result;
				callback(resp.result.id);
			});
		});

	});
}

// we are going to assume people pass names in the vocabulary_id column
// to which point we need to look up the id from the name so package_create
// does the correct association
function setVocabIds(index, pkg, callback) {
	if(!pkg.tags) return callback();

	if( index == pkg.tags.length ) {
		callback();
	} else {
		getVocabId(pkg.tags[index].vocabulary_id, function(id) {
			pkg.tags[index].vocabulary_id = id;
			index++;
			setVocabIds(index, pkg, callback);
		});
	}
}

// if the id doesn't exist, create it
function getVocabId(name, callback) {
	if( vocabMap[name] ) return callback(vocabMap[name]);

	ckan.exec("vocabulary_show", {id: name}, function(err, resp) {
		if( err ) error("Unable to access vocabulary");

		if( !resp.success ) {
			if( name.match(/.*-.*-.*-.*-.*/) ) {
				if( err ) error("No vocabulary found for passed id");

				create("vocabulary", {name: name, tags: []}, function(err, resp){
					if( err ) error("Unable to create vocabulary: "+name);
					vocabMap[name] = resp.result.id;
					callback(resp.result.id);
				});
			}
		} else {
			vocabMap[name] = resp.result.id;
			callback(resp.result.id);
		}
	});
}

function createResource(pkgName, resource, callback) {
	if( !resource.name &&  !resource.url ) error("Attempting to create a resource w/o a name or url: "+JSON.stringify(resource));

	// first check this resource has not already been created
	if( packages[pkgName].resources ) {
		for( var i = 0; i < packages[pkgName].resources.length; i++ ) {

			if( (resource.name && packages[pkgName].resources[i].name == resource.name ) ||
				(resource.url && packages[pkgName].resources[i].url == resource.url) ) {

				if( options.update && !packages[pkgName].resources[i].file ) {
					update("resource", packages[pkgName].resources[i].id, resource, function(resp){
						callback();
					});
				} else if ( options.update && packages[pkgName].resources[i].file &&
							(options.updateFile === true || options.updateFile == null) ) {

					update("resource", packages[pkgName].resources[i].id, resource, function(resp){
						callback();
					});
				/*} else if ( options.replace ) {
					replace("resource", packages[pkgName].resources[i].id, resource, function(resp){
						callback();
					});*/
				} else {
					callback();
				}
				return;
			}

		}
	}

	create("resource", resource, function(resp){
		callback();
	});
}

function update(type, id, obj, callback) {
	if( options.debug ) console.log("CKAN IMPORT: Updating "+type+" '"+(obj.name ? obj.name : obj.url)+"'");
	obj.id = id;
	var t = new Date().getTime();

	ckan.exec(type+"_update", obj, function(err, resp) {
		if( options.debug ) console.log("  --"+(new Date().getTime()-t)+"ms");
		if( err ) return error(err);
		if( resp.error ) return error(resp.error);
		callback(resp);
	});
}

// does a full delete an insert of the object
// Currently there is no package purge... can this even be done?
/*function replace(type, id, obj, callback) {
	if( options.debug ) console.log("CKAN IMPORT: Replacing "+type+" '"+obj.name+"'");

	ckan.exec(type+"_delete",{id:id}, function(err, resp){
		if( err ) return error(err);
		if( resp.error ) return error(resp.error);

		create(type, obj, callback);
	});
}*/

function create(type, obj, callback) {
	if( options.debug ) console.log("CKAN IMPORT: Creating "+type+" '"+(obj.name ? obj.name : obj.url)+"'");
	var t = new Date().getTime();

	ckan.exec(type+"_create", obj, function(err, resp) {
		if( options.debug ) console.log("  --"+(new Date().getTime()-t)+"ms");
		if( err ) return error(err);
		if( resp.error ) return error(resp.error);

		callback(resp);
	});
}

function error(msg) {
	console.log(msg);
	process.exit(1);
}<|endoftext|>


<commit_before>suiteHasFailed = function (suite)  {
  return !! VelocityTestReports.findOne({
    framework: suite.framework,
    ancestors: suite.ancestors,
    result: "failed"
  });
};

frameworkStatus = function (name) {
  var hasTests = VelocityTestReports.find({framework: name}).count() > 0;
  if (!hasTests) return "empty"

  var frameworkExecStatus = VelocityAggregateReports.findOne({name: name});
  var isComplete = (frameworkExecStatus && frameworkExecStatus.result === "completed");
  var hasFailed = !! VelocityTestReports.findOne({framework: name, result: "failed"});

  if (hasFailed)
    return "failed";
  else if (isComplete)
    return "passed";
  else
    return "pending";
}

function mochaPresent() {
  //XXX hard-coding mocha iframe support for now
  return !! VelocityAggregateReports.findOne({'name': 'mocha'});
}
function nightwatchPresent() {
  return !! VelocityAggregateReports.findOne({'name': 'nightwatch'});
}

Template.velocity.created = function () {
  // Only show widget when we know we are NOT running in a Velocity Mirror
  Session.setDefault('velocity.isMirror', true);

  // Determine if session is running in a Velocity mirror or not
  Meteor.call('velocity/isMirror', function (err, res) {
    if (err) {
      // Log error. HTML Reporter will not be shown
      console.error(err);
    } else {
      Session.set('velocity.isMirror', res);
    }
  })
};

Template.velocity.helpers({
  statusWidgetClass: function () {
    var aggregateResult = VelocityAggregateReports.findOne({name: 'aggregateResult'});
    if (aggregateResult && aggregateResult.result === 'failed') {
      return  'failed';
    }

    var aggregateComplete = VelocityAggregateReports.findOne({name: 'aggregateComplete'});
    if (aggregateComplete && aggregateResult
      && aggregateResult.result === 'passed' && aggregateComplete.result === 'completed') {
      return 'passed';
    }
    return 'pending';
  },
  resetting: function () {
    return Session.get('resettingVelocity')
  },
  testReports: function () {
    return VelocityTestReports.find();
  },
  frameworks: function () {
    return VelocityAggregateReports.find({name: {$nin: ["aggregateResult", "aggregateComplete"]}});
  },
  active: function (id) {
    return reamplify.store(id);
  },
  overlayIsVisible: function () {
    return amplify.store('velocityOverlayIsVisible')
  },
  notInMirror: function () {
    // This causes the html reporter to remain hidden if running in a Velocity mirror
    return Session.equals('velocity.isMirror', false);
  },
  mochaPresent: mochaPresent,
  nightwatchPresent: nightwatchPresent
});

Template.velocityReports.helpers({
  frameworkStatus: function () {
    return frameworkStatus(this.name)
  },
  isPassed: function (status) {
    return status === 'passed'
  },
  frameworkTotalTestCount: function () {
    return VelocityTestReports.find({framework: this.name}).count();
  },
  frameworkPassedTestCount: function () {
    return VelocityTestReports.find({framework: this.name, result: 'passed'}).count();
  },
  noFrameworkFiles: function () {
    // XXX presence of VelocityAggregateReports is a stand-in for
    // Velocity being loaded. This is a bit brittle. It breaks
    // if you call the Velocity "reset" method.
    var velocityIsLoaded = !! VelocityAggregateReports;
    return  ! velocityIsLoaded ?  false : ! VelocityTestFiles.findOne({targetFramework: this.name});
  },
  suites: function () {
    var result =  [];
    var reports = VelocityTestReports.find({framework: this.name}).fetch();
    // XXX for now, ancestors get reduced to a single-tier suite
    // Should we do fancier indenting, etc. for nested suites?
    // If not, forcing packages to concatenate their own "suite" string
    // instead of ancestors array would clean this up.
    if (reports.length > 0) {

      var reports = _.map(reports, function (report) {
        //must clone report.ancestors to not mutate report.ancestors with .reverse()
        var ancestors = report.ancestors ? _.clone(report.ancestors) : [];
        report.suite = ancestors.reverse().join(".");
        return report;
      });

      _.each(reports, function (report) {
        if (! _.findWhere(result, {suite: report.suite}))
          result.push({
            framework: report.framework,
            ancestors: report.ancestors, //needed for future queries
            suite: report.suite
          })
      });

      return result;
    }
  },
  suiteStatus: function () {
    return suiteHasFailed(this) ? 'failed' : 'passed';
  },
  suiteNotHidden: function () {
    if (!reamplify.store('showSuccessful'))
      return suiteHasFailed(this);
    return true;
  },
  reports: function () {
    return VelocityTestReports.find({
      framework: this.framework,
      ancestors: this.ancestors
    });
  }
});

Template.velocitySummary.helpers({
  anyFailed: function () {
    var aggregateResult = VelocityAggregateReports.findOne({name: 'aggregateResult'})
    if (aggregateResult && aggregateResult.result === 'failed') {
      return  true;
    }
    return false;
  },
  totalTime: function () {
    var ms = VelocityTestReports
               .find({result: 'passed'})
               .fetch()
               .reduce(function (tot, i) { return tot + (i.duration || 0) }, 0);

    if (ms >= 1000) return Math.round(ms / 1000) + ' s';

    return ms + ' ms';
  },
  regularPlural: function (count, word, suffix) {
    if(count === 1) return word;
    return word + suffix;
  },
  totalFailedTestCount: function () {
    return VelocityTestReports.find({result: 'failed'}).count();
  },
  totalTestCount: function () {
    return VelocityTestReports.find().count();
  },
  totalPassedTestCount: function () {
    return VelocityTestReports.find({result: 'passed'}).count();
  },
});

Template.velocityControlPanel.helpers({
  mochaPresent: mochaPresent,
  nightwatchPresent: nightwatchPresent,
  showActive: function (id) {
    // XXX refactor this to name consistently
    return !reamplify.store(id) ? '' : 'active';
  },
  showActive: function (self) {
    // $self = $("#"+ self);
    return reamplify.store(self) ? 'active' : ''
  }
});

Template.velocityControlPanel.events({
  'click #runNightwatchTests': function () {
    console.log('#runNightwatchTests clicked.');
    Meteor.call('nightwatch/run');
  }
})

Template.velocityTestReport.helpers({
  reportNotHidden: function () {
    if (this.result === "failed")
      return true;
    else{
      return (reamplify.store('showSuccessful'));
    }
  },
  failed: function () {
    return (this.result === "failed");
  }
});

Template.velocityTestFiles.helpers({
  testFiles: function () {
    return VelocityTestFiles.find();
  },
  isVisible: function () {
    return amplify.store('velocityTestFilesIsVisible') ? 'block' : 'none';
  }
});

Template.velocityLogs.helpers({
  logs: function () {
    return VelocityLogs.find();
  },
  isVisible: function () {
    return amplify.store('velocityLogsIsVisible') ? 'block' : 'none';
  }
});

Template.velocity.events({
  'click .display-toggle': function (e) {
    var targetId = $(e.currentTarget).data('target'),
        $target = $('#' + targetId);
    $target.toggleClass('visible');
    amplify.store(targetId + 'IsVisible', $target.hasClass('visible') );
  },
  'change input:checkbox': function (e) {
    var targetId = e.target.id
    reamplify.store(e.target.id, e.target.checked);
  },
  'click button.control-toggle': function (e) {
    var $target = $('#' + e.target.id);
    $target.toggleClass('active');
    reamplify.store(e.target.id, $target.hasClass('active'));
  },
  'click .velocity-options-toggle': function (e, tpl) {
    tpl.$('.velocity-options').toggleClass('visible')
  }
});

Template.velocityReports.events({
  'click .copy-sample-tests': function (e) {
    Meteor.call('velocity/copySampleTests', {framework: this.name}, function (err, res) {
      // XXX This method for getting the new files to register is slow, but it
      // works. The reset method gets Velocity to see the new files.
      // We then disconnect altogether to prevent flapping of reactive
      // template elements (& overlay a notification to show the user
      // what's happening). Then we simply reload. Is there a way to do this
      // with a lighter touch?

      // make sure the user can see the demo tests, which generally pass.
      reamplify.store('showSuccessful', true);
      Session.set('resettingVelocity', true)
      Meteor.call('velocity/reset');
      Meteor.disconnect();
      location.reload();
    });
  }
});
<commit_msg>Fixes #50<commit_after>suiteHasFailed = function (suite) {
  return !!VelocityTestReports.findOne({
    framework: suite.framework,
    ancestors: suite.ancestors,
    result: "failed"
  });
};

frameworkStatus = function (name) {
  var hasTests = VelocityTestReports.find({framework: name}).count() > 0;
  if (!hasTests) return "empty"

  var frameworkExecStatus = VelocityAggregateReports.findOne({name: name});
  var isComplete = (frameworkExecStatus && frameworkExecStatus.result === "completed");
  var hasFailed = !! VelocityTestReports.findOne({framework: name, result: "failed"});

  if (hasFailed)
    return "failed";
  else if (isComplete)
    return "passed";
  else
    return "pending";
}

function mochaPresent() {
  //XXX hard-coding mocha iframe support for now
  return !! VelocityAggregateReports.findOne({'name': 'mocha'});
}
function nightwatchPresent() {
  return !! VelocityAggregateReports.findOne({'name': 'nightwatch'});
}

Template.velocity.created = function () {
  // Only show widget when we know we are NOT running in a Velocity Mirror
  Session.setDefault('velocity.isMirror', true);

  // Determine if session is running in a Velocity mirror or not
  Meteor.call('velocity/isMirror', function (err, res) {
    if (err) {
      // Log error. HTML Reporter will not be shown
      console.error(err);
    } else {
      Session.set('velocity.isMirror', res);
    }
  })
};

Template.velocity.helpers({
  statusWidgetClass: function () {
    var aggregateResult = VelocityAggregateReports.findOne({name: 'aggregateResult'});
    if (aggregateResult && aggregateResult.result === 'failed') {
      return  'failed';
    }

    var aggregateComplete = VelocityAggregateReports.findOne({name: 'aggregateComplete'});
    if (aggregateComplete && aggregateResult
      && aggregateResult.result === 'passed' && aggregateComplete.result === 'completed') {
      return 'passed';
    }
    return 'pending';
  },
  resetting: function () {
    return Session.get('resettingVelocity')
  },
  testReports: function () {
    return VelocityTestReports.find();
  },
  frameworks: function () {
    return VelocityAggregateReports.find({name: {$nin: ["aggregateResult", "aggregateComplete"]}});
  },
  active: function (id) {
    return reamplify.store(id);
  },
  overlayIsVisible: function () {
    return amplify.store('velocityOverlayIsVisible')
  },
  notInMirror: function () {
    // This causes the html reporter to remain hidden if running in a Velocity mirror
    return Session.equals('velocity.isMirror', false);
  },
  mochaPresent: mochaPresent,
  nightwatchPresent: nightwatchPresent
});

Template.velocityReports.helpers({
  frameworkStatus: function () {
    return frameworkStatus(this.name)
  },
  isPassed: function (status) {
    return status === 'passed'
  },
  frameworkTotalTestCount: function () {
    return VelocityTestReports.find({framework: this.name}).count();
  },
  frameworkPassedTestCount: function () {
    return VelocityTestReports.find({framework: this.name, result: 'passed'}).count();
  },
  noFrameworkFiles: function () {
    // XXX presence of VelocityAggregateReports is a stand-in for
    // Velocity being loaded. This is a bit brittle. It breaks
    // if you call the Velocity "reset" method.
    var velocityIsLoaded = !! VelocityAggregateReports;
    return  ! velocityIsLoaded ?  false : ! VelocityTestFiles.findOne({targetFramework: this.name});
  },
  suites: function () {
    var result =  [];
    var reports = VelocityTestReports.find({framework: this.name}).fetch();
    // XXX for now, ancestors get reduced to a single-tier suite
    // Should we do fancier indenting, etc. for nested suites?
    // If not, forcing packages to concatenate their own "suite" string
    // instead of ancestors array would clean this up.
    if (reports.length > 0) {

      var reports = _.map(reports, function (report) {
        //must clone report.ancestors to not mutate report.ancestors with .reverse()
        var ancestors = report.ancestors ? _.clone(report.ancestors) : [];
        report.suite = ancestors.reverse().join(".");
        return report;
      });

      _.each(reports, function (report) {
        if (! _.findWhere(result, {suite: report.suite}))
          result.push({
            framework: report.framework,
            ancestors: report.ancestors, //needed for future queries
            suite: report.suite
          })
      });

      return result;
    }
  },
  suiteStatus: function () {
    return suiteHasFailed(this) ? 'failed' : 'passed';
  },
  suiteNotHidden: function () {
    if (!reamplify.store('showSuccessful'))
      return suiteHasFailed(this);
    return true;
  },
  reports: function () {
    return VelocityTestReports.find({
      framework: this.framework,
      ancestors: this.ancestors
    });
  }
});

Template.velocitySummary.helpers({
  anyFailed: function () {
    var aggregateResult = VelocityAggregateReports.findOne({name: 'aggregateResult'})
    if (aggregateResult && aggregateResult.result === 'failed') {
      return  true;
    }
    return false;
  },
  totalTime: function () {
    var results = VelocityTestReports.find().fetch();

    var firstTimeStamp, lastTimestamp, lastDuration;
    _.each(results, function (result) {
      if (!firstTimeStamp ||  firstTimeStamp > result.timestamp.getTime()) {
        firstTimeStamp = result.timestamp.getTime();
      }
      if (!lastTimestamp ||  lastTimestamp < result.timestamp.getTime()) {
        lastTimestamp = result.timestamp.getTime();
        lastDuration = result.duration;
      }
    });

    //var ms = results
    //  .reduce(function (tot, i) { return tot + (i.duration || 0) }, 0);

    var ms = lastTimestamp + lastDuration - firstTimeStamp;

    if (ms >= 1000) return Math.round(ms / 1000) + ' s';

    return ms?ms:0 + ' ms';
  },
  regularPlural: function (count, word, suffix) {
    if(count === 1) return word;
    return word + suffix;
  },
  totalFailedTestCount: function () {
    return VelocityTestReports.find({result: 'failed'}).count();
  },
  totalTestCount: function () {
    return VelocityTestReports.find().count();
  },
  totalPassedTestCount: function () {
    return VelocityTestReports.find({result: 'passed'}).count();
  },
});

Template.velocityControlPanel.helpers({
  mochaPresent: mochaPresent,
  nightwatchPresent: nightwatchPresent,
  showActive: function (id) {
    // XXX refactor this to name consistently
    return !reamplify.store(id) ? '' : 'active';
  },
  showActive: function (self) {
    // $self = $("#"+ self);
    return reamplify.store(self) ? 'active' : ''
  }
});

Template.velocityControlPanel.events({
  'click #runNightwatchTests': function () {
    console.log('#runNightwatchTests clicked.');
    Meteor.call('nightwatch/run');
  }
})

Template.velocityTestReport.helpers({
  reportNotHidden: function () {
    if (this.result === "failed")
      return true;
    else{
      return (reamplify.store('showSuccessful'));
    }
  },
  failed: function () {
    return (this.result === "failed");
  }
});

Template.velocityTestFiles.helpers({
  testFiles: function () {
    return VelocityTestFiles.find();
  },
  isVisible: function () {
    return amplify.store('velocityTestFilesIsVisible') ? 'block' : 'none';
  }
});

Template.velocityLogs.helpers({
  logs: function () {
    return VelocityLogs.find();
  },
  isVisible: function () {
    return amplify.store('velocityLogsIsVisible') ? 'block' : 'none';
  }
});

Template.velocity.events({
  'click .display-toggle': function (e) {
    var targetId = $(e.currentTarget).data('target'),
        $target = $('#' + targetId);
    $target.toggleClass('visible');
    amplify.store(targetId + 'IsVisible', $target.hasClass('visible') );
  },
  'change input:checkbox': function (e) {
    var targetId = e.target.id
    reamplify.store(e.target.id, e.target.checked);
  },
  'click button.control-toggle': function (e) {
    var $target = $('#' + e.target.id);
    $target.toggleClass('active');
    reamplify.store(e.target.id, $target.hasClass('active'));
  },
  'click .velocity-options-toggle': function (e, tpl) {
    tpl.$('.velocity-options').toggleClass('visible')
  }
});

Template.velocityReports.events({
  'click .copy-sample-tests': function (e) {
    Meteor.call('velocity/copySampleTests', {framework: this.name}, function (err, res) {
      // XXX This method for getting the new files to register is slow, but it
      // works. The reset method gets Velocity to see the new files.
      // We then disconnect altogether to prevent flapping of reactive
      // template elements (& overlay a notification to show the user
      // what's happening). Then we simply reload. Is there a way to do this
      // with a lighter touch?

      // make sure the user can see the demo tests, which generally pass.
      reamplify.store('showSuccessful', true);
      Session.set('resettingVelocity', true)
      Meteor.call('velocity/reset');
      Meteor.disconnect();
      location.reload();
    });
  }
});
<|endoftext|>