<commit_before>'use strict';

/**
 * Parses a string-based equation into a tree of operands & Equation instances.
 *
 * For example, the equation 5*3-(2+1*0.5)-1%3 becomes
 *
 *               5*3-(2+1*0.5)-1%3
 *                     |
 *                     -
 *               /     |       \
 *            5*3   2+1*0.5    1%3
 *             |       |         \
 *             -       +          %
 *           /  \    /  \        / \
 *          5    3  2  1*0.5    1   3
 *                       |
 *                       *
 *                      / \
 *                     1  0.5
 *
 * where an operand node & its immediate children (sub-equations) form an Equation.
 *
 */

var Equation = require('./Equation');
var SO = Equation.SUPPORTED_OPERANDS;

function EquationParser() {}

/**
 * Checks if the parentheses of the given equation are balanced.
 * @param  {String}  equationStr
 * @return {Boolean}             False if unbalanced, otherwise true
 */
function hasBalancedParentheses (equationStr) {

  // Check for odd number of parentheses
  /* jslint bitwise: true */
  if(equationStr.replace(/[^\(\)]/g, '').split('').length & 1) {
    return false;
  }
  /* jslint bitwise: false */

  // Check that all opening/closing parens have a matching counterpart
  var parentheses = 0, i;
  for (i = equationStr.length; i--;) {
    if (equationStr[i] === ')') { parentheses--; }
    else if (equationStr[i] === '(') { parentheses++; }
    if (parentheses === 1) { return false; }
  }

  return true;
}

/**
 * Checks if a given equation string is surrounded by parentheses
 * @param  {String}  equationStr
 * @return {Boolean}             True if the equation string is surrounded by parentheses,
 *                               false otherwise
 */
function hasSurroundingParens (equationStr) {

  var lastCharIdx = equationStr.length - 1;

  if (equationStr[0] !== '(' || equationStr[lastCharIdx] !== ')') { return false; }

  // Loop through the characters from right to left and return false if we hit
  // an opening parenthesis that matches the surrounding closing parenthesis
  // before we have reached the last character
  var parentheses = -1, i;
  for (i = lastCharIdx; i--;) {
    if (equationStr[i] === ')') { parentheses--; }
    else if (equationStr[i] === '(') { parentheses++; }
    if (parentheses === 0 && i) { return false; }
  }

  return true;
}

/**
 * Parentheses-aware String.split(). Splits the equation string by the
 * given operand. Uses String.split() if the equation contains no parentheses.
 * @param  {String} equationStr  e.g. 1+1
 * @param  {String} operand      e.g. +
 * @return {Array}               An array of subequation strings
 */
function split(equationStr, operand) {

  // Return immediately if the given operand doesn't exist
  if (equationStr.indexOf(operand) === -1) { return [ equationStr ]; }

  // Use String.split() if the equation string contains no parentheses
  if (!/\(|\)/.test(equationStr)) {
    return equationStr.split(operand);
  }

  var parentheses = 0;
  var subEquationStrings = [];
  var cBegin, cEnd, char;

  // Loop through the characters from right to left and split the
  // equation string into subequation strings if the given operand
  // is not located within parentheses
  for (cBegin = cEnd = equationStr.length; cBegin--;) {

    char = equationStr[cBegin];

    if (char === '(') { parentheses++; }
    else if (char === ')') { parentheses--; }
    else if (char === operand && !parentheses) {
      subEquationStrings.unshift(equationStr.substring(cBegin + 1, cEnd));
      cEnd = cBegin;
    }

  }

  subEquationStrings.unshift(equationStr.substring(0, cEnd));

  return subEquationStrings;
}

/**
 * Parses the string representation of an equation into an Equation instance
 * consisting of one or more Equation instances.
 *
 * @param  {String} equationStr A string representation of an equation
 * @param  {Array} operands     An array of operands to process (defaults to SO)
 * @return {Equation}           An Equation instance
 */
function parseEquation(equationStr, operands) {

  equationStr = equationStr || '0';

  // Check for a number string
  if (!isNaN(equationStr)) {
    return new Equation(equationStr);
  }

  if (hasSurroundingParens(equationStr)) {

    // Strip surrounding parentheses and call parseEquation again
    return parseEquation(equationStr.replace(/^\(|\)$/g, ''));

  }

  var subEquationStrings, subequations, operand;

  operands = operands ? operands.slice() : SO.slice();

  // Try splitting the equation into sub-equations using each of the supported operands
  while ((operand = operands.shift()) !== undefined) {
    subEquationStrings = split(equationStr, operand);
    if (subEquationStrings.length > 1) { break; }
  }

  // Unary operands are one-sided assignments so drop split's first entry (which is '')
  if (Equation.isUnaryOperand(operand)) { subEquationStrings.shift(); }

  // Iterate over the sub-equations and call parseEquation recursively
  subequations = subEquationStrings.map(function (subEquationStr) {
    return parseEquation(subEquationStr, operands);
  });

  return new Equation(subequations, operand);

}

/**
 * Validates a given equation string by checking if it
 *   - is missing operands [ e.g. 1+1(2+2) ]
 *   - uses decimal point incorrectly [ e.g. +.- or ).( ]
 *   - has unbalanced parentheses [ e.g (1+1)+(2*5-1)) ]
 *   - has two or more consecutive operands [ e.g. 1++1 ]
 *   - contains characters that are not numbers, decimal points, parentheses or operands
 *
 * @param  {String} equationStr
 * @throws {Error}  Throws an Error if the input is invalid
 */
function validateEquation(equationStr) {

  var invalidCharsRegexStr = '[^\\d\\.\\(\\)\\' + SO.ternary.join('\\') + SO.unary.join('') + ']';
  var consecutiveOperandsRegexStr = '[\\' + SO.ternary.join('\\') + ']{2,}';
  var invalidCharsRegex = new RegExp(invalidCharsRegexStr);
  var consecutiveOperandsRegex = new RegExp(consecutiveOperandsRegexStr);

  if (/\)\(/.test(equationStr)) {
    throw new Error('Missing an operand.');
  }

  if (/\D\.\D/.test(equationStr)) {
    throw new Error('Invalid use of the decimal point.');
  }

  if (!hasBalancedParentheses(equationStr)) {
    throw new Error('Parentheses are not in balance.');
  }

  if (consecutiveOperandsRegex.test(equationStr)) {
    throw new Error('Consecutive ternary operands detected.');
  }

  if (invalidCharsRegex.test(equationStr)) {
    throw new Error('The equation contains invalid characters. Supported operands: ' + SO);
  }

}

/**
 * Sanitizes/normalizes the equation string:
 *   - convert to lowercase
 *   - strip whitespace
 *   - strip repeating operands
 *   - strip leading/trailing operands
 *   - pad decimal points with leading/trailing zeros
 *
 * @param  {String} equationStr The equation
 * @return {String}             A sanitized equation
 *
 * @todo  Perf optimize
 */
function sanitizeEquation(equationStr) {

  var repeatingCharsRegex = new RegExp('([\\.\\' + SO.ternary.join('\\') + SO.unary.join('') + '])(?=\\1+)', 'g');
  var trailingLeadingOperands = new RegExp('^[\\' + SO.ternary.join('\\') + ']+|[\\' + SO.ternary.join('\\') + SO.unary.join('') + ']+$', 'g');

  return equationStr
    .toLowerCase()
    // Strip whitespace
    .replace(/\s+/g, '')
    // Strip repeating operands and decimal points (e.g. 1+++2 => 1+2)
    .replace(repeatingCharsRegex, '')
    // Strip leading/trailing ternary and unary operands (+1+2+abs => 1+2)
    .replace(trailingLeadingOperands, '')
    // Pad decimal points with zeros (leading & trailing)
    .replace(/(\D)\.(\d)/g, function (m, p1, p2) { return p1 + '0.' + p2; })
    .replace(/(\d)\.(\D)/g, function (m, p1, p2) { return p1 + '.0' + p2; });

}

/**
 * An overload of parseEquation().
 * Sanitizes & validates the input before passing it to parseEquation().
 *
 * @param  {String}  equationStr             A string representation of an equation
 * @param  {Object}  [options]
 * @param  {Boolean} [options.skipSanitize]  Boolean to control input sanitization (default: false)
 * @param  {Boolean} [options.skipValidate]  Boolean to control input validation (default: false)
 * @return {Equation}                        An Equation instance
 *
 * @see  parseEquation()
 */
EquationParser.prototype.parseEquation = function (equationStr, options) {

  options = options || {};

  // Alias unary operands for faster matching: sqrt => s, abs => a
  equationStr = equationStr.replace(/(s)qrt|(a)bs/gi, '$1$2');

  // Sanitize
  if (!options.skipSanitize) { equationStr = sanitizeEquation(equationStr); }

  // Validate
  if (!options.skipValidate) { validateEquation(equationStr); }

  // Parse
  return parseEquation(equationStr);

};

module.exports = EquationParser;
<commit_msg>Perf: use charCodeAt() where appropriate<commit_after>'use strict';

/**
 * Parses a string-based equation into a tree of operands & Equation instances.
 *
 * For example, the equation 5*3-(2+1*0.5)-1%3 becomes
 *
 *               5*3-(2+1*0.5)-1%3
 *                     |
 *                     -
 *               /     |       \
 *            5*3   2+1*0.5    1%3
 *             |       |         \
 *             -       +          %
 *           /  \    /  \        / \
 *          5    3  2  1*0.5    1   3
 *                       |
 *                       *
 *                      / \
 *                     1  0.5
 *
 * where an operand node & its immediate children (sub-equations) form an Equation.
 *
 */

var Equation = require('./Equation');
var SO = Equation.SUPPORTED_OPERANDS;
var CHAR_OPENING_PARENS = 40;
var CHAR_CLOSING_PARENS = 41;

function EquationParser() {}

/**
 * Checks if the parentheses of the given equation are balanced.
 * @param  {String}  equationStr
 * @return {Boolean}             False if unbalanced, otherwise true
 */
function hasBalancedParentheses (equationStr) {

  // Check for odd number of parentheses
  /* jslint bitwise: true */
  if(equationStr.replace(/[^\(\)]/g, '').split('').length & 1) {
    return false;
  }
  /* jslint bitwise: false */

  // Check that all opening/closing parens have a matching counterpart
  var parentheses = 0, i;
  for (i = equationStr.length; i--;) {
    if (equationStr.charCodeAt(i) === CHAR_CLOSING_PARENS) { parentheses--; }
    else if (equationStr.charCodeAt(i) === CHAR_OPENING_PARENS) { parentheses++; }
    if (parentheses === 1) { return false; }
  }

  return true;
}

/**
 * Checks if a given equation string is surrounded by parentheses
 * @param  {String}  equationStr
 * @return {Boolean}             True if the equation string is surrounded by parentheses,
 *                               false otherwise
 */
function hasSurroundingParens (equationStr) {

  var lastCharIdx = equationStr.length - 1;

  if (
    equationStr.charCodeAt(0) !== CHAR_OPENING_PARENS ||
    equationStr.charCodeAt(lastCharIdx) !== CHAR_CLOSING_PARENS
  ) { return false; }

  // Loop through the characters from right to left and return false if we hit
  // an opening parenthesis that matches the surrounding closing parenthesis
  // before we have reached the last character
  var parentheses = -1, i;
  for (i = lastCharIdx; i--;) {
    if (equationStr.charCodeAt(i) === CHAR_CLOSING_PARENS) { parentheses--; }
    else if (equationStr.charCodeAt(i) === CHAR_OPENING_PARENS) { parentheses++; }
    if (parentheses === 0 && i) { return false; }
  }

  return true;
}

/**
 * Parentheses-aware String.split(). Splits the equation string by the
 * given operand. Uses String.split() if the equation contains no parentheses.
 * @param  {String} equationStr  e.g. 1+1
 * @param  {String} operand      e.g. +
 * @return {Array}               An array of subequation strings
 */
function split(equationStr, operand) {

  // Return immediately if the given operand doesn't exist
  if (equationStr.indexOf(operand) === -1) { return [ equationStr ]; }

  // Use String.split() if the equation string contains no parentheses
  if (!/\(|\)/.test(equationStr)) {
    return equationStr.split(operand);
  }

  var parentheses = 0;
  var subEquationStrings = [];
  var cBegin, cEnd, char, charCode;

  // Loop through the characters from right to left and split the
  // equation string into subequation strings if the given operand
  // is not located within parentheses
  for (cBegin = cEnd = equationStr.length; cBegin--;) {

    char = equationStr[cBegin]
    charCode = char.charCodeAt(0);

    if (charCode === CHAR_OPENING_PARENS) { parentheses++; }
    else if (charCode === CHAR_CLOSING_PARENS) { parentheses--; }
    else if (char === operand && !parentheses) {
      subEquationStrings.unshift(equationStr.substring(cBegin + 1, cEnd));
      cEnd = cBegin;
    }

  }

  subEquationStrings.unshift(equationStr.substring(0, cEnd));

  return subEquationStrings;
}

/**
 * Parses the string representation of an equation into an Equation instance
 * consisting of one or more Equation instances.
 *
 * @param  {String} equationStr A string representation of an equation
 * @param  {Array} operands     An array of operands to process (defaults to SO)
 * @return {Equation}           An Equation instance
 */
function parseEquation(equationStr, operands) {

  equationStr = equationStr || '0';

  // Check for a number string
  if (!isNaN(equationStr)) {
    return new Equation(equationStr);
  }

  if (hasSurroundingParens(equationStr)) {

    // Strip surrounding parentheses and call parseEquation again
    return parseEquation(equationStr.replace(/^\(|\)$/g, ''));

  }

  var subEquationStrings, subequations, operand;

  operands = operands ? operands.slice() : SO.slice();

  // Try splitting the equation into sub-equations using each of the supported operands
  while ((operand = operands.shift()) !== undefined) {
    subEquationStrings = split(equationStr, operand);
    if (subEquationStrings.length > 1) { break; }
  }

  // Unary operands are one-sided assignments so drop split's first entry (which is '')
  if (Equation.isUnaryOperand(operand)) { subEquationStrings.shift(); }

  // Iterate over the sub-equations and call parseEquation recursively
  subequations = subEquationStrings.map(function (subEquationStr) {
    return parseEquation(subEquationStr, operands);
  });

  return new Equation(subequations, operand);

}

/**
 * Validates a given equation string by checking if it
 *   - is missing operands [ e.g. 1+1(2+2) ]
 *   - uses decimal point incorrectly [ e.g. +.- or ).( ]
 *   - has unbalanced parentheses [ e.g (1+1)+(2*5-1)) ]
 *   - has two or more consecutive operands [ e.g. 1++1 ]
 *   - contains characters that are not numbers, decimal points, parentheses or operands
 *
 * @param  {String} equationStr
 * @throws {Error}  Throws an Error if the input is invalid
 */
function validateEquation(equationStr) {

  var invalidCharsRegexStr = '[^\\d\\.\\(\\)\\' + SO.ternary.join('\\') + SO.unary.join('') + ']';
  var consecutiveOperandsRegexStr = '[\\' + SO.ternary.join('\\') + ']{2,}';
  var invalidCharsRegex = new RegExp(invalidCharsRegexStr);
  var consecutiveOperandsRegex = new RegExp(consecutiveOperandsRegexStr);

  if (/\)\(/.test(equationStr)) {
    throw new Error('Missing an operand.');
  }

  if (/\D\.\D/.test(equationStr)) {
    throw new Error('Invalid use of the decimal point.');
  }

  if (!hasBalancedParentheses(equationStr)) {
    throw new Error('Parentheses are not in balance.');
  }

  if (consecutiveOperandsRegex.test(equationStr)) {
    throw new Error('Consecutive ternary operands detected.');
  }

  if (invalidCharsRegex.test(equationStr)) {
    throw new Error('The equation contains invalid characters. Supported operands: ' + SO);
  }

}

/**
 * Sanitizes/normalizes the equation string:
 *   - convert to lowercase
 *   - strip whitespace
 *   - strip repeating operands
 *   - strip leading/trailing operands
 *   - pad decimal points with leading/trailing zeros
 *
 * @param  {String} equationStr The equation
 * @return {String}             A sanitized equation
 *
 * @todo  Perf optimize
 */
function sanitizeEquation(equationStr) {

  var repeatingCharsRegex = new RegExp('([\\.\\' + SO.ternary.join('\\') + SO.unary.join('') + '])(?=\\1+)', 'g');
  var trailingLeadingOperands = new RegExp('^[\\' + SO.ternary.join('\\') + ']+|[\\' + SO.ternary.join('\\') + SO.unary.join('') + ']+$', 'g');

  return equationStr
    .toLowerCase()
    // Strip whitespace
    .replace(/\s+/g, '')
    // Strip repeating operands and decimal points (e.g. 1+++2 => 1+2)
    .replace(repeatingCharsRegex, '')
    // Strip leading/trailing ternary and unary operands (+1+2+abs => 1+2)
    .replace(trailingLeadingOperands, '')
    // Pad decimal points with zeros (leading & trailing)
    .replace(/(\D)\.(\d)/g, function (m, p1, p2) { return p1 + '0.' + p2; })
    .replace(/(\d)\.(\D)/g, function (m, p1, p2) { return p1 + '.0' + p2; });

}

/**
 * An overload of parseEquation().
 * Sanitizes & validates the input before passing it to parseEquation().
 *
 * @param  {String}  equationStr             A string representation of an equation
 * @param  {Object}  [options]
 * @param  {Boolean} [options.skipSanitize]  Boolean to control input sanitization (default: false)
 * @param  {Boolean} [options.skipValidate]  Boolean to control input validation (default: false)
 * @return {Equation}                        An Equation instance
 *
 * @see  parseEquation()
 */
EquationParser.prototype.parseEquation = function (equationStr, options) {

  options = options || {};

  // Alias unary operands for faster matching: sqrt => s, abs => a
  equationStr = equationStr.replace(/(s)qrt|(a)bs/gi, '$1$2');

  // Sanitize
  if (!options.skipSanitize) { equationStr = sanitizeEquation(equationStr); }

  // Validate
  if (!options.skipValidate) { validateEquation(equationStr); }

  // Parse
  return parseEquation(equationStr);

};

module.exports = EquationParser;
<|endoftext|>


<commit_before>'use strict';

/**
 * Parses a string-based equation into a tree of operands & Equation instances.
 *
 * For example, the equation 5*3-(2+1*0.5)-1%3 becomes
 *
 *               5*3-(2+1*0.5)-1%3
 *                     |
 *                     -
 *               /     |       \
 *            5*3   2+1*0.5    1%3
 *             |       |         \
 *             -       +          %
 *           /  \    /  \        / \
 *          5    3  2  1*0.5    1   3
 *                       |
 *                       *
 *                      / \
 *                     1  0.5
 *
 * where an operand node & its immediate children (sub-equations) form an Equation.
 *
 */

var Equation = require('./Equation');
var SO = Equation.SUPPORTED_OPERANDS;

function EquationParser() {}

/**
 * Checks if the parentheses of the given equation are balanced.
 * @param  {String}  equationStr
 * @return {Boolean}             False if unbalanced, otherwise true
 */
function hasBalancedParentheses (equationStr) {

  // Check for odd number of parentheses
  /* jslint bitwise: true */
  if(equationStr.replace(/[^\(\)]/g, '').split('').length & 1) {
    return false;
  }
  /* jslint bitwise: false */

  // Check that all opening/closing parens have a matching counterpart
  var parentheses = 0, i;
  for (i = equationStr.length; i--;) {
    if (equationStr[i] === ')') { parentheses--; }
    else if (equationStr[i] === '(') { parentheses++; }
    if (parentheses === 1) { return false; }
  }

  return true;
}

/**
 * Validates a given equation string by checking if it
 *   - is missing operands [ e.g. 1+1(2+2) ]
 *   - uses decimal point incorrectly [ e.g. +.- or ).( ]
 *   - has unbalanced parentheses [ e.g (1+1)+(2*5-1)) ]
 *   - has two or more consecutive operands [ e.g. 1++1 ]
 *   - contains characters that are not numbers, decimal points, parentheses or operands
 *
 * @param  {String} equationStr
 * @throws {Error}  Throws an Error if the input is invalid
 *
 * @todo  Check if parentheses are in balance
 */
function validateEquation(equationStr) {

  var invalidCharsRegexStr = '[^\\d\\.\\(\\)\\' + SO.ternary.join('\\') + SO.unary.join('') + ']';
  var consecutiveOperandsRegexStr = '[\\' + SO.ternary.join('\\') + ']{2,}';
  var invalidCharsRegex = new RegExp(invalidCharsRegexStr);
  var consecutiveOperandsRegex = new RegExp(consecutiveOperandsRegexStr);

  if (/\)\(/.test(equationStr)) {
    throw new Error('Missing an operand.');
  }

  if (/\D\.\D/.test(equationStr)) {
    throw new Error('Invalid use of the decimal point.');
  }

  if (!hasBalancedParentheses(equationStr)) {
    throw new Error('Parentheses are not in balance.');
  }

  if (consecutiveOperandsRegex.test(equationStr)) {
    throw new Error('Consecutive ternary operands detected.');
  }

  if (invalidCharsRegex.test(equationStr)) {
    throw new Error('The equation contains invalid characters. Supported operands: ' + SO);
  }

}

/**
 * Sanitizes/normalizes the equation string:
 *   - convert to lowercase
 *   - strip whitespace
 *   - strip repeating operands
 *   - pad decimal points with leading/trailing zeros
 *
 * @param  {String} equationStr The equation
 * @return {String}             A sanitized equation
 *
 * @todo  Perf optimize
 */
function sanitizeEquation(equationStr) {

  var repeatingCharsRegex = new RegExp('([\\.\\' + SO.ternary.join('\\') + SO.unary.join('') + '])(?=\\1+)', 'g');
  var trailingLeadingOperands = new RegExp('^[\\' + SO.ternary.join('\\') + ']+|[\\' + SO.ternary.join('\\') + SO.unary.join('') + ']+$', 'g');

  return equationStr
    .toLowerCase()
    // Strip whitespace
    .replace(/\s+/g, '')
    // Strip repeating operands and decimal points (e.g. 1+++2 => 1+2)
    .replace(repeatingCharsRegex, '')
    // Strip leading/trailing ternary and unary operands (+1+2+abs => 1+2)
    .replace(trailingLeadingOperands, '')
    // Pad decimal points with zeros (leading & trailing)
    .replace(/(\D)\.(\d)/g, function (m, p1, p2) { return p1 + '0.' + p2; })
    .replace(/(\d)\.(\D)/g, function (m, p1, p2) { return p1 + '.0' + p2; });

}

/**
 * Checks if a given equation string is surrounded by parentheses
 * @param  {String}  equationStr
 * @return {Boolean}             True if the equation string is surrounded by parentheses,
 *                               false otherwise
 */
function hasSurroundingParens (equationStr) {

  var length = equationStr.length;
  var parentheses = -1;
  var idx, char;

  if (equationStr[0] !== '(' || equationStr[length - 1] !== ')') { return false; }

  // Loop through the characters from right to left and return false if we hit
  // an opening parenthesis that matches the surrounding closing parenthesis
  // before we have reached the last character
  for (idx = length - 1; idx--;) {
    char = equationStr[idx];
    if (char === '(') { parentheses++; }
    else if (char === ')') { parentheses--; }
    if (!parentheses && idx) { return false; }
  }

  return true;
}

/**
 * Parentheses-aware String.split(). Splits the equation string by the
 * given operand. Uses String.split() if the equation contains no parentheses.
 * @param  {String} equationStr  e.g. 1+1
 * @param  {String} operand      e.g. +
 * @return {Array}               An array of subequation strings
 */
function split(equationStr, operand) {

  // Return immediately if the given operand doesn't exist
  if (equationStr.indexOf(operand) === -1) { return [ equationStr ]; }

  // Use String.split() if the equation string contains no parentheses
  if (!/\(|\)/.test(equationStr)) {
    return equationStr.split(operand);
  }

  var parentheses = 0;
  var subEquationStrings = [];
  var cBegin, cEnd, char;

  // Loop through the characters from right to left and split the
  // equation string into subequation strings if the given operand
  // is not located within parentheses
  for (cBegin = cEnd = equationStr.length; cBegin--;) {

    char = equationStr[cBegin];

    if (char === '(') { parentheses++; }
    else if (char === ')') { parentheses--; }
    else if (char === operand && !parentheses) {
      subEquationStrings.unshift(equationStr.substring(cBegin + 1, cEnd));
      cEnd = cBegin;
    }

  }

  subEquationStrings.unshift(equationStr.substring(0, cEnd));

  return subEquationStrings;
}

/**
 * Parses the string representation of an equation into an Equation instance
 * consisting of one or more Equation instances.
 *
 * @param  {String} equationStr A string representation of an equation
 * @param  {Array} operands     An array of operands to process (defaults to SO)
 * @return {Equation}           An Equation instance
 */
function parseEquation(equationStr, operands) {

  equationStr = equationStr || '0';

  // Check for a number string
  if (!isNaN(equationStr)) {
    return new Equation(equationStr);
  }

  if (hasSurroundingParens(equationStr)) {

    // Strip surrounding parentheses and call parseEquation again
    return parseEquation(equationStr.replace(/^\(|\)$/g, ''));

  }

  var subEquationStrings, subequations, operand;

  operands = operands ? operands.slice() : SO.slice();

  // Try splitting the equation into sub-equations using each of the supported operands
  while ((operand = operands.shift()) !== undefined) {
    subEquationStrings = split(equationStr, operand);
    if (subEquationStrings.length > 1) { break; }
  }

  // Unary operands are one-sided assignments so drop split's first entry (which is '')
  if (Equation.isUnaryOperand(operand)) { subEquationStrings.shift(); }

  // Iterate over the sub-equations and call parseEquation recursively
  subequations = subEquationStrings.map(function (subEquationStr) {
    return parseEquation(subEquationStr, operands);
  });

  return new Equation(subequations, operand);

}

/**
 * An overload of parseEquation().
 * Sanitizes & validates the input before passing it to parseEquation().
 *
 * @param  {String}  equationStr             A string representation of an equation
 * @param  {Object}  [options]
 * @param  {Boolean} [options.skipSanitize]  Boolean to control input sanitization (default: false)
 * @param  {Boolean} [options.skipValidate]  Boolean to control input validation (default: false)
 * @return {Equation}                        An Equation instance
 *
 * @see  parseEquation()
 */
EquationParser.prototype.parseEquation = function (equationStr, options) {

  options = options || {};

  // Alias unary operands for faster matching: sqrt => s, abs => a
  equationStr = equationStr.replace(/(s)qrt|(a)bs/gi, '$1$2');

  // Sanitize
  if (!options.skipSanitize) { equationStr = sanitizeEquation(equationStr); }

  // Validate
  if (!options.skipValidate) { validateEquation(equationStr); }

  // Parse
  return parseEquation(equationStr);

};

module.exports = EquationParser;
<commit_msg>EquationParser: update documentation<commit_after>'use strict';

/**
 * Parses a string-based equation into a tree of operands & Equation instances.
 *
 * For example, the equation 5*3-(2+1*0.5)-1%3 becomes
 *
 *               5*3-(2+1*0.5)-1%3
 *                     |
 *                     -
 *               /     |       \
 *            5*3   2+1*0.5    1%3
 *             |       |         \
 *             -       +          %
 *           /  \    /  \        / \
 *          5    3  2  1*0.5    1   3
 *                       |
 *                       *
 *                      / \
 *                     1  0.5
 *
 * where an operand node & its immediate children (sub-equations) form an Equation.
 *
 */

var Equation = require('./Equation');
var SO = Equation.SUPPORTED_OPERANDS;

function EquationParser() {}

/**
 * Checks if the parentheses of the given equation are balanced.
 * @param  {String}  equationStr
 * @return {Boolean}             False if unbalanced, otherwise true
 */
function hasBalancedParentheses (equationStr) {

  // Check for odd number of parentheses
  /* jslint bitwise: true */
  if(equationStr.replace(/[^\(\)]/g, '').split('').length & 1) {
    return false;
  }
  /* jslint bitwise: false */

  // Check that all opening/closing parens have a matching counterpart
  var parentheses = 0, i;
  for (i = equationStr.length; i--;) {
    if (equationStr[i] === ')') { parentheses--; }
    else if (equationStr[i] === '(') { parentheses++; }
    if (parentheses === 1) { return false; }
  }

  return true;
}

/**
 * Validates a given equation string by checking if it
 *   - is missing operands [ e.g. 1+1(2+2) ]
 *   - uses decimal point incorrectly [ e.g. +.- or ).( ]
 *   - has unbalanced parentheses [ e.g (1+1)+(2*5-1)) ]
 *   - has two or more consecutive operands [ e.g. 1++1 ]
 *   - contains characters that are not numbers, decimal points, parentheses or operands
 *
 * @param  {String} equationStr
 * @throws {Error}  Throws an Error if the input is invalid
 */
function validateEquation(equationStr) {

  var invalidCharsRegexStr = '[^\\d\\.\\(\\)\\' + SO.ternary.join('\\') + SO.unary.join('') + ']';
  var consecutiveOperandsRegexStr = '[\\' + SO.ternary.join('\\') + ']{2,}';
  var invalidCharsRegex = new RegExp(invalidCharsRegexStr);
  var consecutiveOperandsRegex = new RegExp(consecutiveOperandsRegexStr);

  if (/\)\(/.test(equationStr)) {
    throw new Error('Missing an operand.');
  }

  if (/\D\.\D/.test(equationStr)) {
    throw new Error('Invalid use of the decimal point.');
  }

  if (!hasBalancedParentheses(equationStr)) {
    throw new Error('Parentheses are not in balance.');
  }

  if (consecutiveOperandsRegex.test(equationStr)) {
    throw new Error('Consecutive ternary operands detected.');
  }

  if (invalidCharsRegex.test(equationStr)) {
    throw new Error('The equation contains invalid characters. Supported operands: ' + SO);
  }

}

/**
 * Sanitizes/normalizes the equation string:
 *   - convert to lowercase
 *   - strip whitespace
 *   - strip repeating operands
 *   - strip leading/trailing operands
 *   - pad decimal points with leading/trailing zeros
 *
 * @param  {String} equationStr The equation
 * @return {String}             A sanitized equation
 *
 * @todo  Perf optimize
 */
function sanitizeEquation(equationStr) {

  var repeatingCharsRegex = new RegExp('([\\.\\' + SO.ternary.join('\\') + SO.unary.join('') + '])(?=\\1+)', 'g');
  var trailingLeadingOperands = new RegExp('^[\\' + SO.ternary.join('\\') + ']+|[\\' + SO.ternary.join('\\') + SO.unary.join('') + ']+$', 'g');

  return equationStr
    .toLowerCase()
    // Strip whitespace
    .replace(/\s+/g, '')
    // Strip repeating operands and decimal points (e.g. 1+++2 => 1+2)
    .replace(repeatingCharsRegex, '')
    // Strip leading/trailing ternary and unary operands (+1+2+abs => 1+2)
    .replace(trailingLeadingOperands, '')
    // Pad decimal points with zeros (leading & trailing)
    .replace(/(\D)\.(\d)/g, function (m, p1, p2) { return p1 + '0.' + p2; })
    .replace(/(\d)\.(\D)/g, function (m, p1, p2) { return p1 + '.0' + p2; });

}

/**
 * Checks if a given equation string is surrounded by parentheses
 * @param  {String}  equationStr
 * @return {Boolean}             True if the equation string is surrounded by parentheses,
 *                               false otherwise
 */
function hasSurroundingParens (equationStr) {

  var length = equationStr.length;
  var parentheses = -1;
  var idx, char;

  if (equationStr[0] !== '(' || equationStr[length - 1] !== ')') { return false; }

  // Loop through the characters from right to left and return false if we hit
  // an opening parenthesis that matches the surrounding closing parenthesis
  // before we have reached the last character
  for (idx = length - 1; idx--;) {
    char = equationStr[idx];
    if (char === '(') { parentheses++; }
    else if (char === ')') { parentheses--; }
    if (!parentheses && idx) { return false; }
  }

  return true;
}

/**
 * Parentheses-aware String.split(). Splits the equation string by the
 * given operand. Uses String.split() if the equation contains no parentheses.
 * @param  {String} equationStr  e.g. 1+1
 * @param  {String} operand      e.g. +
 * @return {Array}               An array of subequation strings
 */
function split(equationStr, operand) {

  // Return immediately if the given operand doesn't exist
  if (equationStr.indexOf(operand) === -1) { return [ equationStr ]; }

  // Use String.split() if the equation string contains no parentheses
  if (!/\(|\)/.test(equationStr)) {
    return equationStr.split(operand);
  }

  var parentheses = 0;
  var subEquationStrings = [];
  var cBegin, cEnd, char;

  // Loop through the characters from right to left and split the
  // equation string into subequation strings if the given operand
  // is not located within parentheses
  for (cBegin = cEnd = equationStr.length; cBegin--;) {

    char = equationStr[cBegin];

    if (char === '(') { parentheses++; }
    else if (char === ')') { parentheses--; }
    else if (char === operand && !parentheses) {
      subEquationStrings.unshift(equationStr.substring(cBegin + 1, cEnd));
      cEnd = cBegin;
    }

  }

  subEquationStrings.unshift(equationStr.substring(0, cEnd));

  return subEquationStrings;
}

/**
 * Parses the string representation of an equation into an Equation instance
 * consisting of one or more Equation instances.
 *
 * @param  {String} equationStr A string representation of an equation
 * @param  {Array} operands     An array of operands to process (defaults to SO)
 * @return {Equation}           An Equation instance
 */
function parseEquation(equationStr, operands) {

  equationStr = equationStr || '0';

  // Check for a number string
  if (!isNaN(equationStr)) {
    return new Equation(equationStr);
  }

  if (hasSurroundingParens(equationStr)) {

    // Strip surrounding parentheses and call parseEquation again
    return parseEquation(equationStr.replace(/^\(|\)$/g, ''));

  }

  var subEquationStrings, subequations, operand;

  operands = operands ? operands.slice() : SO.slice();

  // Try splitting the equation into sub-equations using each of the supported operands
  while ((operand = operands.shift()) !== undefined) {
    subEquationStrings = split(equationStr, operand);
    if (subEquationStrings.length > 1) { break; }
  }

  // Unary operands are one-sided assignments so drop split's first entry (which is '')
  if (Equation.isUnaryOperand(operand)) { subEquationStrings.shift(); }

  // Iterate over the sub-equations and call parseEquation recursively
  subequations = subEquationStrings.map(function (subEquationStr) {
    return parseEquation(subEquationStr, operands);
  });

  return new Equation(subequations, operand);

}

/**
 * An overload of parseEquation().
 * Sanitizes & validates the input before passing it to parseEquation().
 *
 * @param  {String}  equationStr             A string representation of an equation
 * @param  {Object}  [options]
 * @param  {Boolean} [options.skipSanitize]  Boolean to control input sanitization (default: false)
 * @param  {Boolean} [options.skipValidate]  Boolean to control input validation (default: false)
 * @return {Equation}                        An Equation instance
 *
 * @see  parseEquation()
 */
EquationParser.prototype.parseEquation = function (equationStr, options) {

  options = options || {};

  // Alias unary operands for faster matching: sqrt => s, abs => a
  equationStr = equationStr.replace(/(s)qrt|(a)bs/gi, '$1$2');

  // Sanitize
  if (!options.skipSanitize) { equationStr = sanitizeEquation(equationStr); }

  // Validate
  if (!options.skipValidate) { validateEquation(equationStr); }

  // Parse
  return parseEquation(equationStr);

};

module.exports = EquationParser;
<|endoftext|>


<commit_before>'use strict';

/**
 * The definition of BavariaIpsum class.
 */
var BavariaIpsum = function (opts) {
    opts = opts || {};

    /**
     * Array of "all" available bavarian words.
     */
    this.source = require('./source.json');

    /**
     * The default starting sentence.
     */
    this.startSentence = opts.startSentence || 'Bavaria ipsum dolor sit amet';

    /**
     * Min limit of words in one sentence.
     */
    this.minSentenceWords = opts.minSentenceWords || 2;

    /**
     * Max limit of words in one sentence.
     */
    this.maxSentenceWords = opts.maxSentenceWords || 20;

    /**
     * The chance to show comma after next word.
     */
    this.showCommaChance = opts.showCommaChance || 0.1;

    /**
     * Min limit of sentences in the paragraph.
     */
    this.minParagraphSentences = opts.minParagraphSentences || 2;

    /**
     * Max limit of sentences in the paragraph.
     */
    this.maxParagraphSentences = opts.maxParagraphSentences || 20;
};

BavariaIpsum.prototype = {
    /**
     * Return random Bavarian word.
     */
    generateWord: function () {
        return this.source[
            this._getRandomInt(0, this.source.length)
        ];
    },

    /**
     * Generate random Bavarian sentence.
     */
    generateSentence: function (length) {
        var sentence = "",
            i;

        length = length || this._getRandomInt(
            this.minSentenceWords,
            this.maxSentenceWords
        );

        for (i = 0; i < length; ++i) {
            sentence += this.generateWord();
            sentence += this._shouldShowComma() ? ", " : " ";
        }

        sentence = sentence.replace(/,?\s*$/, '');
        sentence += (new RegExp("[\?!\.]$")).test(sentence) ? '' : '.';

        return sentence.charAt(0).toUpperCase() + sentence.slice(1);
    },

    /**
     * Generate paragraph
     */
    generateParagraph: function (length, opts) {
        var sentences = [],
            args = Array.prototype.slice.call(arguments),
            argsLen = args.length,
            i;

        if (argsLen === 0 || (argsLen === 1 && typeof length === 'object')) {
            length = this._getRandomInt(
                this.minParagraphSentences,
                this.maxParagraphSentences
            );

            opts = args[0] || {};
        } else if (args.length === 2) {
            opts = opts || {};
            opts.useStartingSentence = !!opts.useStartingSentence;
        } else if (args.length === 1) {
            opts = {
                useStartingSentence: false
            };
        } else {
            throw new Error(
                'Invalid arguments'
            );
        }

        this._validateParagraphLength(length);
        this._validateParagraphOptions(opts);

        if (opts.useStartingSentence === true) {
            sentences.push(this.startSentence);
            sentences[sentences.length - 1] += ' ';
            sentences[sentences.length - 1] += this.generateSentence();
            --length;
        }

        for (i = 0; i < length; ++i) {
            sentences.push(this.generateSentence());
        }

        return sentences.join(' ');
    },

    /**
     * Return `true` if comma should be shown after next word.
     */
    _shouldShowComma: function () {
        return Math.random() < this.showCommaChance ? true : false;
    },

    /**
     * Return random int between min and max.
     */
    _getRandomInt: function (min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    },

    /**
     * Validate paragraph length (must be an int)
     */
    _validateParagraphLength: function (length) {
        if (length % 1 === 0) {
            return true;
        }

        throw new Error(
            'Length must be an Integer'
        );
    },

    _validateParagraphOptions: function (opts) {
        if (typeof opts === 'object') {
            return true;
        }

        throw new Error(
            'Opts must be an Object'
        );
    }
};

module.exports = BavariaIpsum;
<commit_msg>Fix Bad or unnecessary escaping<commit_after>'use strict';

/**
 * The definition of BavariaIpsum class.
 */
var BavariaIpsum = function (opts) {
    opts = opts || {};

    /**
     * Array of "all" available bavarian words.
     */
    this.source = require('./source.json');

    /**
     * The default starting sentence.
     */
    this.startSentence = opts.startSentence || 'Bavaria ipsum dolor sit amet';

    /**
     * Min limit of words in one sentence.
     */
    this.minSentenceWords = opts.minSentenceWords || 2;

    /**
     * Max limit of words in one sentence.
     */
    this.maxSentenceWords = opts.maxSentenceWords || 20;

    /**
     * The chance to show comma after next word.
     */
    this.showCommaChance = opts.showCommaChance || 0.1;

    /**
     * Min limit of sentences in the paragraph.
     */
    this.minParagraphSentences = opts.minParagraphSentences || 2;

    /**
     * Max limit of sentences in the paragraph.
     */
    this.maxParagraphSentences = opts.maxParagraphSentences || 20;
};

BavariaIpsum.prototype = {
    /**
     * Return random Bavarian word.
     */
    generateWord: function () {
        return this.source[
            this._getRandomInt(0, this.source.length)
        ];
    },

    /**
     * Generate random Bavarian sentence.
     */
    generateSentence: function (length) {
        var sentence = "",
            i;

        length = length || this._getRandomInt(
            this.minSentenceWords,
            this.maxSentenceWords
        );

        for (i = 0; i < length; ++i) {
            sentence += this.generateWord();
            sentence += this._shouldShowComma() ? ", " : " ";
        }

        sentence = sentence.replace(/,?\s*$/, '');
        sentence += (new RegExp("[?!\.]$")).test(sentence) ? '' : '.';

        return sentence.charAt(0).toUpperCase() + sentence.slice(1);
    },

    /**
     * Generate paragraph
     */
    generateParagraph: function (length, opts) {
        var sentences = [],
            args = Array.prototype.slice.call(arguments),
            argsLen = args.length,
            i;

        if (argsLen === 0 || (argsLen === 1 && typeof length === 'object')) {
            length = this._getRandomInt(
                this.minParagraphSentences,
                this.maxParagraphSentences
            );

            opts = args[0] || {};
        } else if (args.length === 2) {
            opts = opts || {};
            opts.useStartingSentence = !!opts.useStartingSentence;
        } else if (args.length === 1) {
            opts = {
                useStartingSentence: false
            };
        } else {
            throw new Error(
                'Invalid arguments'
            );
        }

        this._validateParagraphLength(length);
        this._validateParagraphOptions(opts);

        if (opts.useStartingSentence === true) {
            sentences.push(this.startSentence);
            sentences[sentences.length - 1] += ' ';
            sentences[sentences.length - 1] += this.generateSentence();
            --length;
        }

        for (i = 0; i < length; ++i) {
            sentences.push(this.generateSentence());
        }

        return sentences.join(' ');
    },

    /**
     * Return `true` if comma should be shown after next word.
     */
    _shouldShowComma: function () {
        return Math.random() < this.showCommaChance ? true : false;
    },

    /**
     * Return random int between min and max.
     */
    _getRandomInt: function (min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    },

    /**
     * Validate paragraph length (must be an int)
     */
    _validateParagraphLength: function (length) {
        if (length % 1 === 0) {
            return true;
        }

        throw new Error(
            'Length must be an Integer'
        );
    },

    _validateParagraphOptions: function (opts) {
        if (typeof opts === 'object') {
            return true;
        }

        throw new Error(
            'Opts must be an Object'
        );
    }
};

module.exports = BavariaIpsum;
<|endoftext|>


<commit_before><commit_msg>update TableCalculation<commit_after><|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

const _ = require('lodash');
const Promise = require('bluebird');
const figlet = Promise.promisify(require('./figlet'));
figlet.fonts = Promise.promisify(figlet.fonts);

const cheers = {
  'afrikaans': 'Gesondheid',
  'albanian': 'Gëzuar',
  'arabic': 'Fe sahetek',
  'armenian': 'Genatzt',
  'azerbaijani': 'Nuş olsun',
  'bosnian': 'Živjeli',
  'bulgarian': 'Naz-dra-vey',
  'burmese': 'Aung myin par say',
  'catalan': 'Salut',
  'chamorro': 'Biba',
  'chinese': 'gān bēi',
  'croatian': 'Nazdravlje',
  'czech': 'Na zdravi',
  'danish': 'Skål',
  'dutch': 'Proost',
  'english': 'Cheers',
  'estonian': 'Terviseks',
  'filipino': 'Mabuhay',
  'finnish': 'Kippis',
  'french': 'Santé',
  'french2': 'À la vôtre',
  'galician': 'Salud',
  'german': 'Prost',
  'german2': 'Zum wohl',
  'greek': 'Yamas',
  'hawaiian': 'Okole maluna',
  'hebrew': 'L\'chaim',
  'hungarian': 'Egészségedre',
  'hungarian2': 'Fenékig',
  'icelandic': 'Skál',
  'irish Gaelic': 'Sláinte',
  'italian': 'Salute',
  'italian2': 'Cin cin',
  'japanese': 'Kanpai',
  'korean': 'Gun bae',
  'latvian': 'Priekā',
  'latvian2': 'Prosit',
  'lithuanian': 'į sveikatą',
  'norwegian': 'Skål',
  'polish': 'Na zdrowie',
  'portuguese': 'Saúde',
  'romanian': 'Noroc',
  'romanian2': 'Sanatate',
  'russian': 'Budem zdorovi',
  'russian2': 'Na zdorovie',
  'serbian': 'ziveli',
  'slovak': 'Na zdravie',
  'slovenian': 'Na zdravje',
  'spanish': 'Salud',
  'swedish': 'Skål',
  'thai': 'Chok dee',
  'turkish': 'Serefe',
  'ukranian': 'Boodmo',
  'vietnamese': 'Môt hai ba, yo',
  'welsh': 'Iechyd da',
  'yiddish': 'Sei gesund',
};

const latinFonts = [
  'Big', 'Slant', 'Small', 'Small Slant', 'Standard', 'Block', 'Def Leppard', 'Efti Font', 'Efti Italic',
  'Georgi16', 'Georgia11', 'Lean', 'Mini', 'Mirror', 'Mnemonic', 'Script', 'Shadow', 'Wavy'
];

/**
 * This module exports a function that enrich the interactive command line and return a promise
 * @returns {Promise} - a promise that resolve when the operation is done
 */
module.exports = (icli) => {
  // Build the lists of choices
  const choicesLists = getChoices();

  const config = {
    section: 'CLI core',
    cmd: 'please',
    description: 'Have a beer! You deserve it',
    options: { noHelp: true },
    parameters: [{
      cmdSpec: '-l, --language <language>',
      type: 'list',
      choices: choicesLists.language
    }, {
      cmdSpec: '-f, --font <font name>',
      type: 'list',
      choices: choicesLists.font
    }]
  };

  /**
   * Build the choices for "list" and "checkbox" parameters
   * @param {Array} endpoints - the list o available endpoint specifications
   * @returns {Object} - collection of lists of choices for "list" and "checkbox" parameters
   */
  function getChoices() {
    return {
      language: _.keys(cheers),
      font: () => {
        return figlet.fonts();
      }
    };
  }

  /**
   * The following code cannot be correcltly tested because icli.getProgram().parse() fire an event to execute it and we cannot
   * know when its execution is finished. Pebo could gracefully handle this kind of behavior.
   */
  /**
   * Create the new project
   * @param {Object} parameters - the parameters provided in the command and in the prompt
   * @returns {Promise<null>} - The execution stops here
   */
  function executeCommand(parameters) {
    const language = parameters.language || _.sample(_.keys(cheers));
    let word = cheers[language];
    return figlet.fonts()
    .then(fonts => {
      const font = parameters.font ? parameters.font : _.sample(fonts);
      if (latinFonts.indexOf(font) === -1) { word = _.deburr(word); }
      console.log('language: ' + language);
      console.log('font: ' + font);
      return figlet(word, { font });
    })
    .then(cheers => {
      const b = txt => { return icli.format.custom(txt, '\x1b[93m'); };
      const m = txt => { return icli.format.custom(txt, '\x1b[1m'); };
      let beer = ['',
        m('    ,~~~,,`´´°°,,,~~~°°~`´´~°°o,         '),
        m('   ( °      °        °      °°  )        '),
        m('  (    °    °)          (     °  )       '),
        m(' (      )          °°  (       ,)°       '),
        m(' (  °    ),,,,,°°o,,,O°°~,~,,,,)         '),
        m('  (    )°') + '°)°  °( °  )  °°( ° )°|         ',
        m('   o') + '|' + m('°') + '( ° ) °  ( ° o) ° °(   ) |         ',
        '    |o(°°°)°°oo(~o~~)~O°°(°°°)¨|         ',
        '    |' + b(' (   ) °  ( °  )    (   ) ') + '|___      ',
        '    |' + b(' (   )    (°   )    (   )°') + '    `\\    ',
        '    |' + b(' (   )  ° ( °  )    (   ) ') + ' __   \\   ',
        '    |' + b(' (   )  ° (°   )    ( ° ) ') + '|  `\\  \\  ',
        '    |' + b(' (   ) °  (    )    (   ) ') + '|    \\  \\ ',
        '    |' + b(' (   )    (°   )    (   ) ') + '|    )  ) ',
        '    |' + b(' (   )  ° ( °  )    (   ) ') + '|    )  ) ',
        '    |' + b(' (   )  ° ( °  )  ° (   ) ') + '|    )  ) ',
        '    |' + b(' (°  ) °  ( °  )    (   ) ') + '|    )  ) ',
        '    |' + b(' (   ) °  (°   )    (   ) ') + '|    /  / ',
        '    |' + b(' (   )  ° (    )    (   ) ') + '|__,/  /  ',
        '    |' + b(' (   ) °  ( °  )    (   ) ') + '      /   ',
        '    |' + b(' (   ) °  (°   )  ° (   ) ') + ' ___,/    ',
        '    |' + b(' (   )  ° (°   )  ° (   ) ') + '|         ',
        '    |' + b(' (   )  ° ( °  )    (  °) ') + '|         ',
        '    |' + b('°(   )  ° ( °  )    (   ) ') + '|         ',
        '    |' + b('  ¨¨¨  °  `~~~~´     ¨¨¨  ') + '|         ',
        '    l__' + b('     °   °            ') + '__j         ',
        'ah     ````¨¨¨^~~~~~~^¨¨¨´´´´            ',
        ''
      ];
      cheers = cheers.split('\n');
      const termWidth = process.stdout.columns;
      const cheersWidth = _.max(_.map(cheers, (o) => { return o.length; }));
      const beerWidth = _.max(_.map(beer, (o) => { return o.length; }));
      console.log(beerWidth, cheersWidth, termWidth);
      if (!process.stdout.isTTY || (beerWidth + cheersWidth < termWidth)) {
        const top = Math.round((beer.length - cheers.length) / 2);
        for (let i = 0; i < cheers.length; i++) {
          beer[top + i + 1] += '   ' + cheers[i];
        }
      } else if (cheersWidth < termWidth) {
        beer = _.concat(beer, cheers);
      }
      console.log(beer.join('\n'));
      return Promise.resolve(true);
    });
  }

  /**
   * Create the command and the prompt
   */
  return icli.createSubCommand(config, executeCommand);
};
<commit_msg>fix travis tty during integration tests<commit_after>#!/usr/bin/env node
'use strict';

const _ = require('lodash');
const Promise = require('bluebird');
const figlet = Promise.promisify(require('./figlet'));
figlet.fonts = Promise.promisify(figlet.fonts);

const cheers = {
  'afrikaans': 'Gesondheid',
  'albanian': 'Gëzuar',
  'arabic': 'Fe sahetek',
  'armenian': 'Genatzt',
  'azerbaijani': 'Nuş olsun',
  'bosnian': 'Živjeli',
  'bulgarian': 'Naz-dra-vey',
  'burmese': 'Aung myin par say',
  'catalan': 'Salut',
  'chamorro': 'Biba',
  'chinese': 'gān bēi',
  'croatian': 'Nazdravlje',
  'czech': 'Na zdravi',
  'danish': 'Skål',
  'dutch': 'Proost',
  'english': 'Cheers',
  'estonian': 'Terviseks',
  'filipino': 'Mabuhay',
  'finnish': 'Kippis',
  'french': 'Santé',
  'french2': 'À la vôtre',
  'galician': 'Salud',
  'german': 'Prost',
  'german2': 'Zum wohl',
  'greek': 'Yamas',
  'hawaiian': 'Okole maluna',
  'hebrew': 'L\'chaim',
  'hungarian': 'Egészségedre',
  'hungarian2': 'Fenékig',
  'icelandic': 'Skál',
  'irish Gaelic': 'Sláinte',
  'italian': 'Salute',
  'italian2': 'Cin cin',
  'japanese': 'Kanpai',
  'korean': 'Gun bae',
  'latvian': 'Priekā',
  'latvian2': 'Prosit',
  'lithuanian': 'į sveikatą',
  'norwegian': 'Skål',
  'polish': 'Na zdrowie',
  'portuguese': 'Saúde',
  'romanian': 'Noroc',
  'romanian2': 'Sanatate',
  'russian': 'Budem zdorovi',
  'russian2': 'Na zdorovie',
  'serbian': 'ziveli',
  'slovak': 'Na zdravie',
  'slovenian': 'Na zdravje',
  'spanish': 'Salud',
  'swedish': 'Skål',
  'thai': 'Chok dee',
  'turkish': 'Serefe',
  'ukranian': 'Boodmo',
  'vietnamese': 'Môt hai ba, yo',
  'welsh': 'Iechyd da',
  'yiddish': 'Sei gesund',
};

const latinFonts = [
  'Big', 'Slant', 'Small', 'Small Slant', 'Standard', 'Block', 'Def Leppard', 'Efti Font', 'Efti Italic',
  'Georgi16', 'Georgia11', 'Lean', 'Mini', 'Mirror', 'Mnemonic', 'Script', 'Shadow', 'Wavy'
];

/**
 * This module exports a function that enrich the interactive command line and return a promise
 * @returns {Promise} - a promise that resolve when the operation is done
 */
module.exports = (icli) => {
  // Build the lists of choices
  const choicesLists = getChoices();

  const config = {
    section: 'CLI core',
    cmd: 'please',
    description: 'Have a beer! You deserve it',
    options: { noHelp: true },
    parameters: [{
      cmdSpec: '-l, --language <language>',
      type: 'list',
      choices: choicesLists.language
    }, {
      cmdSpec: '-f, --font <font name>',
      type: 'list',
      choices: choicesLists.font
    }]
  };

  /**
   * Build the choices for "list" and "checkbox" parameters
   * @param {Array} endpoints - the list o available endpoint specifications
   * @returns {Object} - collection of lists of choices for "list" and "checkbox" parameters
   */
  function getChoices() {
    return {
      language: _.keys(cheers),
      font: () => {
        return figlet.fonts();
      }
    };
  }

  /**
   * The following code cannot be correcltly tested because icli.getProgram().parse() fire an event to execute it and we cannot
   * know when its execution is finished. Pebo could gracefully handle this kind of behavior.
   */
  /**
   * Create the new project
   * @param {Object} parameters - the parameters provided in the command and in the prompt
   * @returns {Promise<null>} - The execution stops here
   */
  function executeCommand(parameters) {
    const language = parameters.language || _.sample(_.keys(cheers));
    let word = cheers[language];
    return figlet.fonts()
    .then(fonts => {
      const font = parameters.font ? parameters.font : _.sample(fonts);
      if (latinFonts.indexOf(font) === -1) { word = _.deburr(word); }
      console.log('language: ' + language);
      console.log('font: ' + font);
      return figlet(word, { font });
    })
    .then(cheers => {
      const b = txt => { return icli.format.custom(txt, '\x1b[93m'); };
      const m = txt => { return icli.format.custom(txt, '\x1b[1m'); };
      let beer = ['',
        m('    ,~~~,,`´´°°,,,~~~°°~`´´~°°o,         '),
        m('   ( °      °        °      °°  )        '),
        m('  (    °    °)          (     °  )       '),
        m(' (      )          °°  (       ,)°       '),
        m(' (  °    ),,,,,°°o,,,O°°~,~,,,,)         '),
        m('  (    )°') + '°)°  °( °  )  °°( ° )°|         ',
        m('   o') + '|' + m('°') + '( ° ) °  ( ° o) ° °(   ) |         ',
        '    |o(°°°)°°oo(~o~~)~O°°(°°°)¨|         ',
        '    |' + b(' (   ) °  ( °  )    (   ) ') + '|___      ',
        '    |' + b(' (   )    (°   )    (   )°') + '    `\\    ',
        '    |' + b(' (   )  ° ( °  )    (   ) ') + ' __   \\   ',
        '    |' + b(' (   )  ° (°   )    ( ° ) ') + '|  `\\  \\  ',
        '    |' + b(' (   ) °  (    )    (   ) ') + '|    \\  \\ ',
        '    |' + b(' (   )    (°   )    (   ) ') + '|    )  ) ',
        '    |' + b(' (   )  ° ( °  )    (   ) ') + '|    )  ) ',
        '    |' + b(' (   )  ° ( °  )  ° (   ) ') + '|    )  ) ',
        '    |' + b(' (°  ) °  ( °  )    (   ) ') + '|    )  ) ',
        '    |' + b(' (   ) °  (°   )    (   ) ') + '|    /  / ',
        '    |' + b(' (   )  ° (    )    (   ) ') + '|__,/  /  ',
        '    |' + b(' (   ) °  ( °  )    (   ) ') + '      /   ',
        '    |' + b(' (   ) °  (°   )  ° (   ) ') + ' ___,/    ',
        '    |' + b(' (   )  ° (°   )  ° (   ) ') + '|         ',
        '    |' + b(' (   )  ° ( °  )    (  °) ') + '|         ',
        '    |' + b('°(   )  ° ( °  )    (   ) ') + '|         ',
        '    |' + b('  ¨¨¨  °  `~~~~´     ¨¨¨  ') + '|         ',
        '    l__' + b('     °   °            ') + '__j         ',
        'ah     ````¨¨¨^~~~~~~^¨¨¨´´´´            ',
        ''
      ];
      cheers = cheers.split('\n');
      const termWidth = process.stdout.columns;
      const cheersWidth = _.max(_.map(cheers, (o) => { return o.length; }));
      const beerWidth = _.max(_.map(beer, (o) => { return o.length; }));
      // The test "termWidth === 0" is useful in the travis environment
      if (termWidth === 0 || (beerWidth + cheersWidth < termWidth)) {
        const top = Math.round((beer.length - cheers.length) / 2);
        for (let i = 0; i < cheers.length; i++) {
          beer[top + i + 1] += '   ' + cheers[i];
        }
      } else if (cheersWidth < termWidth) {
        beer = _.concat(beer, cheers);
      }
      console.log(beer.join('\n'));
      return Promise.resolve(true);
    });
  }

  /**
   * Create the command and the prompt
   */
  return icli.createSubCommand(config, executeCommand);
};
<|endoftext|>


<commit_before>$( document ).ready(function() {
    $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
        jqXHR.setRequestHeader('X-CSRF-Token', Cookies.get('csrftoken'));
        });
    $(document).ajaxStart(function () { $("html").addClass("wait"); });
    $(document).ajaxStop(function () { $("html").removeClass("wait"); });

//uuid
function uuid()
{
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
}

//user cookie

if (typeof Cookies.get('NamingGameUser') === 'undefined'){
    var user_str = uuid();
    Cookies.set('NamingGameUser',
        user_str
        );

    };

      $.ajax({
                                    url: url_send_user_info+user_str,
                                    success: function(result2){

            window.location.href = url_home;}

    });
var user_str = Cookies.get('NamingGameUser');
 //window.location.href =  url_send_user_info+user_str;

$("#username").html(user_str);

    $(document).ajaxStop(function () { $("#username").html(user_str); });
});

<commit_msg>forgot login.js<commit_after>$( document ).ready(function() {
    $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
        jqXHR.setRequestHeader('X-CSRF-Token', Cookies.get('csrftoken'));
        });
    $(document).ajaxStart(function () { $("html").addClass("wait"); });
    $(document).ajaxStop(function () { $("html").removeClass("wait"); });

//uuid
function uuid()
{
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
}

//user cookie

if (typeof Cookies.get('NamingGameUser') === 'undefined'){
    var user_str = uuid();
    Cookies.set('NamingGameUser',
        user_str
        );

    };

$.ajax({
                                    url: url_send_user_info+user_str,
                                    success: function(result2){

            window.location.href = url_home;}

    });
var user_str = Cookies.get('NamingGameUser');
 //window.location.href =  url_send_user_info+user_str;

$("#username").html(user_str);

    $(document).ajaxStop(function () { $("#username").html(user_str); });
});

<|endoftext|>


<commit_before>import { includes, keyBy } from 'lodash/collection';
import { forOwn } from 'lodash/object';

/**
 * Filters out commands based on user permissions.
 * @param {Object} filterValues - The value of the 'permissions' property as defined on the command's filters.
 * @param {Message} message - The message being tested.
 * @returns {Boolean} Returns true if command can be filtered out, false otherwise.
 */
export const permissions = (filterValues, message) => {
  const channelPermissions = message.channel.isPrivate
    ? null
    : message.channel.permissionsOf(message.author).serialize();

  if (channelPermissions) {
    let permissionsMatchRequirements = true;

    forOwn(filterValues, (value, key) => {
      // the values of the permissions in the filter object and the channel permissions object must match
      if ((value && !channelPermissions[key]) || (!value && channelPermissions[key])) {
        permissionsMatchRequirements = false;

        return false;
      }
    });

    if (!permissionsMatchRequirements) {
      return true;
    }
  }

  return false;
};

/**
 * Filters out commands based on user role names.
 * @param {Array.<String>} filterValues - The value of the 'roleNames' property as defined on the command's filters.
 * @param {Message} message - The message being tested.
 * @returns {Boolean} Returns true if command can be filtered out, false otherwise.
 */
export const roleNames = (filterValues, message) => {
  if (!message.server) {
    return false;
  }

  const userRoleNameIndex = keyBy(filterValues);
  const userRoles = message.server.rolesOfUser(message.author);

  for (const role of userRoles) {
    if (userRoleNameIndex[role.name]) {
      return false;
    }
  }

  return true;
};

/**
 * Filters out commands based on user role IDs.
 * @param {Array.<String>} filterValues - The value of the 'roleIds' property as defined on the command's filters.
 * @param {Message} message - The message being tested.
 * @returns {Boolean} Returns true if command can be filtered out, false otherwise.
 */
export const roleIds = (filterValues, message) => {
  if (!message.server) {
    return false;
  }

  const userRoleIdIndex = keyBy(filterValues);
  const userRoles = message.server.rolesOfUser(message.author);

  for (const role of userRoles) {
    if (userRoleIdIndex[role.id]) {
      return false;
    }
  }

  return true;
};

/**
 * Filters out commands based on user IDs.
 * @param {Array.<String>} filterValues - The value of the 'userIds' property as defined on the command's filters.
 * @param {Message} message - The message being tested.
 * @returns {Boolean} Returns true if command can be filtered out, false otherwise.
 */
export const userIds = (filterValues, message) => filterValues.length && !includes(filterValues, message.author.id);
<commit_msg>Update for v9.<commit_after>import { includes, keyBy } from 'lodash/collection';
import { forOwn } from 'lodash/object';

/**
 * Filters out commands based on user permissions.
 * @param {Object} filterValues - The value of the 'permissions' property as defined on the command's filters.
 * @param {Message} message - The message being tested.
 * @returns {Boolean} Returns true if command can be filtered out, false otherwise.
 */
export const permissions = (filterValues, message) => {
  const channelPermissions = message.channel.type === 'text' || message.channel.type === 'voice'
    ? null
    : message.channel.permissionsFor(message.author).serialize();

  if (channelPermissions) {
    let permissionsMatchRequirements = true;

    forOwn(filterValues, (value, key) => {
      // the values of the permissions in the filter object and the channel permissions object must match
      if ((value && !channelPermissions[key]) || (!value && channelPermissions[key])) {
        permissionsMatchRequirements = false;

        return false;
      }
    });

    if (!permissionsMatchRequirements) {
      return true;
    }
  }

  return false;
};

/**
 * Filters out commands based on user role names.
 * @param {Array.<String>} filterValues - The value of the 'roleNames' property as defined on the command's filters.
 * @param {Message} message - The message being tested.
 * @returns {Boolean} Returns true if command can be filtered out, false otherwise.
 */
export const roleNames = (filterValues, message) => {
  if (!message.guild || (message.guild && !message.guild.available)) {
    return false;
  }

  const userRoleNameIndex = keyBy(filterValues);
  const userRoles = message.guild.members.find('id', message.author.id).roles;

  for (const [roleId, role] of userRoles) {
    if (userRoleNameIndex[role.name]) {
      return false;
    }
  }

  return true;
};

/**
 * Filters out commands based on user role IDs.
 * @param {Array.<String>} filterValues - The value of the 'roleIds' property as defined on the command's filters.
 * @param {Message} message - The message being tested.
 * @returns {Boolean} Returns true if command can be filtered out, false otherwise.
 */
export const roleIds = (filterValues, message) => {
  if (!message.guild || (message.guild && !message.guild.available)) {
    return false;
  }

  const userRoleIdIndex = keyBy(filterValues);
  const userRoles = message.guild.members.find('id', message.author.id).roles;

  for (const [roleId, role] of userRoles) {
    if (userRoleIdIndex[roleId]) {
      return false;
    }
  }

  return true;
};

/**
 * Filters out commands based on user IDs.
 * @param {Array.<String>} filterValues - The value of the 'userIds' property as defined on the command's filters.
 * @param {Message} message - The message being tested.
 * @returns {Boolean} Returns true if command can be filtered out, false otherwise.
 */
export const userIds = (filterValues, message) => filterValues.length && !includes(filterValues, message.author.id);
<|endoftext|>


<commit_before>window.requestAnimFrame = (function () {
    return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function (callback) {
        window.setTimeout(callback, 1000 / 30);
    };
})();

var control_canvas,
c,        // c is the fg_canvas' context 2D
halfWidth,
halfHeight,
leftPointerID = -1,
leftPointerPos = new Vector2(0, 0),
leftPointerStartPos = new Vector2(0, 0),
leftVector = new Vector2(0, 0);
arrow = new VectorLED(0, 0, 0, 0);

var touches; // collections of pointers

/////////////////////////////// ARDUINO SETUP
var IOBoard = BO.IOBoard;
var IOBoardEvent = BO.IOBoardEvent;
var Pin = BO.Pin;

//// Variables
// LED related
var led1; //-90 D
var led2; //0 R
var led3; //90 U
var led4; //180=-180 L
var LEDloopON = false;
var LEDcont = 1;
var max_val;

var frame = 0;
var lastUpdateTime = 0;
var acDelta = 0;
var msPerFrame = 10;

// Set to true to print debug messages to console
BO.enableDebugging = true;

var host = window.location.hostname;
// if the file is opened locally, set the host to "localhost"
if (window.location.protocol.indexOf("file:") === 0) {
        host = "171.65.102.132";
    }
var arduino = new IOBoard(host, 8887);
///////////////////////////// ARDUINO SETUP END

var username = "noname";
var socket;

document.addEventListener("DOMContentLoaded", init);

window.onorientationchange = resetCanvas;
window.onresize = resetCanvas;

function init() {
    setupCanvas();
    setupD3();
    setupMotionDetection();

    touches = new Collection();

    arduino.addEventListener(IOBoardEvent.READY, onReady);
}

function onReady(event) {
        // Remove the event listener because it is no longer needed
        arduino.removeEventListener(IOBoardEvent.READY, onReady);

        // Set Pin 5,6,9,10 to PWM
        arduino.setDigitalPinMode(5, Pin.PWM);
        arduino.setDigitalPinMode(6, Pin.PWM);
        arduino.setDigitalPinMode(9, Pin.PWM);
        arduino.setDigitalPinMode(10, Pin.PWM);

        // Create an LED object to interface with the LED wired
        // to the I/O board
        led1 = arduino.getDigitalPin(5);
        led2 = arduino.getDigitalPin(6);
        led3 = arduino.getDigitalPin(9);
        led4 = arduino.getDigitalPin(10);

        // jQuery part for the sliders
    $("#n_slider").slider({
        step: 1,
        min : 1,
        max : 20,
        value: 4
    });

    $('#n_value').text("Value: 4");

    $( "#n_slider" ).bind( "slide", function(event, ui) {
        var value = ui.value;
        $('#n_value').text("Value: " + value);
        n = value;
    });

    $("#size_slider").slider({
        step: 10,
        min : 20,
        max : 200,
        value : 80
    });

    $('#size_value').text("Value: 80");

    $( "#size_slider" ).bind( "slide", function(event, ui) {
        var value = ui.value;
        $('#size_value').text("Value: " + value);
        console.log(value);
        l = value;
    });

    $("#v_slider").slider({
        step: 0.05,
        min : 0.0,
        max : 1.0,
        value : 0.4
    });

    $('#v_value').text("Value: 0.40");

    $( "#v_slider" ).bind( "slide", function(event, ui) {
        var value = ui.value;
        $('#v_value').text("Value: " + value);
        console.log(value);
        v = value;
    });

    $("#br_slider").slider({
        step: 0.05,
        min : 0.0,
        max : 1.0,
        value: 0
    });

    $('#br_value').text("Value: 0.00");

    $( "#br_slider" ).bind( "slide", function(event, ui) {
        var value = ui.value;
        $('#br_value').text("Value: " + value.toFixed(2));
        brown_const = value;
    });

        $('input[name=setUsername]').click(function(){
        	if($('input[name=usernameTxt]').val() != ""){
                username = $('input[name=usernameTxt]').val();
                    var msg = {type:'setUsername', user:username};
                    socket.json.send(msg);
                }
            $('#username').slideUp("slow",function(){
                $('#entergame').slideDown("slow");
            });
        });

        $("input[name=gamestartBtn]").click(function(){
            resetGame();
        });

        socket = new io.connect('http://171.65.102.132:8088');
        var chat = $('#chat');
        var board = $('#board');

        socket.on('connect', function() {
                console.log("Connected");
                //chat.html("Connected!");
                socket.emit('message', {channel:'realtime'});
        });

        socket.on('message', function(message){
                chat.append(message + '
');
        });

        socket.on('postscore', function(score){
                board.empty();
                for (var i=0;i<score.length;i++){
                        if(i==0){
                                board.append(''+ score[i][0]+'  :  '+score[i][1]+'
');
                        }else{
                                board.append(score[i][0]+'  :  '+score[i][1]+ '
');
                        }
                }
                board.fadeOut('fast');
                board.fadeIn('fast');
                board.fadeOut('fast');
                board.fadeIn('fast');
        });

        socket.on('disconnect', function() {
                console.log('disconnected');
                chat.html("Disconnect!");
        });

        $("input[name=sendBtn]").click(function(){
                var msg = {type:'chat',message:username + " : " + $("input[name=chatTxt]").val()}
                socket.json.send(msg);
                $("input[name=chatTxt]").val("");
        });

    control_canvas.addEventListener('pointerdown', onPointerDown, false);
    control_canvas.addEventListener('pointermove', onPointerMove, false);
    control_canvas.addEventListener('pointerup', onPointerUp, false);
    control_canvas.addEventListener('pointerout', onPointerUp, false);

    requestAnimFrame(joystick_draw);
}

function joystick_draw() {
    c.clearRect(0, 0, control_canvas.width, control_canvas.height);

    c.beginPath();
    c.moveTo(halfWidth, halfHeight-4);
    c.strokeStyle = "rgba(250, 102, 0, 1)";
    c.lineWidth = 2;
    c.lineTo(halfWidth, halfHeight+4);
    c.stroke();

    c.beginPath();
    c.moveTo(halfWidth+4, halfHeight);
    c.strokeStyle = "rgba(250, 102, 0, 1)";
    c.lineWidth = 2;
    c.lineTo(halfWidth-4, halfHeight);
    c.stroke();

    drawCircles(halfWidth, halfHeight);

    var img_hand = new Image;
    img_hand.onload = function(){c.drawImage(img_hand,0,0);};
    img_hand.src = "http://www.stanford.edu/~amchung/joystick_hand.svg";

        //// mouse event loop
    touches.forEach(function (touch) {
        if (touch.identifier == leftPointerID) {
            var alpha = arrow.trimArrow(leftVector, max_val);

            c.beginPath();
            c.fillStyle = "rgba(250, 102, 0, 1)";
            c.arc(leftPointerPos.x, leftPointerPos.y, 16, 0, Math.PI * 2, true);
            c.fill();

            c.beginPath();
            c.moveTo(leftPointerStartPos.x,leftPointerStartPos.y);
            c.strokeStyle = "rgba(250, 102, 0, 1)";
                        c.lineTo(leftPointerStartPos.x+max_val*(arrow.int2-arrow.int4),leftPointerStartPos.y+max_val*(arrow.int1-arrow.int3));
                        c.lineWidth = 3;
                        c.stroke();

                        c.beginPath();
                        c.fillStyle = "rgba(255, 255, 255, "+alpha*(LEDcont)+")";
                    c.arc(halfWidth, halfHeight, 16, 0, Math.PI * 2, true);
                    c.fill();

                        c.beginPath();
                c.fillStyle = "#fff";
                c.fillText(alpha,halfWidth-10, halfHeight-25);

                c.beginPath();
                c.fillStyle = "#dd6600";
                var theta = leftVector.angle();
                c.fillText(theta.toFixed(0),leftPointerPos.x+10, leftPointerPos.y-20);
        }
    });

    requestAnimFrame(joystick_draw);

    //// LED control loop
    var delta = Date.now() - lastUpdateTime;
    if (acDelta > msPerFrame)
    {
        acDelta = 0;
        if(LEDloopON)
        {
                //LEDon = frame%2;
                LEDcont = 1;
                changeLED(LEDcont);
        }
        frame++;
        if (frame >= 2) {frame = 0;}
    } else
    {
        acDelta += delta;
    }
    lastUpdateTime = Date.now();
}

function drawCircles(xCenter,yCenter)
{
        var needle = new Vector2(max_val, 0);
        for(var i=0;i<24*3;i++)
        {
                c.beginPath();
                c.fillStyle = "rgba(255, 255, 255, 0.5)";
                c.lineWidth = 3;
                c.arc(xCenter + needle.x, yCenter + needle.y, 1, 0, Math.PI * 2, true);
                c.fill();
                needle.rotate(5,0);
        }
}

function givePointerType(event) {
    switch (event.pointerType) {
        case event.POINTER_TYPE_MOUSE:
            return "MOUSE";
            break;
        case event.POINTER_TYPE_PEN:
            return "PEN";
            break;
        case event.POINTER_TYPE_TOUCH:
            return "TOUCH";
            break;
    }
}

function onPointerDown(e) {
    var newPointer = { identifier: e.pointerId, x: e.clientX, y: e.clientY, type: givePointerType(e) };
    leftPointerID = e.pointerId;
    //leftPointerStartPos.reset(e.clientX, e.clientY);
    leftPointerStartPos.reset(halfWidth, halfHeight);
    leftPointerPos.copyFrom(leftPointerStartPos);
    leftVector.reset(0, 0);
    arrow.reset(0, 0, 0, 0);
    touches.add(e.pointerId, newPointer);
}

function onPointerMove(e) {
    if (leftPointerID == e.pointerId) {
        //leftPointerPos.reset(e.clientX, e.clientY);
        leftPointerPos.reset(e.offsetX, e.offsetY);
        leftVector.copyFrom(leftPointerPos);
        //leftVector.minusEq(leftPointerStartPos);
        leftVector.minusEq(leftPointerStartPos);
        arrow.setArrow(leftVector, max_val);
        LEDloopON = true;
    }
    else {
        if (touches.item(e.pointerId)) {
            touches.item(e.pointerId).x = e.clientX;
            touches.item(e.pointerId).y = e.clientY;
        }
    }
}

function onPointerUp(e) {
    if (leftPointerID == e.pointerId) {
        leftPointerID = -1;
        leftVector.reset(0, 0);
    }
    leftVector.reset(0, 0);
    arrow.reset(0, 0, 0, 0);
    touches.remove(e.pointerId);
    LEDloopON = false;
    changeLED(0);
}

function setupCanvas() {
    control_canvas = document.getElementById('controlCanvas');
    c = control_canvas.getContext('2d');
    resetCanvas();
    c.strokeStyle = "#ffffff";
    c.lineWidth = 2;
}

// Arduino control functions
function changeLED(LEDon) {
    if(LEDon)
    {
            led1.value = arrow.int1;
            led2.value = arrow.int2;
            led3.value = arrow.int3;
            led4.value = arrow.int4;
    }
    else
    {
            led1.value = 0;
            led2.value = 0;
            led3.value = 0;
            led4.value = 0;
        }
}

function resetCanvas(e) {
    max_val = (document.getElementById("controlArea").offsetWidth-100)/2;

    // resize the canvas - but remember - this clears the canvas too.

    control_canvas.width = document.getElementById("controlArea").offsetWidth-20;
    control_canvas.height = control_canvas.width-20;

    halfWidth = (control_canvas.width)/2;
    halfHeight = (control_canvas.height)/2;

    // make sure we scroll to the top left.
    window.scrollTo(0, 0);
}<commit_msg>debug svg<commit_after>window.requestAnimFrame = (function () {
    return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function (callback) {
        window.setTimeout(callback, 1000 / 30);
    };
})();

var control_canvas,
c,        // c is the fg_canvas' context 2D
halfWidth,
halfHeight,
leftPointerID = -1,
leftPointerPos = new Vector2(0, 0),
leftPointerStartPos = new Vector2(0, 0),
leftVector = new Vector2(0, 0);
arrow = new VectorLED(0, 0, 0, 0);

var touches; // collections of pointers

/////////////////////////////// ARDUINO SETUP
var IOBoard = BO.IOBoard;
var IOBoardEvent = BO.IOBoardEvent;
var Pin = BO.Pin;

//// Variables
// LED related
var led1; //-90 D
var led2; //0 R
var led3; //90 U
var led4; //180=-180 L
var LEDloopON = false;
var LEDcont = 1;
var max_val;

var frame = 0;
var lastUpdateTime = 0;
var acDelta = 0;
var msPerFrame = 10;

// Set to true to print debug messages to console
BO.enableDebugging = true;

var host = window.location.hostname;
// if the file is opened locally, set the host to "localhost"
if (window.location.protocol.indexOf("file:") === 0) {
        host = "171.65.102.132";
    }
var arduino = new IOBoard(host, 8887);
///////////////////////////// ARDUINO SETUP END

var username = "noname";
var socket;

document.addEventListener("DOMContentLoaded", init);

window.onorientationchange = resetCanvas;
window.onresize = resetCanvas;

function init() {
    setupCanvas();
    setupD3();
    setupMotionDetection();

    touches = new Collection();

    arduino.addEventListener(IOBoardEvent.READY, onReady);
}

function onReady(event) {
        // Remove the event listener because it is no longer needed
        arduino.removeEventListener(IOBoardEvent.READY, onReady);

        // Set Pin 5,6,9,10 to PWM
        arduino.setDigitalPinMode(5, Pin.PWM);
        arduino.setDigitalPinMode(6, Pin.PWM);
        arduino.setDigitalPinMode(9, Pin.PWM);
        arduino.setDigitalPinMode(10, Pin.PWM);

        // Create an LED object to interface with the LED wired
        // to the I/O board
        led1 = arduino.getDigitalPin(5);
        led2 = arduino.getDigitalPin(6);
        led3 = arduino.getDigitalPin(9);
        led4 = arduino.getDigitalPin(10);

        // jQuery part for the sliders
    $("#n_slider").slider({
        step: 1,
        min : 1,
        max : 20,
        value: 4
    });

    $('#n_value').text("Value: 4");

    $( "#n_slider" ).bind( "slide", function(event, ui) {
        var value = ui.value;
        $('#n_value').text("Value: " + value);
        n = value;
    });

    $("#size_slider").slider({
        step: 10,
        min : 20,
        max : 200,
        value : 80
    });

    $('#size_value').text("Value: 80");

    $( "#size_slider" ).bind( "slide", function(event, ui) {
        var value = ui.value;
        $('#size_value').text("Value: " + value);
        console.log(value);
        l = value;
    });

    $("#v_slider").slider({
        step: 0.05,
        min : 0.0,
        max : 1.0,
        value : 0.4
    });

    $('#v_value').text("Value: 0.40");

    $( "#v_slider" ).bind( "slide", function(event, ui) {
        var value = ui.value;
        $('#v_value').text("Value: " + value);
        console.log(value);
        v = value;
    });

    $("#br_slider").slider({
        step: 0.05,
        min : 0.0,
        max : 1.0,
        value: 0
    });

    $('#br_value').text("Value: 0.00");

    $( "#br_slider" ).bind( "slide", function(event, ui) {
        var value = ui.value;
        $('#br_value').text("Value: " + value.toFixed(2));
        brown_const = value;
    });

        $('input[name=setUsername]').click(function(){
        	if($('input[name=usernameTxt]').val() != ""){
                username = $('input[name=usernameTxt]').val();
                    var msg = {type:'setUsername', user:username};
                    socket.json.send(msg);
                }
            $('#username').slideUp("slow",function(){
                $('#entergame').slideDown("slow");
            });
        });

        $("input[name=gamestartBtn]").click(function(){
            resetGame();
        });

        socket = new io.connect('http://171.65.102.132:8088');
        var chat = $('#chat');
        var board = $('#board');

        socket.on('connect', function() {
                console.log("Connected");
                //chat.html("Connected!");
                socket.emit('message', {channel:'realtime'});
        });

        socket.on('message', function(message){
                chat.append(message + '
');
        });

        socket.on('postscore', function(score){
                board.empty();
                for (var i=0;i<score.length;i++){
                        if(i==0){
                                board.append(''+ score[i][0]+'  :  '+score[i][1]+'
');
                        }else{
                                board.append(score[i][0]+'  :  '+score[i][1]+ '
');
                        }
                }
                board.fadeOut('fast');
                board.fadeIn('fast');
                board.fadeOut('fast');
                board.fadeIn('fast');
        });

        socket.on('disconnect', function() {
                console.log('disconnected');
                chat.html("Disconnect!");
        });

        $("input[name=sendBtn]").click(function(){
                var msg = {type:'chat',message:username + " : " + $("input[name=chatTxt]").val()}
                socket.json.send(msg);
                $("input[name=chatTxt]").val("");
        });

    control_canvas.addEventListener('pointerdown', onPointerDown, false);
    control_canvas.addEventListener('pointermove', onPointerMove, false);
    control_canvas.addEventListener('pointerup', onPointerUp, false);
    control_canvas.addEventListener('pointerout', onPointerUp, false);

    requestAnimFrame(joystick_draw);
}

function joystick_draw() {
    c.clearRect(0, 0, control_canvas.width, control_canvas.height);

    c.beginPath();
    c.moveTo(halfWidth, halfHeight-4);
    c.strokeStyle = "rgba(250, 102, 0, 1)";
    c.lineWidth = 2;
    c.lineTo(halfWidth, halfHeight+4);
    c.stroke();

    c.beginPath();
    c.moveTo(halfWidth+4, halfHeight);
    c.strokeStyle = "rgba(250, 102, 0, 1)";
    c.lineWidth = 2;
    c.lineTo(halfWidth-4, halfHeight);
    c.stroke();

    drawCircles(halfWidth, halfHeight);

        //// mouse event loop
    touches.forEach(function (touch) {
        if (touch.identifier == leftPointerID) {
            var alpha = arrow.trimArrow(leftVector, max_val);

            c.beginPath();
            c.fillStyle = "rgba(250, 102, 0, 1)";
            c.arc(leftPointerPos.x, leftPointerPos.y, 16, 0, Math.PI * 2, true);
            c.fill();

            c.beginPath();
            c.moveTo(leftPointerStartPos.x,leftPointerStartPos.y);
            c.strokeStyle = "rgba(250, 102, 0, 1)";
                        c.lineTo(leftPointerStartPos.x+max_val*(arrow.int2-arrow.int4),leftPointerStartPos.y+max_val*(arrow.int1-arrow.int3));
                        c.lineWidth = 3;
                        c.stroke();

                        c.beginPath();
                        c.fillStyle = "rgba(255, 255, 255, "+alpha*(LEDcont)+")";
                    c.arc(halfWidth, halfHeight, 16, 0, Math.PI * 2, true);
                    c.fill();

                        c.beginPath();
                c.fillStyle = "#fff";
                c.fillText(alpha,halfWidth-10, halfHeight-25);

                c.beginPath();
                c.fillStyle = "#dd6600";
                var theta = leftVector.angle();
                c.fillText(theta.toFixed(0),leftPointerPos.x+10, leftPointerPos.y-20);
        }
    });

    requestAnimFrame(joystick_draw);

    //// LED control loop
    var delta = Date.now() - lastUpdateTime;
    if (acDelta > msPerFrame)
    {
        acDelta = 0;
        if(LEDloopON)
        {
                //LEDon = frame%2;
                LEDcont = 1;
                changeLED(LEDcont);
        }
        frame++;
        if (frame >= 2) {frame = 0;}
    } else
    {
        acDelta += delta;
    }
    lastUpdateTime = Date.now();
}

function drawCircles(xCenter,yCenter)
{
        var needle = new Vector2(max_val, 0);
        for(var i=0;i<24*3;i++)
        {
                c.beginPath();
                c.fillStyle = "rgba(255, 255, 255, 0.5)";
                c.lineWidth = 3;
                c.arc(xCenter + needle.x, yCenter + needle.y, 1, 0, Math.PI * 2, true);
                c.fill();
                needle.rotate(5,0);
        }
}

function givePointerType(event) {
    switch (event.pointerType) {
        case event.POINTER_TYPE_MOUSE:
            return "MOUSE";
            break;
        case event.POINTER_TYPE_PEN:
            return "PEN";
            break;
        case event.POINTER_TYPE_TOUCH:
            return "TOUCH";
            break;
    }
}

function onPointerDown(e) {
    var newPointer = { identifier: e.pointerId, x: e.clientX, y: e.clientY, type: givePointerType(e) };
    leftPointerID = e.pointerId;
    //leftPointerStartPos.reset(e.clientX, e.clientY);
    leftPointerStartPos.reset(halfWidth, halfHeight);
    leftPointerPos.copyFrom(leftPointerStartPos);
    leftVector.reset(0, 0);
    arrow.reset(0, 0, 0, 0);
    touches.add(e.pointerId, newPointer);
}

function onPointerMove(e) {
    if (leftPointerID == e.pointerId) {
        //leftPointerPos.reset(e.clientX, e.clientY);
        leftPointerPos.reset(e.offsetX, e.offsetY);
        leftVector.copyFrom(leftPointerPos);
        //leftVector.minusEq(leftPointerStartPos);
        leftVector.minusEq(leftPointerStartPos);
        arrow.setArrow(leftVector, max_val);
        LEDloopON = true;
    }
    else {
        if (touches.item(e.pointerId)) {
            touches.item(e.pointerId).x = e.clientX;
            touches.item(e.pointerId).y = e.clientY;
        }
    }
}

function onPointerUp(e) {
    if (leftPointerID == e.pointerId) {
        leftPointerID = -1;
        leftVector.reset(0, 0);
    }
    leftVector.reset(0, 0);
    arrow.reset(0, 0, 0, 0);
    touches.remove(e.pointerId);
    LEDloopON = false;
    changeLED(0);
}

function setupCanvas() {
    control_canvas = document.getElementById('controlCanvas');
    c = control_canvas.getContext('2d');
    resetCanvas();
    c.strokeStyle = "#ffffff";
    c.lineWidth = 2;
}

// Arduino control functions
function changeLED(LEDon) {
    if(LEDon)
    {
            led1.value = arrow.int1;
            led2.value = arrow.int2;
            led3.value = arrow.int3;
            led4.value = arrow.int4;
    }
    else
    {
            led1.value = 0;
            led2.value = 0;
            led3.value = 0;
            led4.value = 0;
        }
}

function resetCanvas(e) {
    max_val = (document.getElementById("controlArea").offsetWidth-100)/2;

    // resize the canvas - but remember - this clears the canvas too.

    control_canvas.width = document.getElementById("controlArea").offsetWidth-20;
    control_canvas.height = control_canvas.width-20;

    halfWidth = (control_canvas.width)/2;
    halfHeight = (control_canvas.height)/2;

    // make sure we scroll to the top left.
    window.scrollTo(0, 0);
}<|endoftext|>


<commit_before>const moment = require('moment');
const request = require('request-promise');
const argv = require('yargs').alias('staging', 's').alias('production', 'p').argv;

const apiId = process.env.LASERSHIP_API_ID;
const apiKey = process.env.LASERSHIP_API_KEY;
const testFlag = argv.s ? 1 : argv.p ? 0 : 1;

/**
 * Enum of key Lasership times (Critical Pull Time (CPT) and CPT +/- 1 hour).
 * All times are in UTC and relative to Brooklyn.
 * @param  {object} order The order object.
 * @return {object}       The Lasership time object.
 */
function lasershipTimes (order) {
  let lsTimeObject = [
    { label: 'expRFP', hrs: 20 },
    { label: 'cpt', hrs: 21 },
    { label: 'expDeparture', hrs: 22 }
  ];

  return lsTimeObject.reduce((obj, shipObj) => {
    let laserDate = new Date(order.ship_date);
    laserDate.setUTCHours(shipObj.hrs);
    obj[shipObj.label] = laserDate.toISOString().replace('.000Z', 'Z');
    return obj;
  }, {});
}

/**
 * Calculates the local delivery date and converts to UTC.
 * @param  {object} order    The order object.
 * @param  {string} datetime The UTC timestamp to convert.
 * @return {string}          The delivery date string.
 */
function localDeliveryDate (order, datetime) {
  return moment.utc(datetime.replace('Z', order.offset), moment.ISO_8601).add(order.tnt, 'days').format();
}

/**
 * Constructor function for creating Lasership order JSON.
 * @param       {object} order The order object.
 * @constructor
 */
function LasershipOrder (order) {
  let lsTimes = lasershipTimes(order);

  this.CustomerBranch = "CFDBRKLN";
  this.CustomerOrderNumber = order.sales_order;
  this.OrderedFor = order.contact_name;
  this.OrderedBy = {
    Name: "Chef'd",
    Phone: "3105311935",
    Email: "tech@chefd.com"
  };
  this.Reference1 = `${order.reference}: ${order.sales_order}`;
  this.Reference2 = `SHIP DATE: ${order.ship_date}`;
  this.ServiceCode = "RD";
  this.PickupType = "LaserShip";
  this.Origin = {
    LocationType: "Business",
    CustomerClientID: "",
    Contact: "Purple Carrot",
    Organization: "Purple Carrot",
    Address: "365 Ten Eyck St.",
    Address2: "",
    PostalCode: "11206",
    City: "BROOKLYN",
    State: "NY",
    Country: "US",
    Phone: "8577038188",
    PhoneExtension: "",
    Email: "tech@chefd.com",
    Payor: "",
    Instruction: "",
    Note: "",
    UTCExpectedReadyForPickupBy: lsTimes.expRFP,
    UTCExpectedDeparture: lsTimes.expDeparture,
    CustomerRoute: "",
    CustomerSequence: ""
  };
  this.Destination = {
    LocationType: "Residence",
    CustomerClientID: "",
    Contact: order.contact_name,
    Organization: order.company_name,
    Address: order.address_1,
    Address2: order.address_2,
    PostalCode: order.postal_code,
    City: order.city,
    State: order.state,
    Country: order.country,
    Phone: order.telephone,
    PhoneExtension: "",
    Email: "",
    Payor: "",
    Instruction: order.special_delivery_instructions,
    Note: "",
    UTCExpectedDeliveryBy: localDeliveryDate(order, lsTimes.cpt),
    CustomerRoute: "",
    CustomerSequence: ""
  };
  this.Pieces = [{
    ContainerType: "CustomPackaging",
    CustomerBarcode: "",
    CustomerPalletBarcode: "",
    Weight: order.weight,
    WeightUnit: "lbs",
    Width: 13,
    Length: 13,
    Height: 13,
    DimensionUnit: "in",
    Description: "Meal Kit",
    Reference: "",
    DeclaredValue: 65,
    DeclaredValueCurrency: "USD",
    SignatureType: "NotRequired",
    Attributes: [{
      Type: "Perishable",
      Description: ""
    }]
  }];
}

/**
 * Submits an order to Lasership API.
 * @param  {object} order The Lasership JSON order object.
 * @return {Promise}      Resolves with response data from a successful response
 * or rejects with response data from an erroneous response.
 */
function submitOrder (order) {
  order = new LasershipOrder(order);
  let endpoint = `https://api.lasership.com/Method/PlaceOrder/json/${apiId}/${apiKey}/${testFlag}/1/DN4x6`;
  let encodedOrder = encodeURIComponent(JSON.stringify(order));

  return request.post(endpoint).form({Order: encodedOrder});
}

module.exports = {
  submitOrder
};
<commit_msg>Fix company naming convention errors<commit_after>const moment = require('moment');
const request = require('request-promise');
const argv = require('yargs').alias('staging', 's').alias('production', 'p').argv;

const apiId = process.env.LASERSHIP_API_ID;
const apiKey = process.env.LASERSHIP_API_KEY;
const testFlag = argv.s ? 1 : argv.p ? 0 : 1;

/**
 * Enum of key Lasership times (Critical Pull Time (CPT) and CPT +/- 1 hour).
 * All times are in UTC and relative to Brooklyn.
 * @param  {object} order The order object.
 * @return {object}       The Lasership time object.
 */
function lasershipTimes (order) {
  let lsTimeObject = [
    { label: 'expRFP', hrs: 20 },
    { label: 'cpt', hrs: 21 },
    { label: 'expDeparture', hrs: 22 }
  ];

  return lsTimeObject.reduce((obj, shipObj) => {
    let laserDate = new Date(order.ship_date);
    laserDate.setUTCHours(shipObj.hrs);
    obj[shipObj.label] = laserDate.toISOString().replace('.000Z', 'Z');
    return obj;
  }, {});
}

/**
 * Calculates the local delivery date and converts to UTC.
 * @param  {object} order    The order object.
 * @param  {string} datetime The UTC timestamp to convert.
 * @return {string}          The delivery date string.
 */
function localDeliveryDate (order, datetime) {
  return moment.utc(datetime.replace('Z', order.offset), moment.ISO_8601).add(order.tnt, 'days').format();
}

/**
 * Constructor function for creating Lasership order JSON.
 * @param       {object} order The order object.
 * @constructor
 */
function LasershipOrder (order) {
  let lsTimes = lasershipTimes(order);

  this.CustomerBranch = "CFDBRKLN";
  this.CustomerOrderNumber = order.sales_order;
  this.OrderedFor = order.contact_name;
  this.OrderedBy = {
    Name: "Chef'd",
    Phone: "3105311935",
    Email: "tech@chefd.com"
  };
  this.Reference1 = `${order.reference}: ${order.sales_order}`;
  this.Reference2 = `SHIP DATE: ${order.ship_date}`;
  this.ServiceCode = "RD";
  this.PickupType = "LaserShip";
  this.Origin = {
    LocationType: "Business",
    CustomerClientID: "",
    Contact: "Purple Carrot",
    Organization: "Purple Carrot",
    Address: "365 Ten Eyck St.",
    Address2: "",
    PostalCode: "11206",
    City: "BROOKLYN",
    State: "NY",
    Country: "US",
    Phone: "8577038188",
    PhoneExtension: "",
    Email: "tech@chefd.com",
    Payor: "",
    Instruction: "",
    Note: "",
    UTCExpectedReadyForPickupBy: lsTimes.expRFP,
    UTCExpectedDeparture: lsTimes.expDeparture,
    CustomerRoute: "",
    CustomerSequence: ""
  };
  this.Destination = {
    LocationType: "Residence",
    CustomerClientID: "",
    Contact: order.contact_name,
    Organization: order.company_name || order.company,
    Address: order.address_1,
    Address2: order.address_2,
    PostalCode: order.postal_code,
    City: order.city,
    State: order.state,
    Country: order.country,
    Phone: order.telephone,
    PhoneExtension: "",
    Email: "",
    Payor: "",
    Instruction: order.special_delivery_instructions,
    Note: "",
    UTCExpectedDeliveryBy: localDeliveryDate(order, lsTimes.cpt),
    CustomerRoute: "",
    CustomerSequence: ""
  };
  this.Pieces = [{
    ContainerType: "CustomPackaging",
    CustomerBarcode: "",
    CustomerPalletBarcode: "",
    Weight: order.weight,
    WeightUnit: "lbs",
    Width: 13,
    Length: 13,
    Height: 13,
    DimensionUnit: "in",
    Description: "Meal Kit",
    Reference: "",
    DeclaredValue: 65,
    DeclaredValueCurrency: "USD",
    SignatureType: "NotRequired",
    Attributes: [{
      Type: "Perishable",
      Description: ""
    }]
  }];
}

/**
 * Submits an order to Lasership API.
 * @param  {object} order The Lasership JSON order object.
 * @return {Promise}      Resolves with response data from a successful response
 * or rejects with response data from an erroneous response.
 */
function submitOrder (order) {
  order = new LasershipOrder(order);
  let endpoint = `https://api.lasership.com/Method/PlaceOrder/json/${apiId}/${apiKey}/${testFlag}/1/DN4x6`;
  let encodedOrder = encodeURIComponent(JSON.stringify(order));

  return request.post(endpoint).form({Order: encodedOrder});
}

module.exports = {
  submitOrder
};
<|endoftext|>