<commit_before>var path = require('path');
var acorn = require('acorn');

// All CLASS modules are stored here.
var hierarchy = {};

// Files that do not declare CLASS modules are stored here.
var nonHierarchicalNodes = [];

/**
 * @function isExpressionStatement
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isExpressionStatement (node) {
    return node.type === 'ExpressionStatement';
}

/**
 * @function isCallExpression
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isCallExpression (node) {
    return node.type === 'CallExpression';
}

/**
 * @function isAssignmentExpression
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isAssignmentExpression (node) {
    // Only check for AssignmentExpressions that only use the equals sign.
    return node.type === 'AssignmentExpression' && node.operator === '=';
}

/**
 * @function isMemberExpression
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isMemberExpression (node) {
    return node.type === 'MemberExpression';
}

/**
 * @function isIdentifier
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isIdentifier (node) {
    return node.type === 'Identifier';
}

/**
 * @function isProperty
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isProperty (node) {
    return node.type === 'Property';
}

/**
 * Create hierarchy nodes for all CLASS modules.
 *
 * @function createHierarchyNode
 * @param {String} name
 * @api private
 */

function createHierarchyNode (name) {
    if (hierarchy[name] !== undefined) { return undefined; }

    hierarchy[name] = {
        content: '',            // Read file content.
        children: [],           // All parsed children in extend invocations.
        parentName: '',         // Parsed parent in extend invocation.
        moduleAppend: null,     // Append node in AST.
        moduleConstructor: null // Constructor Node in AST.
    };
}

/**
 * Append nodes that contain the content of files
 * that have no CLASS module declarations.
 *
 * @function createNonHierarchicalNode
 * @param {String} content
 * @api private
 */

function createNonHierarchicalNode (content) {
    nonHierarchicalNodes.push({
        content: content
    });
}

/**
 * Read file content and parse it for CLASS modules.
 *
 * @function parseFile
 * @param {Object} grunt
 * @param {String} filePath
 * @api private
 */

function parseFile(grunt, filePath) {
    var content = grunt.file.read(filePath);

    var ast = acorn.parse(content, {
        sourceType: 'script',
        ecmaVersion: 6
    });

    var parseOne = parseExtend(ast);
    var parseTwo = parseClass(ast, content);

    // If no extend invocation and no CLASS declaration is found,
    // then push file content into a non hierarchical node.
    if (!parseOne && !parseTwo) {
        createNonHierarchicalNode(content);
    }
}

/**
 * Iterate on top level expression statements for extend invocation.
 *
 * @function parseExtend
 * @param {Object} ast
 * @return {Boolean}
 * @api private
 */

function parseExtend (ast) {
    for (var i = 0, max = ast.body.length; i < max; i++) {
        var node = ast.body[i];

        // Search for extend('Parent', 'Child');
        if (isExpressionStatement(node) && isCallExpression(node.expression) && node.expression.callee.name === 'extend') {
            node = node.expression;

            var parentName = node.arguments[0].value;
            var childName = node.arguments[1].value;

            createHierarchyNode(parentName);
            createHierarchyNode(childName);

            // Link child.
            hierarchy[parentName].children.push(childName);

            // Link parent.
            hierarchy[childName].parentName = parentName;

            return true;
        }
    }

    return false;
}

/**
 * Iterate on top level expression statements for CLASS constructor
 * and append assignment expressions.
 *
 * @function parseClass
 * @param {Object} ast
 * @param {String} content
 * @return {Boolean}
 * @api private
 */

function parseClass (ast, content) {
    var moduleAppend = null;
    var moduleAppendName = '';

    var moduleConstructor = null;
    var moduleConstructorName = '';

    for (var i = 0, max = ast.body.length; i < max; i++) {
        var node = ast.body[i];

        if (!isExpressionStatement(node) || !isAssignmentExpression(node.expression)) { continue; }

        node = node.expression;

        // Search for constructor -> CLASS.Module = function () {};
        if (isIdentifier(node.left.object) && isIdentifier(node.left.property) && node.left.object.name === 'CLASS') {
            moduleConstructor = node;
            moduleConstructorName = node.left.property.name;

        // Search for append -> CLASS.Module.append = {};
        } else if (isMemberExpression(node.left.object)) {
            var subNode = node.left;

            if (isIdentifier(subNode.object.object) && isIdentifier(subNode.object.property)) {
                if (subNode.object.object.name !== 'CLASS' || subNode.property.name !== 'append') { continue; }

                moduleAppend = node;
                moduleAppendName = subNode.object.property.name;
            }
        }
    }

    // If no constructor or append node is found or if the constructor and
    // append name do not match then don't create the hierarchy node.
    if (moduleConstructor === null || moduleAppend === null) {
        return false;
    } else if (moduleConstructorName !== moduleAppendName) {
        return false;
    }

    createHierarchyNode(moduleConstructorName);

    var hierarchyNode = hierarchy[moduleConstructorName];

    // Store file content if CLASS module is parsed successfully.
    hierarchyNode.content = content;

    // Store constructor and append nodes for concatenation.
    hierarchyNode.moduleAppend = moduleAppend;
    hierarchyNode.moduleConstructor = moduleConstructor;

    return true;
}

/**
 * Concatenate all parsed modules into a single string.
 *
 * @function concatenateParsedModules
 * @return {String}
 * @api private
 */

function concatenateParsedModules () {
    var content = '';
    var moduleNames = Object.keys(hierarchy);

    for (var i = 0, max = moduleNames.length; i < max; i++) {
        var name = moduleNames[i];
        var node = hierarchy[name];

        // Recursively concatenate top level CLASS modules only.
        if (node.parentName === '') {
            content += concatenateClassModule(name, node);
        }
    }

    // Simply append all non hierarchical modules after
    // concatenating all CLASS modules.
    content += concatenateNonHierarchicalModules();

    // Replace all _$_ prototype shorthand references with the
    // standard prototype notation.
    content = content.replace(/\_\$\_\s*?\.\s*?([A-Za-z0-9\_]+)/g, function (match, $1) {
        return 'CLASS.' + $1 + '.prototype';
    });

    return content;
}

/**
 * Append recursively CLASS module hierarchy.
 *
 * @function concatenateClassModule
 * @param {String} name
 * @param {Object} node
 * @return {String}
 * @api private
 */

function concatenateClassModule (name, node) {
    // Append content for parent node before appending the content
    // of all the child nodes.
    var content = concatenateClassConstructor(name, node) + concatenateClassAppend(name, node);

    for (var i = 0, max = node.children.length; i < max; i++) {
        var childName = node.children[i];
        var childNode = hierarchy[childName];

        content += concatenateClassModule(childName, childNode);
    }

    return content;
}

function concatenateClassConstructor (name, node) {
    var content = '\x0A';
    var subString = node.content.substring(node.moduleConstructor.right.start, node.moduleConstructor.right.end);

    if (hierarchy[name].parentName !== '') {
        subString = replaceClassSuper(name, subString);
    }

    content += 'CLASS.' + name + ' = ' + subString + ';';

    return content + '\x0A';
}

function replaceClassSuper (name, content) {
    var replaced = false;

    content = content.replace(/this\s*?\.\s*?super\s*?\(\s*?\)/, function (match) {
        replaced = true;

        return 'CLASS.' + hierarchy[name].parentName + '.call(this)';
    });

    if (replaced) { return content; }

    content = content.replace(/this\s*?\.\s*?super\s*?\(/, function (match) {
        return 'CLASS.' + hierarchy[name].parentName + '.call(this, ';
    });

    return content;
}

function concatenateClassAppend (name, node) {
    var content = '\x0A';

    content += 'CLASS.' + name + '.prototype = ';

    if (node.parentName === '') {
        content += 'Object.create(CLASS.prototype);\x0A\x0A';
    } else {
        content += 'Object.create(CLASS.' + node.parentName + '.prototype);\x0A\x0A';
    }

    content += 'CLASS.' + name + '.prototype.constructor = ' + 'CLASS.' + name + ';';
    content += concatenateClassAppendProperties(name, node);

    return content + '\x0A';
}

function concatenateClassAppendProperties (name, node) {
    var properties = node.moduleAppend.right.properties;
    var max = properties.length;

    if (max === 0) { return ''; }

    var content = '';

    for (var i = 0; i < max; i++) {
        var subNode = properties[i];

        if (!isProperty(subNode)) { continue; }

        content += '\x0A\x0A';
        content += 'CLASS.' + name + '.prototype.' + subNode.key.name + ' = ';
        content += node.content.substring(subNode.value.start, subNode.value.end) + ';';
    }

    return content;
}

function concatenateNonHierarchicalModules () {
    var content = '';

    for (var i = 0, max = nonHierarchicalNodes.length; i < max; i++) {
        content += '\x0A' + nonHierarchicalNodes[i].content + '\x0A';
    }

    return content;
}

module.exports = function (grunt, task, taskData, tmpDir, srcFiles) {
    for (var i = 0, max = srcFiles.length; i < max; i++) {
        parseFile(grunt, srcFiles[i]);
    }

    grunt.file.write(path.join(tmpDir, 'parsed-src-files.js'), concatenateParsedModules());
};
<commit_msg>{Update: parse.js} Module restructure.<commit_after>var path = require('path');
var acorn = require('acorn');

// All CLASS modules are stored here.
var hierarchy = {};

// Files that do not declare CLASS modules are stored here.
var nonHierarchicalNodes = [];

/**
 * @function isExpressionStatement
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isExpressionStatement (node) {
    return node.type === 'ExpressionStatement';
}

/**
 * @function isCallExpression
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isCallExpression (node) {
    return node.type === 'CallExpression';
}

/**
 * @function isAssignmentExpression
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isAssignmentExpression (node) {
    // Only check for AssignmentExpressions that only use the equals sign.
    return node.type === 'AssignmentExpression' && node.operator === '=';
}

/**
 * @function isMemberExpression
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isMemberExpression (node) {
    return node.type === 'MemberExpression';
}

/**
 * @function isIdentifier
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isIdentifier (node) {
    return node.type === 'Identifier';
}

/**
 * @function isProperty
 * @param {Object} node
 * @return {Boolean}
 * @api private
 */

function isProperty (node) {
    return node.type === 'Property';
}

/**
 * Create hierarchy nodes for all CLASS modules.
 *
 * @function createHierarchyNode
 * @param {String} name
 * @api private
 */

function createHierarchyNode (name) {
    if (hierarchy[name] !== undefined) { return undefined; }

    hierarchy[name] = {
        content: '',            // Read file content.
        children: [],           // All parsed children in extend invocations.
        parentName: '',         // Parsed parent in extend invocation.
        moduleAppend: null,     // Append node in AST.
        moduleConstructor: null // Constructor Node in AST.
    };
}

/**
 * Append nodes that contain the content of files
 * that have no CLASS module declarations.
 *
 * @function createNonHierarchicalNode
 * @param {String} content
 * @api private
 */

function createNonHierarchicalNode (content) {
    nonHierarchicalNodes.push({
        content: content
    });
}

/**
 * Read file content and parse it for CLASS modules.
 *
 * @function parseFile
 * @param {Object} grunt
 * @param {String} filePath
 * @api private
 */

function parseFile(grunt, filePath) {
    var content = grunt.file.read(filePath);

    var ast = acorn.parse(content, {
        sourceType: 'script',
        ecmaVersion: 6
    });

    var parseOne = parseExtend(ast);
    var parseTwo = parseClass(ast, content);

    // If no extend invocation and no CLASS declaration is found,
    // then push file content into a non hierarchical node.
    if (!parseOne && !parseTwo) {
        createNonHierarchicalNode(content);
    }
}

/**
 * Iterate on top level expression statements for extend invocation.
 *
 * @function parseExtend
 * @param {Object} ast
 * @return {Boolean}
 * @api private
 */

function parseExtend (ast) {
    for (var i = 0, max = ast.body.length; i < max; i++) {
        var node = ast.body[i];

        // Search for extend('Parent', 'Child');
        if (isExpressionStatement(node) && isCallExpression(node.expression) && node.expression.callee.name === 'extend') {
            node = node.expression;

            var parentName = node.arguments[0].value;
            var childName = node.arguments[1].value;

            createHierarchyNode(parentName);
            createHierarchyNode(childName);

            // Link child.
            hierarchy[parentName].children.push(childName);

            // Link parent.
            hierarchy[childName].parentName = parentName;

            return true;
        }
    }

    return false;
}

/**
 * Iterate on top level expression statements for CLASS constructor
 * and append assignment expressions.
 *
 * @function parseClass
 * @param {Object} ast
 * @param {String} content
 * @return {Boolean}
 * @api private
 */

function parseClass (ast, content) {
    var moduleAppend = null;
    var moduleAppendName = '';

    var moduleConstructor = null;
    var moduleConstructorName = '';

    for (var i = 0, max = ast.body.length; i < max; i++) {
        var node = ast.body[i];

        if (!isExpressionStatement(node) || !isAssignmentExpression(node.expression)) { continue; }

        node = node.expression;

        // Search for constructor -> CLASS.Module = function () {};
        if (isIdentifier(node.left.object) && isIdentifier(node.left.property) && node.left.object.name === 'CLASS') {
            moduleConstructor = node;
            moduleConstructorName = node.left.property.name;

        // Search for append -> CLASS.Module.append = {};
        } else if (isMemberExpression(node.left.object)) {
            var subNode = node.left;

            if (isIdentifier(subNode.object.object) && isIdentifier(subNode.object.property)) {
                if (subNode.object.object.name !== 'CLASS' || subNode.property.name !== 'append') { continue; }

                moduleAppend = node;
                moduleAppendName = subNode.object.property.name;
            }
        }
    }

    // If no constructor or append node is found or if the constructor and
    // append name do not match then don't create the hierarchy node.
    if (moduleConstructor === null || moduleAppend === null) {
        return false;
    } else if (moduleConstructorName !== moduleAppendName) {
        return false;
    }

    createHierarchyNode(moduleConstructorName);

    var hierarchyNode = hierarchy[moduleConstructorName];

    // Store file content if CLASS module is parsed successfully.
    hierarchyNode.content = content;

    // Store constructor and append nodes for concatenation.
    hierarchyNode.moduleAppend = moduleAppend;
    hierarchyNode.moduleConstructor = moduleConstructor;

    return true;
}

/**
 * Concatenate all parsed modules into a single string.
 *
 * @function concatenateParsedModules
 * @return {String}
 * @api private
 */

function concatenateParsedModules () {
    var content = '';
    var moduleNames = Object.keys(hierarchy);

    for (var i = 0, max = moduleNames.length; i < max; i++) {
        var name = moduleNames[i];
        var node = hierarchy[name];

        // Recursively concatenate top level CLASS modules only.
        if (node.parentName === '') {
            content += concatenateClassModule(name, node);
        }
    }

    // Simply append all non hierarchical nodes after
    // concatenating all CLASS modules.
    content += concatenateNonHierarchicalNodes();

    return content;
}

/**
 * Append recursively CLASS module hierarchy.
 *
 * @function concatenateClassModule
 * @param {String} name
 * @param {Object} node
 * @return {String}
 * @api private
 */

function concatenateClassModule (name, node) {
    // Append content for parent node before appending the content
    // of all the child nodes.
    var content = concatenateClassConstructor(name, node) + concatenateClassAppend(name, node);

    for (var i = 0, max = node.children.length; i < max; i++) {
        var childName = node.children[i];
        var childNode = hierarchy[childName];

        content += concatenateClassModule(childName, childNode);
    }

    return content;
}

/**
 * @function concatenateClassConstructor
 * @param {String} name
 * @param {Object} node
 * @return {String}
 * @api private
 */

function concatenateClassConstructor (name, node) {
    var content = '\x0A';
    var subString = node.content.substring(node.moduleConstructor.right.start, node.moduleConstructor.right.end);

    if (hierarchy[name].parentName !== '') {
        subString = replaceClassSuper(name, subString);
    }

    content += 'CLASS.' + name + ' = ' + subString + ';';

    return content + '\x0A';
}

/**
 * @function replaceClassSuper
 * @param {String} name
 * @param {String} content
 * @return {String}
 * @api private
 */

function replaceClassSuper (name, content) {
    var replaced = false;

    // Super invocation with no argument.
    // Regex Match: this.super()
    content = content.replace(/this\s*?\.\s*?super\s*?\(\s*?\)/, function (match) {
        replaced = true;

        return 'CLASS.' + hierarchy[name].parentName + '.call(this)';
    });

    // Only one regex has to match and replace.
    if (replaced) { return content; }

    // Super invocation with arguments.
    // Regex Match: this.super(
    content = content.replace(/this\s*?\.\s*?super\s*?\(/, function (match) {
        return 'CLASS.' + hierarchy[name].parentName + '.call(this, ';
    });

    return content;
}

/**
 * @function concatenateClassAppend
 * @param {String} name
 * @param {Object} node
 * @return {String}
 * @api private
 */

function concatenateClassAppend (name, node) {
    var content = '\x0A';

    // Start parent prototype wrap.
    content += 'CLASS.' + name + '.prototype = Object.create(CLASS.';

    // Concatenate module's parent name if it isn't an empty string.
    if (node.parentName !== '') {
        content += node.parentName + '.';
    }

    // End parent prototype wrap.
    content += 'prototype);\x0A\x0A';

    // The constructor property is the only one that is assigned automatically.
    content += 'CLASS.' + name + '.prototype.constructor = ' + 'CLASS.' + name + ';';

    content += concatenateClassAppendProperties(name, node);

    // Only replace prototype shorthand declarations in the CLASS append.
    content = replaceClassPrototypeShorthand(content);

    return content + '\x0A';
}

/**
 * @function concatenateClassAppendProperties
 * @param {String} name
 * @param {Object} node
 * @return {String}
 * @api private
 */

function concatenateClassAppendProperties (name, node) {
    var properties = node.moduleAppend.right.properties;
    var max = properties.length;

    if (max === 0) { return ''; }

    var content = '';

    for (var i = 0; i < max; i++) {
        var subNode = properties[i];

        if (!isProperty(subNode)) { continue; }

        content += '\x0A\x0A';
        content += 'CLASS.' + name + '.prototype.' + subNode.key.name + ' = ';
        content += node.content.substring(subNode.value.start, subNode.value.end) + ';';
    }

    return content;
}

/**
 * Replace all _$_ prototype shorthand references with the
 * standard prototype notation.
 *
 * @function replaceClassPrototypeShorthand
 * @param {String} content
 * @return {String}
 * @api private
 */

function replaceClassPrototypeShorthand (content) {
    // Regex Match: _$_.(Module)
    return content.replace(/\_\$\_\s*?\.\s*?([A-Za-z0-9\_]+)/g, function (match, $1) {
        return 'CLASS.' + $1 + '.prototype';
    });
}

/**
 * @function concatenateNonHierarchicalNodes
 * @return {String}
 * @api private
 */

function concatenateNonHierarchicalNodes () {
    var content = '';

    for (var i = 0, max = nonHierarchicalNodes.length; i < max; i++) {
        content += '\x0A' + nonHierarchicalNodes[i].content + '\x0A';
    }

    return content;
}

module.exports = function (grunt, task, taskData, tmpDir, srcFiles) {
    // Parse all modules before creating temporary file.
    for (var i = 0, max = srcFiles.length; i < max; i++) {
        parseFile(grunt, srcFiles[i]);
    }

    grunt.file.write(path.join(tmpDir, 'parsed-src-files.js'), concatenateParsedModules());
};
<|endoftext|>


<commit_before><commit_msg>feat(sublist): make selection sticky<commit_after><|endoftext|>


<commit_before>console.log(data);
var model = Autoencoder.deserialize(data);
console.log(model);

var app = angular.module("myApp",[]);
app.controller('InputController', function($scope){
  $scope.headers = model.headers.map(function(x) { return x.replace(/_/g, ' '); });
  $scope.charts = [];
});

app.directive("renderChart",function(){
  return function($scope, element, attrs){
    var j = $scope.$index;
    var getUpdateFn = function(index) {
      return function(update, newValue) { redraw($scope.charts, update, index, newValue); };
    }
    var chart = new Chart(element, getUpdateFn(j));

    $scope.charts.push(chart);

    if ($scope.charts.length == $scope.headers.length) {
      redraw($scope.charts, true);
    }
  }
});

function redraw(charts, update, index, newValue) {
  if (update && newValue != undefined)
    charts[index].fixedValue = newValue;

  var row = [];
  for (var j = 0; j < charts.length; j++)
    row.push(charts[j].fixedValue);

  if (newValue != undefined)
    row[index] = newValue;

  var curves = model.getPdfs(row);

  for (var j = 0; j < row.length; j++) {
    if (update)
      charts[j].update(curves[j].xy);
    else
      charts[j].updateHypothetical(curves[j].xy);
  }
}

function Chart(element, redraw) {
  this.margin = {top: 10, right: 30, bottom: 30, left: 30};
  this.width = element[0].offsetWidth,
  this.height = element[0].offsetHeight,
  this.nBins = 30;
  this.fixedValue = undefined;
  this.redraw = redraw;

  var barWidth = Math.floor(this.width/this.nBins);
  this.width = barWidth * this.nBins;

  var svg = d3.select(element[0])
      .append('svg')
      .attr("width", this.width) // + this.margin.left + this.margin.right)
      .attr("height", this.height) // - this.margin.top - this.margin.bottom)
      .append("g");

  this.axis = svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + (this.height - this.margin.bottom) + ")");

  this.path = svg.append('path')
    .attr('stroke', 'black')
    .attr('stroke-weight', '5')
    .attr('fill', 'none');

  this.hypotheticalPath = svg.append('path')
    .attr('stroke', 'red')
    .attr('stroke-weight', '5')
    .attr('fill', 'none');

  var focus = svg.append("g")
      .attr("class", "focus")
      .style("display", "none");

  focus.append("circle")
    .attr("r", 4.5);

  focus.append("text")
    .attr("x", 9)
    .attr("dy", ".35em");

  svg.append("rect")
    .attr("fill", "none")
    .attr("pointer-events", "all")
    .attr("width", this.width)
    .attr("height", this.height)
    .on("mouseover", function() { focus.style("display", null); })
    .on("mouseout", function() { focus.style("display", "none"); })
    .on("mousemove", getEventHandler(false))
    .on("click", getEventHandler(true));

  var bisectData = d3.bisector(function(d) { return d.x; }).left;

  var chart = this;

  function getEventHandler(update) {
    return function() {
      if (!chart.data)
	return;

      var x0 = chart.x.invert(d3.mouse(this)[0]);

      // TODO: linear interpolation
      focus.attr("transform", "translate(" + chart.x(x0) + "," + chart.y(0) + ")");
      focus.select("text").text(x0);

      chart.redraw(update, x0);
    }
  }
}

Chart.prototype.update = function(data) {
  this.data = data;

  this.x = d3.scale.linear()
    .domain(d3.extent(data, function(d) { return d.x; }))
    .range([0, this.width]);

  this.y = d3.scale.linear()
    .domain([0, d3.max(data, function(d) { return d.y; })])
    .range([this.height - this.margin.bottom, 0]);

  var xAxis = d3.svg.axis()
      .scale(this.x)
      .orient("bottom");

  this.axis.call(xAxis);

  var chart = this;
  var lineFunction = d3.svg.line()
      .x(function(d) { return chart.x(d.x); })
      .y(function(d) { return chart.y(d.y); })
      .interpolate("basis");

  this.path.attr('d', lineFunction(this.data))
}

Chart.prototype.updateHypothetical = function(data) {
  var chart = this;
  var lineFunction = d3.svg.line()
      .x(function(d) { return chart.x(d.x); })
      .y(function(d) { return chart.y(d.y); })
      .interpolate("basis");

  this.hypotheticalPath.attr('d', lineFunction(data));
}
<commit_msg>no interpolation<commit_after>console.log(data);
var model = Autoencoder.deserialize(data);
console.log(model);

var app = angular.module("myApp",[]);
app.controller('InputController', function($scope){
  $scope.headers = model.headers.map(function(x) { return x.replace(/_/g, ' '); });
  $scope.charts = [];
});

app.directive("renderChart",function(){
  return function($scope, element, attrs){
    var j = $scope.$index;
    var getUpdateFn = function(index) {
      return function(update, newValue) { redraw($scope.charts, update, index, newValue); };
    }
    var chart = new Chart(element, getUpdateFn(j));

    $scope.charts.push(chart);

    if ($scope.charts.length == $scope.headers.length) {
      redraw($scope.charts, true);
    }
  }
});

function redraw(charts, update, index, newValue) {
  if (update && newValue != undefined)
    charts[index].fixedValue = newValue;

  var row = [];
  for (var j = 0; j < charts.length; j++)
    row.push(charts[j].fixedValue);

  if (newValue != undefined)
    row[index] = newValue;

  var curves = model.getPdfs(row);

  for (var j = 0; j < row.length; j++) {
    if (update)
      charts[j].update(curves[j].xy);
    else
      charts[j].updateHypothetical(curves[j].xy);
  }
}

function Chart(element, redraw) {
  this.margin = {top: 10, right: 30, bottom: 30, left: 30};
  this.width = element[0].offsetWidth,
  this.height = element[0].offsetHeight,
  this.nBins = 30;
  this.fixedValue = undefined;
  this.redraw = redraw;

  var barWidth = Math.floor(this.width/this.nBins);
  this.width = barWidth * this.nBins;

  var svg = d3.select(element[0])
      .append('svg')
      .attr("width", this.width) // + this.margin.left + this.margin.right)
      .attr("height", this.height) // - this.margin.top - this.margin.bottom)
      .append("g");

  this.axis = svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + (this.height - this.margin.bottom) + ")");

  this.path = svg.append('path')
    .attr('stroke', 'black')
    .attr('stroke-weight', '5')
    .attr('fill', 'none');

  this.hypotheticalPath = svg.append('path')
    .attr('stroke', 'red')
    .attr('stroke-weight', '5')
    .attr('fill', 'none');

  var focus = svg.append("g")
      .attr("class", "focus")
      .style("display", "none");

  focus.append("circle")
    .attr("r", 4.5);

  focus.append("text")
    .attr("x", 9)
    .attr("dy", ".35em");

  svg.append("rect")
    .attr("fill", "none")
    .attr("pointer-events", "all")
    .attr("width", this.width)
    .attr("height", this.height)
    .on("mouseover", function() { focus.style("display", null); })
    .on("mouseout", function() { focus.style("display", "none"); })
    .on("mousemove", getEventHandler(false))
    .on("click", getEventHandler(true));

  var bisectData = d3.bisector(function(d) { return d.x; }).left;

  var chart = this;

  function getEventHandler(update) {
    return function() {
      if (!chart.data)
	return;

      var x0 = chart.x.invert(d3.mouse(this)[0]);

      // TODO: linear interpolation
      focus.attr("transform", "translate(" + chart.x(x0) + "," + chart.y(0) + ")");
      focus.select("text").text(x0);

      chart.redraw(update, x0);
    }
  }
}

Chart.prototype.update = function(data) {
  this.data = data;

  this.x = d3.scale.linear()
    .domain(d3.extent(data, function(d) { return d.x; }))
    .range([0, this.width]);

  this.y = d3.scale.linear()
    .domain([0, d3.max(data, function(d) { return d.y; })])
    .range([this.height - this.margin.bottom, 0]);

  var xAxis = d3.svg.axis()
      .scale(this.x)
      .orient("bottom");

  this.axis.call(xAxis);

  var chart = this;
  var lineFunction = d3.svg.line()
      .x(function(d) { return chart.x(d.x); })
      .y(function(d) { return chart.y(d.y); });

  this.path.attr('d', lineFunction(this.data))
}

Chart.prototype.updateHypothetical = function(data) {
  var chart = this;
  var lineFunction = d3.svg.line()
      .x(function(d) { return chart.x(d.x); })
      .y(function(d) { return chart.y(d.y); });

  this.hypotheticalPath.attr('d', lineFunction(data));
}
<|endoftext|>


<commit_before>/*
 * grunt-protractor-runner
 * https://github.com/teerapap/grunt-protractor-runner
 *
 * Copyright (c) 2013 Teerapap Changwichukarn
 * Licensed under the MIT license.
 */

'use strict';

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

module.exports = function(grunt) {

  grunt.registerMultiTask('protractor', 'A grunt task to run protractor.', function() {

    // '.../node_modules/protractor/lib/protractor.js'
    var protractorMainPath = require.resolve('protractor');
    // '.../node_modules/protractor/bin/protractor'
    var protractorBinPath = path.resolve(protractorMainPath, '../../bin/protractor');
    // '.../node_modules/protractor/referenceConf.js'
    var protractorRefConfPath = path.resolve(protractorMainPath, '../../referenceConf.js');

    // Merge task-specific and/or target-specific options with these defaults.
    var opts = this.options({
      configFile: protractorRefConfPath,
      keepAlive: true,
      noColor: false,
      debug: false,
      args: {}
    });

    // configFile is a special property which need not to be in options{} object.
    if (!grunt.util._.isUndefined(this.data.configFile)) {
      opts.configFile = this.data.configFile;
    }

    grunt.verbose.writeln("Options: " + util.inspect(opts));

    var keepAlive = opts['keepAlive'];
    var strArgs = ["seleniumAddress", "seleniumServerJar", "seleniumPort", "baseUrl", "rootElement", "browser", "chromeDriver", "chromeOnly", "sauceUser", "sauceKey", "framework"];
    var listArgs = ["specs"];
    var boolArgs = ["includeStackTrace", "verbose"];
    var objectArgs = ["params", "capabilities", "cucumberOpts"];

    var args = [protractorBinPath, opts.configFile];
    if (opts.noColor){
      args.push('--no-jasmineNodeOpts.showColors');
    }
    if (!grunt.util._.isUndefined(opts.debug) && opts.debug === true){
      args.splice(1,0,'debug');
    }

    // Iterate over all supported arguments.
    strArgs.forEach(function(a) {
      if (a in opts.args || grunt.option(a)) {
        args.push('--'+a, grunt.option(a) || opts.args[a]);
      }
    });
    listArgs.forEach(function(a) {
      if (a in opts.args || grunt.option(a)) {
        args.push('--'+a,  grunt.option(a) || opts.args[a].join(","));
      }
    });
    boolArgs.forEach(function(a) {
      if (a in opts.args || grunt.option(a)) {
        args.push('--'+a);
      }
    });

    // Convert [object] to --[object].key1 val1 --[object].key2 val2 ....
    objectArgs.forEach(function(a) {
      (function convert(prefix, obj, args) {
        for (var key in obj) {
          var val = obj[key];
          var type = typeof obj[key];
          if (type === "object") {
            if (Array.isArray(val)) {
              // Add duplicates --[object].key val1 --[object].key val2 ...
              for (var i=0;i<val.length;i++) {
                args.push(prefix+"."+key, val[i]);
              }
            } else {
              // Dig deeper
              convert(prefix+"."+key, val, args);
            }
          } else if (type === "undefined" || type === "function") {
            // Skip these types
          } else if (type === "boolean") {
            // Add --[object].key
            args.push(prefix+"."+key);
          } else {
            // Add --[object].key value
            args.push(prefix+"."+key, val);
          }
        }
      })("--" + a, opts.args[a], args);
    });

    grunt.verbose.writeln("Spawn node with arguments: " + args.join(" "));

    // Spawn protractor command
    var done = this.async();
    grunt.util.spawn({
        cmd: 'node',
        args: args,
        opts: {
          stdio:'inherit'
        }
      },
      function(error, result, code) {
        if (error) {
          grunt.log.error(String(result));
          if(code === 1 && keepAlive) {
            // Test fails but do not want to stop the grunt process.
            grunt.log.oklns("Test failed but keep the grunt process alive.");
            done();
            done = null;
          } else {
            // Test fails and want to stop the grunt process,
            // or protractor exited with other reason.
            grunt.fail.fatal('protractor exited with code: '+code, 3);
          }
        } else {
          done();
          done = null;
        }
      }
    );
  });

};
<commit_msg>add support for exclude argument<commit_after>/*
 * grunt-protractor-runner
 * https://github.com/teerapap/grunt-protractor-runner
 *
 * Copyright (c) 2013 Teerapap Changwichukarn
 * Licensed under the MIT license.
 */

'use strict';

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

module.exports = function(grunt) {

  grunt.registerMultiTask('protractor', 'A grunt task to run protractor.', function() {

    // '.../node_modules/protractor/lib/protractor.js'
    var protractorMainPath = require.resolve('protractor');
    // '.../node_modules/protractor/bin/protractor'
    var protractorBinPath = path.resolve(protractorMainPath, '../../bin/protractor');
    // '.../node_modules/protractor/referenceConf.js'
    var protractorRefConfPath = path.resolve(protractorMainPath, '../../referenceConf.js');

    // Merge task-specific and/or target-specific options with these defaults.
    var opts = this.options({
      configFile: protractorRefConfPath,
      keepAlive: true,
      noColor: false,
      debug: false,
      args: {}
    });

    // configFile is a special property which need not to be in options{} object.
    if (!grunt.util._.isUndefined(this.data.configFile)) {
      opts.configFile = this.data.configFile;
    }

    grunt.verbose.writeln("Options: " + util.inspect(opts));

    var keepAlive = opts['keepAlive'];
    var strArgs = ["seleniumAddress", "seleniumServerJar", "seleniumPort", "baseUrl", "rootElement", "browser", "chromeDriver", "chromeOnly", "sauceUser", "sauceKey", "framework"];
    var listArgs = ["specs", "exclude"];
    var boolArgs = ["includeStackTrace", "verbose"];
    var objectArgs = ["params", "capabilities", "cucumberOpts"];

    var args = [protractorBinPath, opts.configFile];
    if (opts.noColor){
      args.push('--no-jasmineNodeOpts.showColors');
    }
    if (!grunt.util._.isUndefined(opts.debug) && opts.debug === true){
      args.splice(1,0,'debug');
    }

    // Iterate over all supported arguments.
    strArgs.forEach(function(a) {
      if (a in opts.args || grunt.option(a)) {
        args.push('--'+a, grunt.option(a) || opts.args[a]);
      }
    });
    listArgs.forEach(function(a) {
      if (a in opts.args || grunt.option(a)) {
        args.push('--'+a,  grunt.option(a) || opts.args[a].join(","));
      }
    });
    boolArgs.forEach(function(a) {
      if (a in opts.args || grunt.option(a)) {
        args.push('--'+a);
      }
    });

    // Convert [object] to --[object].key1 val1 --[object].key2 val2 ....
    objectArgs.forEach(function(a) {
      (function convert(prefix, obj, args) {
        for (var key in obj) {
          var val = obj[key];
          var type = typeof obj[key];
          if (type === "object") {
            if (Array.isArray(val)) {
              // Add duplicates --[object].key val1 --[object].key val2 ...
              for (var i=0;i<val.length;i++) {
                args.push(prefix+"."+key, val[i]);
              }
            } else {
              // Dig deeper
              convert(prefix+"."+key, val, args);
            }
          } else if (type === "undefined" || type === "function") {
            // Skip these types
          } else if (type === "boolean") {
            // Add --[object].key
            args.push(prefix+"."+key);
          } else {
            // Add --[object].key value
            args.push(prefix+"."+key, val);
          }
        }
      })("--" + a, opts.args[a], args);
    });

    grunt.verbose.writeln("Spawn node with arguments: " + args.join(" "));

    // Spawn protractor command
    var done = this.async();
    grunt.util.spawn({
        cmd: 'node',
        args: args,
        opts: {
          stdio:'inherit'
        }
      },
      function(error, result, code) {
        if (error) {
          grunt.log.error(String(result));
          if(code === 1 && keepAlive) {
            // Test fails but do not want to stop the grunt process.
            grunt.log.oklns("Test failed but keep the grunt process alive.");
            done();
            done = null;
          } else {
            // Test fails and want to stop the grunt process,
            // or protractor exited with other reason.
            grunt.fail.fatal('protractor exited with code: '+code, 3);
          }
        } else {
          done();
          done = null;
        }
      }
    );
  });

};
<|endoftext|>


<commit_before>/*
 * This file is part of the Brickrouge package.
 *
 * (c) Olivier Laviale <olivier.laviale@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

define('Brickrouge.Form', [

	'./Core',
	'olvlvl-subject'

], function (Brickrouge, Subject) {

	"use strict";

	/**
	 * Key for generic errors
	 */
	const GENERIC = '__generic__'

	/**
	 * Fired before the form is submitted.
	 *
	 * @event Brickrouge.Form#submit
	 */
	const SubmitEvent = Subject.createEvent(function () {

	})

	/**
	 * Fired before the XHR is sent
	 *
	 * @event Brickrouge.Form#request
	 */
	const RequestEvent = Subject.createEvent(function () {

	})

	/**
	 * Fired when the request is successful
	 *
	 * @param {object} response
	 *
	 * @event Brickrouge.Form#success
	 * @property {object} response
	 */
	const SuccessEvent = Subject.createEvent(function (response) {

		this.response = response

	})

	/**
	 * Fired when the request failed
	 *
	 * @param {XMLHttpRequest} xhr
	 * @param {object} response
	 *
	 * @event Brickrouge.Form#failure
	 * @property {XMLHttpRequest} xhr
	 * @property {object} response
	 */
	const FailureEvent = Subject.createEvent(function (xhr, response) {

		this.xhr = xhr
		this.response = response

	})

	/**
	 * Fired when the request is complete
	 *
	 * @event Brickrouge.Form#complete
	 */
	const CompleteEvent = Subject.createEvent(function () {

	})

	/**
	 * Support for asynchronous forms.
	 */
	const Form = new Class({

		Implements: [ Subject ],

		options:
		{
			url: null,
			useXHR: false,
			replaceOnSuccess: false
		},

		initialize: function(el, options)
		{
			this.element = el
			Object.assign(this.options, options)

			forms[Brickrouge.uidOf(el)] = this

			el.addEventListener('submit', ev => {

				if (!this.isProcessingSubmit) return

				ev.preventDefault()

				this.submit()

			})
		},

		/**
		 * Determine whether the submit event should be processed by the class.
		 *
		 * @returns bool
		 */
		isProcessingSubmit: function()
		{
			let options = this.options

			return options.useXHR
			|| options.onRequest
			|| options.onComplete
			|| options.onFailure
			|| options.onSuccess
			|| options.replaceOnSuccess
		},

		alert: function(messages, type)
		{
			let original = messages
			let alert = this.element.querySelector('.alert-' + type)
			|| new Element('.alert.alert-' + type + '.dismissible').adopt(new Element('button.close[type="button"][data-dismiss="alert"]', { html: '×' }))

			if (typeOf(messages) == 'string')
			{
				messages = [ messages ]
			}
			else if (typeOf(messages) == 'object')
			{
				messages = []

				Object.forEach(original, (message, id) => {

					if (id !== GENERIC)
					{
						this.addError(id)
					}

					if (!message || message === true)
					{
						return
					}

					messages.push(message)

				})
			}

			if (!messages.length)
			{
				return
			}

			messages.forEach(message => {

				alert.appendChild(new Element('p', { html: message }))

			})

			this.insertAlert(alert)
		},

		insertAlert: function(alert)
		{
			var el = this.element

			if (alert.classList.contains('alert-success') && this.options.replaceOnSuccess)
			{
				alert.querySelector('[data-dismiss="alert"]').remove()
				alert.classList.add('dismissible')
				alert.inject(el, 'before')

				el.classList.add('hidden')
			}
			else if (!alert.parentNode)
			{
				alert.inject(el, 'top')
			}
		},

		/**
		 * Clears dismissible alerts and removes `.has-danger`.
		 */
		clearAlert: function()
		{
			const form = this.element

			form.querySelectorAll('.alert.dismissible').forEach(alert => {

				alert.remove()

			})

			form.querySelectorAll('.has-danger').forEach(control => {

				control.classList.remove('has-danger')

			})
		},

		/**
		 * Add a control error.
		 *
		 * @param {string} name Name of the control
		 */
		addError: function (name) {

			let control = this.element.elements[name]

			if (!control) return

			let group = control.closest('.form-group')

			if (group)
			{
				group.classList.add('has-danger')
			}

			if (typeOf(control) == 'collection')
			{
				let parent = control[0].closest('.radio-group')

				if (parent)
				{
					parent.classList.add('has-danger')
				}
				else
				{
					control.forEach(checkbox => {

						checkbox.classList.add('has-danger')

					})
				}

				return
			}

			control.classList.add('has-danger')

		},

		submit: function()
		{
			this.notify(new SubmitEvent)
			this.getOperation().send(this.element)
		},

		getOperation: function()
		{
			if (this.operation)
			{
				return this.operation
			}

			return this.operation = new Request.JSON({

				url: this.options.url || this.element.action,
				method: this.element.getAttribute('method') || 'GET',

				onRequest: this.request.bind(this),
				onComplete: this.complete.bind(this),
				onSuccess: this.success.bind(this),
				onFailure: this.failure.bind(this)

			})
		},

		/**
		 * @fires Brickrouge.Form#request
		 */
		request: function()
		{
			this.clearAlert()
			this.notify(new RequestEvent)
		},

		/**
		 * @fires Brickrouge.Form#complete
		 */
		complete: function()
		{
			this.notify(new CompleteEvent)
		},

		/**
		 * @fires Brickrouge.Form#success
		 */
		success: function(response)
		{
			if (response.message)
			{
				this.alert(response.message, 'success')
			}

			this.notify(new SuccessEvent(response)).notify(new CompleteEvent)
		},

		/**
		 * @fires Brickrouge.Form#failure
		 */
		failure: function(xhr)
		{
			var response = {}

			try
			{
				response = JSON.decode(xhr.responseText)

				if (response.errors)
				{
					this.alert(response.errors, 'danger')
				}

				if (response.exception)
				{
					alert(response.exception)
				}
			}
			catch (e)
			{
				if (console)
				{
					console.error(e)
				}

				alert(xhr.statusText)
			}

			this.notify(new FailureEvent(xhr, response))
		}
	})

	let forms = []

	/**
	 * Retrieve the Brickrouge form associated with an element.
	 *
	 * @param {Element} element
	 *
	 * @returns {Form}
	 */
	function from(element)
	{
		let uid = Brickrouge.uidOf(element)

		if (uid in forms)
		{
			return forms[uid]
		}

		throw new Error("No Brickrouge form is associated with this element")
	}

	Object.defineProperties(Form, {

		EVENT_SUBMIT:   { value: SubmitEvent },
		EVENT_REQUEST:  { value: RequestEvent },
		EVENT_SUCCESS:  { value: SuccessEvent },
		EVENT_FAILURE:  { value: FailureEvent },
		EVENT_COMPLETE: { value: CompleteEvent },
		from:           { value: from }

	})

	return Brickrouge.Form = Form

})
<commit_msg>Use class static rather than defineProperties<commit_after>/*
 * This file is part of the Brickrouge package.
 *
 * (c) Olivier Laviale <olivier.laviale@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

define('Brickrouge.Form', [

	'./Core',
	'olvlvl-subject'

],

/**
 * @param {Brickrouge} Brickrouge
 * @param {Brickrouge.Subject} Subject
 *
 * @returns {Brickrouge.Form}
 */
(Brickrouge, Subject) => {

	"use strict";

	/**
	 * Key for generic errors
	 */
	const GENERIC = '__generic__'

	/**
	 * Fired before the form is submitted.
	 *
	 * @event Brickrouge.Form#submit
	 */
	const SubmitEvent = Subject.createEvent(function () {

	})

	/**
	 * Fired before the XHR is sent
	 *
	 * @event Brickrouge.Form#request
	 */
	const RequestEvent = Subject.createEvent(function () {

	})

	/**
	 * Fired when the request is successful
	 *
	 * @param {Object} response
	 *
	 * @event Brickrouge.Form#success
	 * @property {Object} response
	 */
	const SuccessEvent = Subject.createEvent(function (response) {

		this.response = response

	})

	/**
	 * Fired when the request failed
	 *
	 * @param {XMLHttpRequest} xhr
	 * @param {Object} response
	 *
	 * @event Brickrouge.Form#failure
	 * @property {XMLHttpRequest} xhr
	 * @property {Object} response
	 */
	const FailureEvent = Subject.createEvent(function (xhr, response) {

		this.xhr = xhr
		this.response = response

	})

	/**
	 * Fired when the request is complete
	 *
	 * @event Brickrouge.Form#complete
	 */
	const CompleteEvent = Subject.createEvent(function () {

	})

	/**
	 * @type {Brickrouge.Form.Options|*}
	 */
	const DEFAULT_OPTIONS = {

		url: null,
		useXHR: false,
		replaceOnSuccess: false

	}

	/**
	 * Forms created.
	 *
	 * @type {Array<int, Brickrouge.Form>}
	 */
	const forms = []

	/**
	 * Support for asynchronous forms.
	 *
	 * @property {HTMLFormElement} element
	 */
	class Form extends Brickrouge.mixin(Object, Subject) {

		/**
		 * @returns {Brickrouge.Form.SubmitEvent}
		 * @constructor
		 */
		static get SubmitEvent()
		{
			return SubmitEvent
		}

		/**
		 * @returns {Brickrouge.Form.RequestEvent}
		 * @constructor
		 */
		static get RequestEvent()
		{
			return RequestEvent
		}

		/**
		 * @returns {Brickrouge.Form.SuccessEvent}
		 * @constructor
		 */
		static get SuccessEvent()
		{
			return SuccessEvent
		}

		/**
		 * @returns {Brickrouge.Form.FailureEvent}
		 * @constructor
		 */
		static get FailureEvent()
		{
			return FailureEvent
		}

		/**
		 * @returns {Brickrouge.Form.CompleteEvent}
		 * @constructor
		 */
		static get CompleteEvent()
		{
			return CompleteEvent
		}

		/**
		 * Retrieve the Brickrouge form associated with an element.
		 *
		 * @param {HTMLFormElement} element
		 *
		 * @returns {Brickrouge.Form}
		 */
		static from(element)
		{
			const uid = Brickrouge.uidOf(element)

			if (uid in forms)
			{
				return forms[uid]
			}

			throw new Error("No Brickrouge form is associated with this element")
		}

		/**
		 * @param {HTMLFormElement} element
		 * @param {Brickrouge.Form.Options} options
		 */
		constructor (element, options)
		{
			super()

			this.element = element
			this.options = Object.assign({}, DEFAULT_OPTIONS, options)

			forms[Brickrouge.uidOf(element)] = this

			element.addEventListener('submit', ev => {

				if (!this.isProcessingSubmit) {
					return
				}

				ev.preventDefault()

				this.submit()

			})
		}

		/**
		 * Determine whether the submit event should be processed by the class.
		 *
		 * @returns bool
		 */
		get isProcessingSubmit()
		{
			let options = this.options

			return options.useXHR
			|| options.onRequest
			|| options.onComplete
			|| options.onFailure
			|| options.onSuccess
			|| options.replaceOnSuccess
		}

		/**
		 * @param {string|Object} messages
		 * @param {string} type
		 */
		alert(messages, type)
		{
			let original = messages
			let alert = this.element.querySelector('.alert-' + type)
			|| new Element('.alert.alert-' + type + '.dismissible').adopt(new Element('button.close[type="button"][data-dismiss="alert"]', { html: '×' }))

			if (typeOf(messages) == 'string')
			{
				messages = [ messages ]
			}
			else if (typeOf(messages) == 'object')
			{
				messages = []

				Object.forEach(original, (message, id) => {

					if (id !== GENERIC)
					{
						this.addError(id)
					}

					if (!message || message === true)
					{
						return
					}

					messages.push(message)

				})
			}

			if (!messages.length)
			{
				return
			}

			messages.forEach(message => {

				alert.appendChild(new Element('p', { html: message }))

			})

			this.insertAlert(alert)
		}

		/**
		 * @param {Element} alert
		 */
		insertAlert(alert)
		{
			const el = this.element

			if (alert.classList.contains('alert-success') && this.options.replaceOnSuccess)
			{
				alert.querySelector('[data-dismiss="alert"]').remove()
				alert.classList.add('dismissible')
				alert.inject(el, 'before')

				el.classList.add('hidden')
			}
			else if (!alert.parentNode)
			{
				alert.inject(el, 'top')
			}
		}

		/**
		 * Clears dismissible alerts and removes `.has-danger`.
		 */
		clearAlert()
		{
			const form = this.element

			form.querySelectorAll('.alert.dismissible').forEach(alert => {

				alert.remove()

			})

			form.querySelectorAll('.has-danger').forEach(control => {

				control.classList.remove('has-danger')

			})
		}

		/**
		 * Add a control error.
		 *
		 * @param {string} name Name of the control
		 */
		addError(name)
		{
			const control = this.element.elements[name]

			if (!control) return

			const group = control.closest('.form-group')

			if (group)
			{
				group.classList.add('has-danger')
			}

			if (typeOf(control) == 'collection')
			{
				let parent = control[0].closest('.radio-group')

				if (parent)
				{
					parent.classList.add('has-danger')
				}
				else
				{
					control.forEach(checkbox => {

						checkbox.classList.add('has-danger')

					})
				}

				return
			}

			control.classList.add('has-danger')
		}

		submit()
		{
			this.notify(new SubmitEvent)
			this.getOperation().send(this.element)
		}

		getOperation()
		{
			if (this.operation)
			{
				return this.operation
			}

			return this.operation = new Request.JSON({

				url: this.options.url || this.element.action,
				method: this.element.getAttribute('method') || 'GET',

				onRequest: this.request.bind(this),
				onComplete: this.complete.bind(this),
				onSuccess: this.success.bind(this),
				onFailure: this.failure.bind(this)

			})
		}

		/**
		 * @fires Brickrouge.Form#request
		 */
		request()
		{
			this.clearAlert()
			this.notify(new RequestEvent)
		}

		/**
		 * @fires Brickrouge.Form#complete
		 */
		complete()
		{
			this.notify(new CompleteEvent)
		}

		/**
		 * @fires Brickrouge.Form#success
		 */
		success(response)
		{
			if (response.message)
			{
				this.alert(response.message, 'success')
			}

			this.notify(new SuccessEvent(response)).notify(new CompleteEvent)
		}

		/**
		 * @fires Brickrouge.Form#failure
		 */
		failure(xhr)
		{
			var response = {}

			try
			{
				response = JSON.decode(xhr.responseText)

				if (response.errors)
				{
					this.alert(response.errors, 'danger')
				}

				if (response.exception)
				{
					alert(response.exception)
				}
			}
			catch (e)
			{
				if (console)
				{
					console.error(e)
				}

				alert(xhr.statusText)
			}

			this.notify(new FailureEvent(xhr, response))
		}

		/**
		 * @param {Function} callback
		 */
		observeSubmit(callback)
		{
			this.observe(SubmitEvent, callback)
		}

		/**
		 * @param {Function} callback
		 */
		observeRequest(callback)
		{
			this.observe(RequestEvent, callback)
		}

		/**
		 * @param {Function} callback
		 */
		observeSuccess(callback)
		{
			this.observe(SuccessEvent, callback)
		}

		/**
		 * @param {Function} callback
		 */
		observeFailure(callback)
		{
			this.observe(FailureEvent, callback)
		}

		/**
		 * @param {Function} callback
		 */
		observeComplete(callback)
		{
			this.observe(CompleteEvent, callback)
		}
	}

	return Brickrouge.Form = Form

})
<|endoftext|>


<commit_before>/* globals require describe it beforeEach afterEach*/

const chai = require("chai");
const sinonModule = require("sinon");

let expect = chai.expect;

describe("Test environment", () => {
    it("Expect to pass", ()=>{
        expect(1).to.equal(1);
    });

    it("Expect to fail", ()=>{
        expect(1).to.equal(2);
    });
});<commit_msg>Add initial variant of pet-data tests, still working on them.<commit_after>/* globals require describe it beforeEach afterEach*/

const chai = require("chai");
const sinonModule = require("sinon");

let expect = chai.expect;

//describe("Test environment", () => {
//    it("Expect to pass", ()=>{
//        expect(1).to.equal(1);
//    });
//
//    it("Expect to fail", ()=>{
//        expect(1).to.equal(2);
//    });
//});

describe("Test pet data", () => {
    let sinon;
    beforeEach(() => {
        sinon = sinonModule.sandbox.create();
    });

    class Pet {
        constructor(properties) {
            this.name = properties.name;
            this.weight = properties.weight;
            this.sex = properties.sex;
            this.breed = properties.breed;
            this.species = properties.species;
            this.age = properties.age;
        }

        save() { }
        count() { }

        static find() { return this; }
        static findOne() { return this; }
        static findOneAndUpdate() { return this; }

        static select() { return this; }
        static exec() { return this; }
        static sort() { return this; }
        static limit() { return this; }
        static where() { return this; }
        static equals() { return this; }
        static skip() { return this; }
    }

    let data=require("./../../server/data/pet-data")({Pet});

    describe("getById(id)", () => {
        let existingPetId = 1;

        let pet = {
            _id: existingPetId,
            name: "Tobbi"
        };

        let pets = [pet];

        beforeEach(() => {
            sinon.stub(Pet, "findOne", (query, callback) => {
                let id = query._id;
                let foundPet = pets.find(p => p._id === id);
                callback(null, foundPet);
            });
        });

        afterEach(() => {
            Pet.findOne.restore();
        });

        it("Expect to return the pet", done => {
            data.getById(existingPetId)
                .then((actualPet => {
                    expect(actualPet).to.equal(pet[0]);
                    done();
                }));
        });

        it("Expect to return null, when no pet with the id", done => {
            data.getById(138)
                .then((actualPet => {
                    expect(actualPet).to.be.null;
                    done();
                }));
        });
    });

    describe("getPets()", () => {
        it("Expect to return 2 pet", done => {
            //arrange
            let pets = ["Tobbi", "Kitty"];
            sinon.stub(Pet, "find", (_, cb) => {
                cb(null, pets);
            });

            //act
            data.getPets()
                .then(actualPets => {
                    //assert
                    expect(actualPets).to.eql(pets);
                    done();
                })
                .catch(err => {
                    console.log(err);
                });
        });
    });

    describe("getPets()", () => {
        it("Expect all chained methods to be called - find().select().exec()", done => {
            let findSpy = sinon.spy(Pet, "find");
            let selectSpy = sinon.spy(Pet, "select");
            let execSpy = sinon.spy(Pet, "exec");

            data.getPets();

            expect(findSpy.calledOnce).to.be.true;
            expect(selectSpy.calledOnce).to.be.true;
            expect(execSpy.calledOnce).to.be.true;

            done();

            findSpy.restore();
            selectSpy.restore();
            execSpy.restore();
        });
    });

    describe("create(data)", () => {
        afterEach(() => {
            sinon.restore();
        });

        it("Expect to save the pet", done => {
            sinon.stub(Pet.prototype, "save", cb => {
                cb(null);
            });

            let name= "Tobbi";
            data.create(name, "0.33", "male", "dogs", "Akita", 9)
                .then(actualPet => {
                    expect(actualPet.name).to.equal(name);
                    done();
                });
        });

        it("Expect to fail, when name is empty", done => {
            sinon.stub(Pet.prototype, "save", cb => {
                cb(null);
            });

            let name = "";
            data.create(name, "0.33", "male", "dogs", "Akita", 9)
                .catch(err => {
                    expect(err).not.to.be.null;
                    done();
                });
        });

        //other properties here
    });
});<|endoftext|>


<commit_before>VICA.ConfigHandler = {
  getValue : function(key){
    var env;
    switch( window.location.hostname ){
      case "localhost":
      case "127.0.0.1":
        env = 'Local';
        break;
      case "http://15.185.109.31/":
      case "15.185.109.31":
        env = 'Dev';
        break;
      case "yourdomain.com":
        env = 'Staging';
        break;
      default:
        throw('Unknown environment: ' + window.location.hostname );
    }
    return VICA.Config[env][key];
  }
};

<commit_msg>upload code<commit_after>VICA.ConfigHandler = {
  getValue : function(key){
    var env;
    switch( window.location.hostname ){
      case "localhost":
      case "127.0.0.1":
        env = 'Local';
        break;
      case "http://15.185.109.31/":
      case "15.185.109.31":
        env = 'Dev';
        break;
      case "http://15.185.160.200/":
      case "15.185.160.200":
        env = 'Dev';
        break;
      case "yourdomain.com":
        env = 'Staging';
        break;
      default:
        throw('Unknown environment: ' + window.location.hostname );
    }
    return VICA.Config[env][key];
  }
};

<|endoftext|>


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

var entities = require('./Entities.js')

/*
 * General game handler
 */
function Game(client1, client2) {
    this.players = [];
    this.balls = [];
    this.powerups = [];

    this.current_tick = 0;

    this.init(client1, client2);

    this.ended = false;
}

Game.prototype.start = function() {
    winston.info(
        'Starting new game with ' +
        this.players.length +
        ' players!'
    );

    // say hello
    for(var i in this.players) {
        var cur = this.players[i];

        for(var j in this.players) {
            if(i != j) {
                var other = this.players[i];

                other.connection.emit('ready', {name: other.name})
            }
        }
    }

    // run the game
    var last_time = Date.now();
    while(true) {
        cur_time = Date.now();
        this.update(cur_time - last_time);
        last_time = cur_time;
    }
}

Game.prototype.end = function(msg) {
    if(this.ended)
        return;
    this.ended = true;

    winston.info(
        'Ending game [' +
        msg +
        ']'
    );

}

Game.prototype.init = function(client1, client2) {
    // add two players to the game
    var p1 = new entities.Player(
        client1.name,
        client1.conn,
        [[0, 0], [10, 480]]
    )
    var p2 = new entities.Player(
        client2.name,
        client2.conn,
        [[640-10, 0], [10, 480]]
    )

    this.players.push(p1);
    this.players.push(p2);

    // add one ball
    var ball = new entities.Ball(10, 10, 1, 1);

    this.balls.push(ball);
}

Game.prototype.update = function(dt) {
    // move all balls
    for(var i in this.balls) {
        cur = this.balls[i];

        cur.move(dt);
    }
}

/*
 * Exports
 */
module.exports.Game = Game;<commit_msg>Changed ready event<commit_after>var winston = require('winston');

var entities = require('./Entities.js')

/*
 * General game handler
 */
function Game(client1, client2) {
    this.players = [];
    this.balls = [];
    this.powerups = [];

    this.current_tick = 0;

    this.init(client1, client2);

    this.ended = false;
}

Game.prototype.start = function() {
    winston.info(
        'Starting new game with ' +
        this.players.length +
        ' players!'
    );

    // say hello
    for(var i in this.players) {
        var cur = this.players[i];

        var names = [];
        for(var j in this.players) {
            if(i != j) {
                var other = this.players[j];
                names.push(other.name);
            }
        }
        cur.connection.emit('ready', {names: names});
    }

    // run the game
    var last_time = Date.now();
    while(true) {
        cur_time = Date.now();
        this.update(cur_time - last_time);
        last_time = cur_time;
    }
}

Game.prototype.end = function(msg) {
    if(this.ended)
        return;
    this.ended = true;

    winston.info(
        'Ending game [' +
        msg +
        ']'
    );

}

Game.prototype.init = function(client1, client2) {
    // add two players to the game
    var p1 = new entities.Player(
        client1.name,
        client1.conn,
        [[0, 0], [10, 480]]
    )
    var p2 = new entities.Player(
        client2.name,
        client2.conn,
        [[640-10, 0], [10, 480]]
    )

    this.players.push(p1);
    this.players.push(p2);

    // add one ball
    var ball = new entities.Ball(10, 10, 1, 1);

    this.balls.push(ball);
}

Game.prototype.update = function(dt) {
    // move all balls
    for(var i in this.balls) {
        cur = this.balls[i];

        cur.move(dt);
    }

    // move snakes
    for(var i in this.snakes) {
        cur = this.players[i].snake;

        cur.move(dt);
    }
}

/*
 * Exports
 */
module.exports.Game = Game;<|endoftext|>


<commit_before>'use strict';

require('should');

describe('setTempBasal', function ( ) {
    var determinebasal = require('../bin/oref0-determine-basal')();

   //function setTempBasal(rate, duration, profile, requestedTemp)

    var profile = { "current_basal":0.8,"max_daily_basal":1.3,"max_basal":3.0 };
    var rt = {};
    it('should cancel temp', function () {
        var requestedTemp = determinebasal.setTempBasal(0, 0, profile, rt);
        requestedTemp.rate.should.equal(0);
        requestedTemp.duration.should.equal(0);
    });

    it('should set zero temp', function () {
        var requestedTemp = determinebasal.setTempBasal(0, 30, profile, rt);
        requestedTemp.rate.should.equal(0);
        requestedTemp.duration.should.equal(30);
    });

    it('should set high temp', function () {
        var requestedTemp = determinebasal.setTempBasal(2, 30, profile, rt);
        requestedTemp.rate.should.equal(2);
        requestedTemp.duration.should.equal(30);
    });

    it('should limit high temp to max_basal', function () {
        var requestedTemp = determinebasal.setTempBasal(4, 30, profile, rt);
        requestedTemp.rate.should.equal(3);
        requestedTemp.duration.should.equal(30);
    });

    it('should set current_basal as temp on requestedTemp if offline', function () {
        var requestedTemp = determinebasal.setTempBasal(0, 0, profile, rt, "Offline");
        requestedTemp.rate.should.equal(0.8);
        requestedTemp.duration.should.equal(30);
    });

    it('should limit high temp to 3 * max_daily_basal', function () {
        var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":10.0 };
        var requestedTemp = determinebasal.setTempBasal(6, 30, profile, rt);
        requestedTemp.rate.should.equal(3.9);
        requestedTemp.duration.should.equal(30);
    });

    it('should limit high temp to 4 * current_basal', function () {
        var profile = { "current_basal":0.7,"max_daily_basal":1.3,"max_basal":10.0 };
        var requestedTemp = determinebasal.setTempBasal(6, 30, profile, rt);
        requestedTemp.rate.should.equal(2.8);
        requestedTemp.duration.should.equal(30);
    });

});

describe('determine-basal', function ( ) {
    var determinebasal = require('../bin/oref0-determine-basal')();

   //function determine_basal(glucose_status, currenttemp, iob_data, profile)

    // standard initial conditions for all determine-basal test cases unless overridden
    var glucose_status = {"delta":0,"glucose":115,"avgdelta":0};
    var currenttemp = {"duration":0,"rate":0,"temp":"absolute"};
    var iob_data = {"iob":0,"activity":0,"bolusiob":0};
    var profile = {"max_iob":1.5,"dia":3,"type":"current","current_basal":0.9,"max_daily_basal":1.3,"max_basal":3.5,"max_bg":120,"min_bg":110,"sens":40};

    it('should do nothing when in range w/o IOB', function () {
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        (typeof output.rate).should.equal('undefined');
        (typeof output.duration).should.equal('undefined');
        output.reason.should.match(/in range/);
    });

    it('should set current temp when in range w/o IOB with Offline set', function () {
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile, 'Offline');
        output.rate.should.equal(0.9);
        output.duration.should.equal(30);
        output.reason.should.match(/in range.*setting current basal/);
    });

    // low glucose suspend test cases
    it('should temp to 0 when low w/o IOB', function () {
        var glucose_status = {"delta":-5,"glucose":75,"avgdelta":-5};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(30);
        output.reason.should.match(/BG 75<80/);
    });

    it('should do nothing when low and rising w/o IOB', function () {
        var glucose_status = {"delta":5,"glucose":75,"avgdelta":5};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        (typeof output.rate).should.equal('undefined');
        (typeof output.duration).should.equal('undefined');
        output.reason.should.match(/75<80.*no high-temp/);
    });

    it('should do nothing when low and rising w/ negative IOB', function () {
        var glucose_status = {"delta":5,"glucose":75,"avgdelta":5};
        var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        (typeof output.rate).should.equal('undefined');
        (typeof output.duration).should.equal('undefined');
        output.reason.should.match(/75<80.*no high-temp/);
    });

    it('should do nothing on uptick even if avgdelta is still negative', function () {
        var glucose_status = {"delta":1,"glucose":75,"avgdelta":-2};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        (typeof output.rate).should.equal('undefined');
        (typeof output.duration).should.equal('undefined');
        output.reason.should.match(/BG 75<80/);
    });

    it('should temp to 0 when rising slower than BGI', function () {
        var glucose_status = {"delta":1,"glucose":75,"avgdelta":1};
        var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(30);
        output.reason.should.match(/BG 75<80/);
    });

    it('should temp to 0 when low and falling, regardless of BGI', function () {
        var glucose_status = {"delta":-1,"glucose":75,"avgdelta":-1};
        var iob_data = {"iob":1,"activity":0.01,"bolusiob":0.5};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(30);
        output.reason.should.match(/BG 75<80/);
    });

    it('should cancel high-temp when low and rising faster than BGI', function () {
        var currenttemp = {"duration":20,"rate":2,"temp":"absolute"};
        var glucose_status = {"delta":5,"glucose":75,"avgdelta":5};
        var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(0);
        output.reason.should.match(/BG 75<80/);
    });

    it('should high-temp when > 80-ish and rising w/ lots of negative IOB', function () {
        var glucose_status = {"delta":5,"glucose":85,"avgdelta":5};
        var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.be.above(1);
        output.duration.should.equal(30);
        output.reason.should.match(/no temp, setting/);
    });

    // low eventualBG

    it('should low-temp when eventualBG < min_bg', function () {
        var glucose_status = {"delta":-3,"glucose":110,"avgdelta":-1};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.be.below(0.8);
        output.duration.should.equal(30);
        output.reason.should.match(/Eventual BG .*<110/);
    });

    it('should cancel low-temp when lowish and rising faster than BGI', function () {
        var currenttemp = {"duration":20,"rate":0.5,"temp":"absolute"};
        var glucose_status = {"delta":3,"glucose":85,"avgdelta":3};
        var iob_data = {"iob":-0.5,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(0);
        output.reason.should.match(/Eventual BG.*<.*but Delta.*> BGI.*; cancel/);
    });

    it('should low-temp when low and rising slower than BGI', function () {
        var glucose_status = {"delta":1,"glucose":85,"avgdelta":1};
        var iob_data = {"iob":-0.5,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.be.below(0.8);
        output.duration.should.equal(30);
        output.reason.should.match(/no temp, setting/);
    });

    // high eventualBG

    it('should high-temp when eventualBG > max_bg', function () {
        var glucose_status = {"delta":+3,"glucose":120,"avgdelta":+1};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.be.above(1);
        output.duration.should.equal(30);
        output.reason.should.match(/Eventual BG .*>120/);
    });

    it('should cancel high-temp when high and falling faster than BGI', function () {
        var currenttemp = {"duration":20,"rate":2,"temp":"absolute"};
        var glucose_status = {"delta":-5,"glucose":175,"avgdelta":-5};
        var iob_data = {"iob":1,"activity":0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(0);
        output.reason.should.match(/Eventual BG.*>.*but Delta.*< BGI.*; cancel/);
    });

    it('should high-temp when high and falling slower than BGI', function () {
        var glucose_status = {"delta":-1,"glucose":175,"avgdelta":-1};
        var iob_data = {"iob":1,"activity":0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.be.above(1);
        output.duration.should.equal(30);
        output.reason.should.match(/no temp, setting/);
    });

    it('should handle NS sgv fields', function () {
      var glucose_status = determinebasal.getLastGlucose([{sgv: 100}, {sgv: 95}, {sgv: 90}, {sgv: 70}]);
      glucose_status.delta.should.equal(5);
      glucose_status.glucose.should.equal(100);
      glucose_status.avgdelta.should.equal(10);
    });

});
<commit_msg>fix test to accommodate Avg. Delta<commit_after>'use strict';

require('should');

describe('setTempBasal', function ( ) {
    var determinebasal = require('../bin/oref0-determine-basal')();

   //function setTempBasal(rate, duration, profile, requestedTemp)

    var profile = { "current_basal":0.8,"max_daily_basal":1.3,"max_basal":3.0 };
    var rt = {};
    it('should cancel temp', function () {
        var requestedTemp = determinebasal.setTempBasal(0, 0, profile, rt);
        requestedTemp.rate.should.equal(0);
        requestedTemp.duration.should.equal(0);
    });

    it('should set zero temp', function () {
        var requestedTemp = determinebasal.setTempBasal(0, 30, profile, rt);
        requestedTemp.rate.should.equal(0);
        requestedTemp.duration.should.equal(30);
    });

    it('should set high temp', function () {
        var requestedTemp = determinebasal.setTempBasal(2, 30, profile, rt);
        requestedTemp.rate.should.equal(2);
        requestedTemp.duration.should.equal(30);
    });

    it('should limit high temp to max_basal', function () {
        var requestedTemp = determinebasal.setTempBasal(4, 30, profile, rt);
        requestedTemp.rate.should.equal(3);
        requestedTemp.duration.should.equal(30);
    });

    it('should set current_basal as temp on requestedTemp if offline', function () {
        var requestedTemp = determinebasal.setTempBasal(0, 0, profile, rt, "Offline");
        requestedTemp.rate.should.equal(0.8);
        requestedTemp.duration.should.equal(30);
    });

    it('should limit high temp to 3 * max_daily_basal', function () {
        var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":10.0 };
        var requestedTemp = determinebasal.setTempBasal(6, 30, profile, rt);
        requestedTemp.rate.should.equal(3.9);
        requestedTemp.duration.should.equal(30);
    });

    it('should limit high temp to 4 * current_basal', function () {
        var profile = { "current_basal":0.7,"max_daily_basal":1.3,"max_basal":10.0 };
        var requestedTemp = determinebasal.setTempBasal(6, 30, profile, rt);
        requestedTemp.rate.should.equal(2.8);
        requestedTemp.duration.should.equal(30);
    });

});

describe('determine-basal', function ( ) {
    var determinebasal = require('../bin/oref0-determine-basal')();

   //function determine_basal(glucose_status, currenttemp, iob_data, profile)

    // standard initial conditions for all determine-basal test cases unless overridden
    var glucose_status = {"delta":0,"glucose":115,"avgdelta":0};
    var currenttemp = {"duration":0,"rate":0,"temp":"absolute"};
    var iob_data = {"iob":0,"activity":0,"bolusiob":0};
    var profile = {"max_iob":1.5,"dia":3,"type":"current","current_basal":0.9,"max_daily_basal":1.3,"max_basal":3.5,"max_bg":120,"min_bg":110,"sens":40};

    it('should do nothing when in range w/o IOB', function () {
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        (typeof output.rate).should.equal('undefined');
        (typeof output.duration).should.equal('undefined');
        output.reason.should.match(/in range/);
    });

    it('should set current temp when in range w/o IOB with Offline set', function () {
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile, 'Offline');
        output.rate.should.equal(0.9);
        output.duration.should.equal(30);
        output.reason.should.match(/in range.*setting current basal/);
    });

    // low glucose suspend test cases
    it('should temp to 0 when low w/o IOB', function () {
        var glucose_status = {"delta":-5,"glucose":75,"avgdelta":-5};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(30);
        output.reason.should.match(/BG 75<80/);
    });

    it('should do nothing when low and rising w/o IOB', function () {
        var glucose_status = {"delta":5,"glucose":75,"avgdelta":5};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        (typeof output.rate).should.equal('undefined');
        (typeof output.duration).should.equal('undefined');
        output.reason.should.match(/75<80.*no high-temp/);
    });

    it('should do nothing when low and rising w/ negative IOB', function () {
        var glucose_status = {"delta":5,"glucose":75,"avgdelta":5};
        var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        (typeof output.rate).should.equal('undefined');
        (typeof output.duration).should.equal('undefined');
        output.reason.should.match(/75<80.*no high-temp/);
    });

    it('should do nothing on uptick even if avgdelta is still negative', function () {
        var glucose_status = {"delta":1,"glucose":75,"avgdelta":-2};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        (typeof output.rate).should.equal('undefined');
        (typeof output.duration).should.equal('undefined');
        output.reason.should.match(/BG 75<80/);
    });

    it('should temp to 0 when rising slower than BGI', function () {
        var glucose_status = {"delta":1,"glucose":75,"avgdelta":1};
        var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(30);
        output.reason.should.match(/BG 75<80/);
    });

    it('should temp to 0 when low and falling, regardless of BGI', function () {
        var glucose_status = {"delta":-1,"glucose":75,"avgdelta":-1};
        var iob_data = {"iob":1,"activity":0.01,"bolusiob":0.5};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(30);
        output.reason.should.match(/BG 75<80/);
    });

    it('should cancel high-temp when low and rising faster than BGI', function () {
        var currenttemp = {"duration":20,"rate":2,"temp":"absolute"};
        var glucose_status = {"delta":5,"glucose":75,"avgdelta":5};
        var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(0);
        output.reason.should.match(/BG 75<80/);
    });

    it('should high-temp when > 80-ish and rising w/ lots of negative IOB', function () {
        var glucose_status = {"delta":5,"glucose":85,"avgdelta":5};
        var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.be.above(1);
        output.duration.should.equal(30);
        output.reason.should.match(/no temp, setting/);
    });

    // low eventualBG

    it('should low-temp when eventualBG < min_bg', function () {
        var glucose_status = {"delta":-3,"glucose":110,"avgdelta":-1};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.be.below(0.8);
        output.duration.should.equal(30);
        output.reason.should.match(/Eventual BG .*<110/);
    });

    it('should cancel low-temp when lowish and rising faster than BGI', function () {
        var currenttemp = {"duration":20,"rate":0.5,"temp":"absolute"};
        var glucose_status = {"delta":3,"glucose":85,"avgdelta":3};
        var iob_data = {"iob":-0.5,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(0);
        output.reason.should.match(/Eventual BG.*<.*but.*Delta.*> BGI.*; cancel/);
    });

    it('should low-temp when low and rising slower than BGI', function () {
        var glucose_status = {"delta":1,"glucose":85,"avgdelta":1};
        var iob_data = {"iob":-0.5,"activity":-0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.be.below(0.8);
        output.duration.should.equal(30);
        output.reason.should.match(/no temp, setting/);
    });

    // high eventualBG

    it('should high-temp when eventualBG > max_bg', function () {
        var glucose_status = {"delta":+3,"glucose":120,"avgdelta":+1};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.be.above(1);
        output.duration.should.equal(30);
        output.reason.should.match(/Eventual BG .*>120/);
    });

    it('should cancel high-temp when high and falling faster than BGI', function () {
        var currenttemp = {"duration":20,"rate":2,"temp":"absolute"};
        var glucose_status = {"delta":-5,"glucose":175,"avgdelta":-5};
        var iob_data = {"iob":1,"activity":0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.equal(0);
        output.duration.should.equal(0);
        output.reason.should.match(/Eventual BG.*>.*but.*Delta.*< BGI.*; cancel/);
    });

    it('should high-temp when high and falling slower than BGI', function () {
        var glucose_status = {"delta":-1,"glucose":175,"avgdelta":-1};
        var iob_data = {"iob":1,"activity":0.01,"bolusiob":0};
        var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile);
        output.rate.should.be.above(1);
        output.duration.should.equal(30);
        output.reason.should.match(/no temp, setting/);
    });

    it('should handle NS sgv fields', function () {
      var glucose_status = determinebasal.getLastGlucose([{sgv: 100}, {sgv: 95}, {sgv: 90}, {sgv: 70}]);
      glucose_status.delta.should.equal(5);
      glucose_status.glucose.should.equal(100);
      glucose_status.avgdelta.should.equal(10);
    });

});
<|endoftext|>