<commit_before>'use strict';

var common              = require('./common');
var NIL                 = common.NIL;
var YAMLException       = require('./exception');
var DEFAULT_FULL_SCHEMA = require('./schema/default_full');
var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe');

var _hasOwnProperty = Object.prototype.hasOwnProperty;

var CHAR_TAB                  = 0x09; /* Tab */
var CHAR_LINE_FEED            = 0x0A; /* LF */
var CHAR_CARRIAGE_RETURN      = 0x0D; /* CR */
var CHAR_SPACE                = 0x20; /* Space */
var CHAR_EXCLAMATION          = 0x21; /* ! */
var CHAR_DOUBLE_QUOTE         = 0x22; /* " */
var CHAR_SHARP                = 0x23; /* # */
var CHAR_PERCENT              = 0x25; /* % */
var CHAR_AMPERSAND            = 0x26; /* & */
var CHAR_SINGLE_QUOTE         = 0x27; /* ' */
var CHAR_ASTERISK             = 0x2A; /* * */
var CHAR_COMMA                = 0x2C; /* , */
var CHAR_MINUS                = 0x2D; /* - */
var CHAR_COLON                = 0x3A; /* : */
var CHAR_GREATER_THAN         = 0x3E; /* > */
var CHAR_QUESTION             = 0x3F; /* ? */
var CHAR_COMMERCIAL_AT        = 0x40; /* @ */
var CHAR_LEFT_SQUARE_BRACKET  = 0x5B; /* [ */
var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */
var CHAR_GRAVE_ACCENT         = 0x60; /* ` */
var CHAR_LEFT_CURLY_BRACKET   = 0x7B; /* { */
var CHAR_VERTICAL_LINE        = 0x7C; /* | */
var CHAR_RIGHT_CURLY_BRACKET  = 0x7D; /* } */

var ESCAPE_SEQUENCES = {};

ESCAPE_SEQUENCES[0x00]   = '\\0';
ESCAPE_SEQUENCES[0x07]   = '\\a';
ESCAPE_SEQUENCES[0x08]   = '\\b';
ESCAPE_SEQUENCES[0x09]   = '\\t';
ESCAPE_SEQUENCES[0x0A]   = '\\n';
ESCAPE_SEQUENCES[0x0B]   = '\\v';
ESCAPE_SEQUENCES[0x0C]   = '\\f';
ESCAPE_SEQUENCES[0x0D]   = '\\r';
ESCAPE_SEQUENCES[0x1B]   = '\\e';
ESCAPE_SEQUENCES[0x22]   = '\\"';
ESCAPE_SEQUENCES[0x5C]   = '\\\\';
ESCAPE_SEQUENCES[0x85]   = '\\N';
ESCAPE_SEQUENCES[0xA0]   = '\\_';
ESCAPE_SEQUENCES[0x2028] = '\\L';
ESCAPE_SEQUENCES[0x2029] = '\\P';

function kindOf(object) {
  var kind = typeof object;

  if (null === object) {
    return 'null';
  } else if ('number' === kind) {
    return 0 === object % 1 ? 'integer' : 'float';
  } else if ('object' === kind && Array.isArray(object)) {
    return 'array';
  } else {
    return kind;
  }
}

function compileStyleMap(schema, map) {
  var result, keys, index, length, tag, style, type;

  if (null === map) {
    return {};
  }

  result = {};
  keys = Object.keys(map);

  for (index = 0, length = keys.length; index < length; index += 1) {
    tag = keys[index];
    style = String(map[tag]);

    if ('!!' === tag.slice(0, 2)) {
      tag = 'tag:yaml.org,2002:' + tag.slice(2);
    }

    type = schema.compiledTypeMap[tag];

    if (type && type.dumper) {
      if (_hasOwnProperty.call(type.dumper.styleAliases, style)) {
        style = type.dumper.styleAliases[style];
      }
    }

    result[tag] = style;
  }

  return result;
}

function encodeHex(character) {
  var string, handle, length;

  string = character.toString(16).toUpperCase();

  if (character <= 0xFF) {
    handle = 'x';
    length = 2;
  } else if (character <= 0xFFFF) {
    handle = 'u';
    length = 4;
  } else if (character <= 0xFFFFFFFF) {
    handle = 'U';
    length = 8;
  } else {
    throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF');
  }

  return '\\' + handle + common.repeat('0', length - string.length) + string;
}

function dump(input, options) {
  options = options || {};

  var schema      = options['schema'] || DEFAULT_FULL_SCHEMA,
      indent      = Math.max(1, (options['indent'] || 2)),
      skipInvalid = options['skipInvalid'] || false,
      flowLevel   = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']),
      styleMap    = compileStyleMap(schema, options['styles'] || null),

      implicitTypes = schema.compiledImplicit,
      explicitTypes = schema.compiledExplicit,

      kind,
      tag,
      result;

  function generateNextLine(level) {
    return '\n' + common.repeat(' ', indent * level);
  }

  function testImplicitResolving(object) {
    var index, length, type;

    for (index = 0, length = implicitTypes.length; index < length; index += 1) {
      type = implicitTypes[index];

      if (null !== type.loader &&
          NIL !== type.loader.resolver(object, false)) {
        return true;
      }
    }

    return false;
  }

  function writeScalar(object) {
    var isQuoted, checkpoint, position, length, character;

    result = '';
    isQuoted = false;
    checkpoint = 0;

    if (0          === object.length ||
        CHAR_SPACE === object.charCodeAt(0) ||
        CHAR_SPACE === object.charCodeAt(object.length - 1)) {
      isQuoted = true;
    }

    for (position = 0, length = object.length; position < length; position += 1) {
      character = object.charCodeAt(position);

      if (!isQuoted) {
        if (CHAR_TAB                  === character ||
            CHAR_LINE_FEED            === character ||
            CHAR_CARRIAGE_RETURN      === character ||
            CHAR_COMMA                === character ||
            CHAR_LEFT_SQUARE_BRACKET  === character ||
            CHAR_RIGHT_SQUARE_BRACKET === character ||
            CHAR_LEFT_CURLY_BRACKET   === character ||
            CHAR_RIGHT_CURLY_BRACKET  === character ||
            CHAR_SHARP                === character ||
            CHAR_AMPERSAND            === character ||
            CHAR_ASTERISK             === character ||
            CHAR_EXCLAMATION          === character ||
            CHAR_VERTICAL_LINE        === character ||
            CHAR_GREATER_THAN         === character ||
            CHAR_SINGLE_QUOTE         === character ||
            CHAR_DOUBLE_QUOTE         === character ||
            CHAR_PERCENT              === character ||
            CHAR_COMMERCIAL_AT        === character ||
            CHAR_GRAVE_ACCENT         === character ||
            CHAR_QUESTION             === character ||
            CHAR_COLON                === character ||
            CHAR_MINUS                === character) {
          isQuoted = true;
        }
      }

      if (ESCAPE_SEQUENCES[character] ||
          !((0x00020 <= character && character <= 0x00007E) ||
            (0x00085 === character)                         ||
            (0x000A0 <= character && character <= 0x00D7FF) ||
            (0x0E000 <= character && character <= 0x00FFFD) ||
            (0x10000 <= character && character <= 0x10FFFF))) {
        result += object.slice(checkpoint, position);
        result += ESCAPE_SEQUENCES[character] || encodeHex(character);
        checkpoint = position + 1;
        isQuoted = true;
      }
    }

    if (checkpoint < position) {
      result += object.slice(checkpoint, position);
    }

    if (!isQuoted && testImplicitResolving(result)) {
      isQuoted = true;
    }

    if (isQuoted) {
      result = '"' + result + '"';
    }
  }

  function writeFlowSequence(level, object) {
    var _result = '',
        _tag    = tag,
        index,
        length;

    for (index = 0, length = object.length; index < length; index += 1) {
      // Write only valid elements.
      if (writeNode(level, object[index], false, false)) {
        if (0 !== index) {
          _result += ', ';
        }
        _result += result;
      }
    }

    tag = _tag;
    result = '[' + _result + ']';
  }

  function writeBlockSequence(level, object, compact) {
    var _result = '',
        _tag    = tag,
        index,
        length;

    for (index = 0, length = object.length; index < length; index += 1) {
      // Write only valid elements.
      if (writeNode(level + 1, object[index], true, true)) {
        if (!compact || 0 !== index) {
          _result += generateNextLine(level);
        }
        _result += '- ' + result;
      }
    }

    tag = _tag;
    result = _result || '[]'; // Empty sequence if no valid values.
  }

  function writeFlowMapping(level, object) {
    var _result       = '',
        _tag          = tag,
        objectKeyList = Object.keys(object),
        index,
        length,
        objectKey,
        objectValue,
        pairBuffer;

    for (index = 0, length = objectKeyList.length; index < length; index += 1) {
      pairBuffer = '';

      if (0 !== index) {
        pairBuffer += ', ';
      }

      objectKey = objectKeyList[index];
      objectValue = object[objectKey];

      if (!writeNode(level, objectKey, false, false)) {
        continue; // Skip this pair because of invalid key;
      }

      if (result.length > 1024) {
        pairBuffer += '? ';
      }

      pairBuffer += result + ': ';

      if (!writeNode(level, objectValue, false, false)) {
        continue; // Skip this pair because of invalid value.
      }

      pairBuffer += result;

      // Both key and value are valid.
      _result += pairBuffer;
    }

    tag = _tag;
    result = '{' + _result + '}';
  }

  function writeBlockMapping(level, object, compact) {
    var _result       = '',
        _tag          = tag,
        objectKeyList = Object.keys(object),
        index,
        length,
        objectKey,
        objectValue,
        explicitPair,
        pairBuffer;

    for (index = 0, length = objectKeyList.length; index < length; index += 1) {
      pairBuffer = '';

      if (!compact || 0 !== index) {
        pairBuffer += generateNextLine(level);
      }

      objectKey = objectKeyList[index];
      objectValue = object[objectKey];

      if (!writeNode(level + 1, objectKey, true, true)) {
        continue; // Skip this pair because of invalid key.
      }

      explicitPair = (null !== tag && '?' !== tag && result.length <= 1024);

      if (explicitPair) {
        pairBuffer += '? ';
      }

      pairBuffer += result;

      if (explicitPair) {
        pairBuffer += generateNextLine(level);
      }

      if (!writeNode(level + 1, objectValue, true, explicitPair)) {
        continue; // Skip this pair because of invalid value.
      }

      pairBuffer += ': ' + result;

      // Both key and value are valid.
      _result += pairBuffer;
    }

    tag = _tag;
    result = _result || '{}'; // Empty mapping if no valid pairs.
  }

  function detectType(object, explicit) {
    var _result, typeList, index, length, type, style;

    typeList = explicit ? explicitTypes : implicitTypes;
    kind = kindOf(object);

    for (index = 0, length = typeList.length; index < length; index += 1) {
      type = typeList[index];

      if ((null !== type.dumper) &&
          (null === type.dumper.kind       || kind === type.dumper.kind) &&
          (null === type.dumper.instanceOf || object instanceof type.dumper.instanceOf) &&
          (null === type.dumper.predicate  || type.dumper.predicate(object))) {
        tag = explicit ? type.tag : '?';

        if (null !== type.dumper.representer) {
          style = styleMap[type.tag] || type.dumper.defaultStyle;

          if ('function' === typeof type.dumper.representer) {
            _result = type.dumper.representer(object, style);
          } else if (_hasOwnProperty.call(type.dumper.representer, style)) {
            _result = type.dumper.representer[style](object, style);
          } else {
            throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style');
          }

          if (NIL !== _result) {
            kind = kindOf(_result);
            result = _result;
          } else {
            if (explicit) {
              throw new YAMLException('cannot represent an object of !<' + type.tag + '> type');
            } else {
              continue;
            }
          }
        }

        return true;
      }
    }

    return false;
  }

  // Serializes `object` and writes it to global `result`.
  // Returns true on success, or false on invalid object.
  //
  function writeNode(level, object, block, compact) {
    tag = null;
    result = object;

    if (!detectType(object, false)) {
      detectType(object, true);
    }

    if (block) {
      block = (0 > flowLevel || flowLevel > level);
    }

    if ((null !== tag && '?' !== tag) || (2 !== indent && level > 0)) {
      compact = false;
    }

    if ('object' === kind) {
      if (block && (0 !== Object.keys(result).length)) {
        writeBlockMapping(level, result, compact);
      } else {
        writeFlowMapping(level, result);
      }
    } else if ('array' === kind) {
      if (block && (0 !== result.length)) {
        writeBlockSequence(level, result, compact);
      } else {
        writeFlowSequence(level, result);
      }
    } else if ('string' === kind) {
      if ('?' !== tag) {
        writeScalar(result);
      }
    } else if (skipInvalid) {
      return false;
    } else {
      throw new YAMLException('unacceptabe kind of an object to dump (' + kind + ')');
    }

    if (null !== tag && '?' !== tag) {
      result = '!<' + tag + '> ' + result;
    }
    return true;
  }

  if (writeNode(0, input, true, true)) {
    return result + '\n';
  } else {
    return '';
  }
}

function safeDump(input, options) {
  return dump(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options));
}

module.exports.dump     = dump;
module.exports.safeDump = safeDump;
<commit_msg>Quote boolean values when dumping strings<commit_after>'use strict';

var common              = require('./common');
var NIL                 = common.NIL;
var YAMLException       = require('./exception');
var DEFAULT_FULL_SCHEMA = require('./schema/default_full');
var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe');

var _hasOwnProperty = Object.prototype.hasOwnProperty;

var CHAR_TAB                  = 0x09; /* Tab */
var CHAR_LINE_FEED            = 0x0A; /* LF */
var CHAR_CARRIAGE_RETURN      = 0x0D; /* CR */
var CHAR_SPACE                = 0x20; /* Space */
var CHAR_EXCLAMATION          = 0x21; /* ! */
var CHAR_DOUBLE_QUOTE         = 0x22; /* " */
var CHAR_SHARP                = 0x23; /* # */
var CHAR_PERCENT              = 0x25; /* % */
var CHAR_AMPERSAND            = 0x26; /* & */
var CHAR_SINGLE_QUOTE         = 0x27; /* ' */
var CHAR_ASTERISK             = 0x2A; /* * */
var CHAR_COMMA                = 0x2C; /* , */
var CHAR_MINUS                = 0x2D; /* - */
var CHAR_COLON                = 0x3A; /* : */
var CHAR_GREATER_THAN         = 0x3E; /* > */
var CHAR_QUESTION             = 0x3F; /* ? */
var CHAR_COMMERCIAL_AT        = 0x40; /* @ */
var CHAR_LEFT_SQUARE_BRACKET  = 0x5B; /* [ */
var CHAR_RIGHT_SQUARE_BRACKET = 0x5D; /* ] */
var CHAR_GRAVE_ACCENT         = 0x60; /* ` */
var CHAR_LEFT_CURLY_BRACKET   = 0x7B; /* { */
var CHAR_VERTICAL_LINE        = 0x7C; /* | */
var CHAR_RIGHT_CURLY_BRACKET  = 0x7D; /* } */

var ESCAPE_SEQUENCES = {};

ESCAPE_SEQUENCES[0x00]   = '\\0';
ESCAPE_SEQUENCES[0x07]   = '\\a';
ESCAPE_SEQUENCES[0x08]   = '\\b';
ESCAPE_SEQUENCES[0x09]   = '\\t';
ESCAPE_SEQUENCES[0x0A]   = '\\n';
ESCAPE_SEQUENCES[0x0B]   = '\\v';
ESCAPE_SEQUENCES[0x0C]   = '\\f';
ESCAPE_SEQUENCES[0x0D]   = '\\r';
ESCAPE_SEQUENCES[0x1B]   = '\\e';
ESCAPE_SEQUENCES[0x22]   = '\\"';
ESCAPE_SEQUENCES[0x5C]   = '\\\\';
ESCAPE_SEQUENCES[0x85]   = '\\N';
ESCAPE_SEQUENCES[0xA0]   = '\\_';
ESCAPE_SEQUENCES[0x2028] = '\\L';
ESCAPE_SEQUENCES[0x2029] = '\\P';

function kindOf(object) {
  var kind = typeof object;

  if (null === object) {
    return 'null';
  } else if ('number' === kind) {
    return 0 === object % 1 ? 'integer' : 'float';
  } else if ('object' === kind && Array.isArray(object)) {
    return 'array';
  } else {
    return kind;
  }
}

function compileStyleMap(schema, map) {
  var result, keys, index, length, tag, style, type;

  if (null === map) {
    return {};
  }

  result = {};
  keys = Object.keys(map);

  for (index = 0, length = keys.length; index < length; index += 1) {
    tag = keys[index];
    style = String(map[tag]);

    if ('!!' === tag.slice(0, 2)) {
      tag = 'tag:yaml.org,2002:' + tag.slice(2);
    }

    type = schema.compiledTypeMap[tag];

    if (type && type.dumper) {
      if (_hasOwnProperty.call(type.dumper.styleAliases, style)) {
        style = type.dumper.styleAliases[style];
      }
    }

    result[tag] = style;
  }

  return result;
}

function encodeHex(character) {
  var string, handle, length;

  string = character.toString(16).toUpperCase();

  if (character <= 0xFF) {
    handle = 'x';
    length = 2;
  } else if (character <= 0xFFFF) {
    handle = 'u';
    length = 4;
  } else if (character <= 0xFFFFFFFF) {
    handle = 'U';
    length = 8;
  } else {
    throw new YAMLException('code point within a string may not be greater than 0xFFFFFFFF');
  }

  return '\\' + handle + common.repeat('0', length - string.length) + string;
}

function dump(input, options) {
  options = options || {};

  var schema      = options['schema'] || DEFAULT_FULL_SCHEMA,
      indent      = Math.max(1, (options['indent'] || 2)),
      skipInvalid = options['skipInvalid'] || false,
      flowLevel   = (common.isNothing(options['flowLevel']) ? -1 : options['flowLevel']),
      styleMap    = compileStyleMap(schema, options['styles'] || null),

      implicitTypes = schema.compiledImplicit,
      explicitTypes = schema.compiledExplicit,

      kind,
      tag,
      result;

  function generateNextLine(level) {
    return '\n' + common.repeat(' ', indent * level);
  }

  function testImplicitResolving(object) {
    var index, length, type;

    for (index = 0, length = implicitTypes.length; index < length; index += 1) {
      type = implicitTypes[index];

      if (null !== type.loader &&
          NIL !== type.loader.resolver(object, false)) {
        return true;
      }
    }

    return false;
  }

  function writeScalar(object) {
    var isQuoted, checkpoint, position, length, character, booleans;

    result = '';
    isQuoted = false;
    checkpoint = 0;
    booleans = /^(y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)$/;

    if (0          === object.length ||
        CHAR_SPACE === object.charCodeAt(0) ||
        CHAR_SPACE === object.charCodeAt(object.length - 1)) {
      isQuoted = true;
    }

    for (position = 0, length = object.length; position < length; position += 1) {
      character = object.charCodeAt(position);

      if (!isQuoted) {
        if (CHAR_TAB                  === character ||
            CHAR_LINE_FEED            === character ||
            CHAR_CARRIAGE_RETURN      === character ||
            CHAR_COMMA                === character ||
            CHAR_LEFT_SQUARE_BRACKET  === character ||
            CHAR_RIGHT_SQUARE_BRACKET === character ||
            CHAR_LEFT_CURLY_BRACKET   === character ||
            CHAR_RIGHT_CURLY_BRACKET  === character ||
            CHAR_SHARP                === character ||
            CHAR_AMPERSAND            === character ||
            CHAR_ASTERISK             === character ||
            CHAR_EXCLAMATION          === character ||
            CHAR_VERTICAL_LINE        === character ||
            CHAR_GREATER_THAN         === character ||
            CHAR_SINGLE_QUOTE         === character ||
            CHAR_DOUBLE_QUOTE         === character ||
            CHAR_PERCENT              === character ||
            CHAR_COMMERCIAL_AT        === character ||
            CHAR_GRAVE_ACCENT         === character ||
            CHAR_QUESTION             === character ||
            CHAR_COLON                === character ||
            CHAR_MINUS                === character) {
          isQuoted = true;
        }
      }

      if (ESCAPE_SEQUENCES[character] ||
          !((0x00020 <= character && character <= 0x00007E) ||
            (0x00085 === character)                         ||
            (0x000A0 <= character && character <= 0x00D7FF) ||
            (0x0E000 <= character && character <= 0x00FFFD) ||
            (0x10000 <= character && character <= 0x10FFFF))) {
        result += object.slice(checkpoint, position);
        result += ESCAPE_SEQUENCES[character] || encodeHex(character);
        checkpoint = position + 1;
        isQuoted = true;
      }
    }

    if (checkpoint < position) {
      result += object.slice(checkpoint, position);
    }

    if (!isQuoted && testImplicitResolving(result)) {
      isQuoted = true;
    }

    if (!isQuoted && booleans.test(object)) {
      isQuoted = true;
    }

    if (isQuoted) {
      result = '"' + result + '"';
    }
  }

  function writeFlowSequence(level, object) {
    var _result = '',
        _tag    = tag,
        index,
        length;

    for (index = 0, length = object.length; index < length; index += 1) {
      // Write only valid elements.
      if (writeNode(level, object[index], false, false)) {
        if (0 !== index) {
          _result += ', ';
        }
        _result += result;
      }
    }

    tag = _tag;
    result = '[' + _result + ']';
  }

  function writeBlockSequence(level, object, compact) {
    var _result = '',
        _tag    = tag,
        index,
        length;

    for (index = 0, length = object.length; index < length; index += 1) {
      // Write only valid elements.
      if (writeNode(level + 1, object[index], true, true)) {
        if (!compact || 0 !== index) {
          _result += generateNextLine(level);
        }
        _result += '- ' + result;
      }
    }

    tag = _tag;
    result = _result || '[]'; // Empty sequence if no valid values.
  }

  function writeFlowMapping(level, object) {
    var _result       = '',
        _tag          = tag,
        objectKeyList = Object.keys(object),
        index,
        length,
        objectKey,
        objectValue,
        pairBuffer;

    for (index = 0, length = objectKeyList.length; index < length; index += 1) {
      pairBuffer = '';

      if (0 !== index) {
        pairBuffer += ', ';
      }

      objectKey = objectKeyList[index];
      objectValue = object[objectKey];

      if (!writeNode(level, objectKey, false, false)) {
        continue; // Skip this pair because of invalid key;
      }

      if (result.length > 1024) {
        pairBuffer += '? ';
      }

      pairBuffer += result + ': ';

      if (!writeNode(level, objectValue, false, false)) {
        continue; // Skip this pair because of invalid value.
      }

      pairBuffer += result;

      // Both key and value are valid.
      _result += pairBuffer;
    }

    tag = _tag;
    result = '{' + _result + '}';
  }

  function writeBlockMapping(level, object, compact) {
    var _result       = '',
        _tag          = tag,
        objectKeyList = Object.keys(object),
        index,
        length,
        objectKey,
        objectValue,
        explicitPair,
        pairBuffer;

    for (index = 0, length = objectKeyList.length; index < length; index += 1) {
      pairBuffer = '';

      if (!compact || 0 !== index) {
        pairBuffer += generateNextLine(level);
      }

      objectKey = objectKeyList[index];
      objectValue = object[objectKey];

      if (!writeNode(level + 1, objectKey, true, true)) {
        continue; // Skip this pair because of invalid key.
      }

      explicitPair = (null !== tag && '?' !== tag && result.length <= 1024);

      if (explicitPair) {
        pairBuffer += '? ';
      }

      pairBuffer += result;

      if (explicitPair) {
        pairBuffer += generateNextLine(level);
      }

      if (!writeNode(level + 1, objectValue, true, explicitPair)) {
        continue; // Skip this pair because of invalid value.
      }

      pairBuffer += ': ' + result;

      // Both key and value are valid.
      _result += pairBuffer;
    }

    tag = _tag;
    result = _result || '{}'; // Empty mapping if no valid pairs.
  }

  function detectType(object, explicit) {
    var _result, typeList, index, length, type, style;

    typeList = explicit ? explicitTypes : implicitTypes;
    kind = kindOf(object);

    for (index = 0, length = typeList.length; index < length; index += 1) {
      type = typeList[index];

      if ((null !== type.dumper) &&
          (null === type.dumper.kind       || kind === type.dumper.kind) &&
          (null === type.dumper.instanceOf || object instanceof type.dumper.instanceOf) &&
          (null === type.dumper.predicate  || type.dumper.predicate(object))) {
        tag = explicit ? type.tag : '?';

        if (null !== type.dumper.representer) {
          style = styleMap[type.tag] || type.dumper.defaultStyle;

          if ('function' === typeof type.dumper.representer) {
            _result = type.dumper.representer(object, style);
          } else if (_hasOwnProperty.call(type.dumper.representer, style)) {
            _result = type.dumper.representer[style](object, style);
          } else {
            throw new YAMLException('!<' + type.tag + '> tag resolver accepts not "' + style + '" style');
          }

          if (NIL !== _result) {
            kind = kindOf(_result);
            result = _result;
          } else {
            if (explicit) {
              throw new YAMLException('cannot represent an object of !<' + type.tag + '> type');
            } else {
              continue;
            }
          }
        }

        return true;
      }
    }

    return false;
  }

  // Serializes `object` and writes it to global `result`.
  // Returns true on success, or false on invalid object.
  //
  function writeNode(level, object, block, compact) {
    tag = null;
    result = object;

    if (!detectType(object, false)) {
      detectType(object, true);
    }

    if (block) {
      block = (0 > flowLevel || flowLevel > level);
    }

    if ((null !== tag && '?' !== tag) || (2 !== indent && level > 0)) {
      compact = false;
    }

    if ('object' === kind) {
      if (block && (0 !== Object.keys(result).length)) {
        writeBlockMapping(level, result, compact);
      } else {
        writeFlowMapping(level, result);
      }
    } else if ('array' === kind) {
      if (block && (0 !== result.length)) {
        writeBlockSequence(level, result, compact);
      } else {
        writeFlowSequence(level, result);
      }
    } else if ('string' === kind) {
      if ('?' !== tag) {
        writeScalar(result);
      }
    } else if (skipInvalid) {
      return false;
    } else {
      throw new YAMLException('unacceptabe kind of an object to dump (' + kind + ')');
    }

    if (null !== tag && '?' !== tag) {
      result = '!<' + tag + '> ' + result;
    }
    return true;
  }

  if (writeNode(0, input, true, true)) {
    return result + '\n';
  } else {
    return '';
  }
}

function safeDump(input, options) {
  return dump(input, common.extend({ schema: DEFAULT_SAFE_SCHEMA }, options));
}

module.exports.dump     = dump;
module.exports.safeDump = safeDump;
<|endoftext|>


<commit_before>
node.Rule = function Rule(name, value) {
    this.name = name;
    this.value = value;

    if (name.charAt(0) === '@') {
        require('sys').puts('NEW VAR, value:' + require('sys').inspect(value))
        this.variable = true;
    } else { this.variable = false }
};
node.Rule.prototype.toCSS = function (env) {
    return this.name + ": " + (this.value.toCSS ? this.value.toCSS(env) : this.value) + ";";
};

node.Value = function Value(value) {
    this.value = value;
    this.is = 'value';
};
node.Value.prototype.eval = function (env) {
    if (this.value.length === 1) {
        return this.value[0].eval(env);
    } else {
        throw new(Error)("trying to evaluate compound value");
    }
};
node.Value.prototype.toCSS = function (env) {
    return this.value.map(function (e) {
        return e.toCSS ? e.toCSS(env) : e;
    }).join(', ');
};

<commit_msg>removed trace code from rule.js<commit_after>
node.Rule = function Rule(name, value) {
    this.name = name;
    this.value = value;

    if (name.charAt(0) === '@') {
        this.variable = true;
    } else { this.variable = false }
};
node.Rule.prototype.toCSS = function (env) {
    return this.name + ": " + (this.value.toCSS ? this.value.toCSS(env) : this.value) + ";";
};

node.Value = function Value(value) {
    this.value = value;
    this.is = 'value';
};
node.Value.prototype.eval = function (env) {
    if (this.value.length === 1) {
        return this.value[0].eval(env);
    } else {
        throw new(Error)("trying to evaluate compound value");
    }
};
node.Value.prototype.toCSS = function (env) {
    return this.value.map(function (e) {
        return e.toCSS ? e.toCSS(env) : e;
    }).join(', ');
};

<|endoftext|>


<commit_before>/* globals assert */

const temp = require('temp').track()
const season = require('season')
const dedent = require('dedent')
const electron = require('electron')
const fs = require('fs-plus')
const path = require('path')
const AtomApplication = require('../../src/main-process/atom-application')
const parseCommandLine = require('../../src/main-process/parse-command-line')
const {emitterEventPromise} = require('../async-spec-helpers')

describe('AtomApplication', function () {
  this.timeout(60 * 1000)
  let scenario

  beforeEach(async function () {
    scenario = await LaunchScenario.create()
  })

  afterEach(async function () {
    await scenario.destroy()
  })

  describe('command-line interface behavior', function () {
    describe('with no open windows', function () {
      it('opens a file', async function () {
        await scenario.launch(parseCommandLine(['a/1.md']))
        await scenario.assert('[_ 1.md]')
      })

      it('opens a directory', async function () {
        await scenario.launch(parseCommandLine(['a']))
        await scenario.assert('[a _]')
      })

      it('opens a file with --add', async function () {
        await scenario.launch(parseCommandLine(['--add', 'a/1.md']))
        await scenario.assert('[_ 1.md]')
      })

      it('opens a directory with --add', async function () {
        await scenario.launch(parseCommandLine(['--add', 'a']))
        await scenario.assert('[a _]')
      })

      it('opens a file with --new-window', async function () {
        await scenario.launch(parseCommandLine(['--new-window', 'a/1.md']))
        await scenario.assert('[_ 1.md]')
      })

      it('opens a directory with --new-window', async function () {
        await scenario.launch(parseCommandLine(['--new-window', 'a']))
        await scenario.assert('[a _]')
      })

      it('opens a directory with --new-window', async function () {
        await scenario.launch(parseCommandLine(['--new-window', 'a']))
      })
    })
  })
})

let channelIdCounter = 0

class LaunchScenario {
  static async create () {
    const scenario = new this()
    await scenario.init()
    return scenario
  }

  constructor () {
    this.applications = new Set()
    this.windows = new Set()
    this.root = null
    this.atomHome = null
    this.projectRootPool = new Map()
    this.filePathPool = new Map()

    this.originalAtomHome = process.env.ATOM_HOME
  }

  async init () {
    if (this.root !== null) {
      return this.root
    }

    await this.clearElectronSession()

    this.root = await new Promise((resolve, reject) => {
      temp.mkdir('launch-', (err, rootPath) => {
        if (err) { reject(err) } else { resolve(rootPath) }
      })
    })

    this.atomHome = path.join(this.root, '.atom')
    process.env.ATOM_HOME = this.atomHome
    await new Promise((resolve, reject) => {
      season.writeFile(path.join(this.atomHome, 'config.cson'), {
        '*': {
          welcome: { showOnStartup: false },
          core: { telemetryConsent: 'no', automaticallyUpdate: false }
        }
      }, err => {
        if (err) { reject(err) } else { resolve() }
      })
    })

    await new Promise((resolve, reject) => {
      // Symlinking the compile cache into the temporary home dir makes the windows load much faster
      fs.symlink(
        path.join(this.originalAtomHome, 'compile-cache'),
        path.join(this.atomHome, 'compile-cache'),
        'junction',
        err => {
          if (err) { reject(err) } else { resolve() }
        }
      )
    })

    await Promise.all(
      ['a', 'b'].map(dirPath => new Promise((resolve, reject) => {
        const fullDirPath = path.join(this.root, dirPath)
        fs.makeTree(fullDirPath, err => {
          if (err) {
            reject(err)
          } else {
            this.projectRootPool.set(dirPath, fullDirPath)
            resolve()
          }
        })
      }))
    )

    await Promise.all(
      ['a/1.md', 'b/2.md'].map(filePath => new Promise((resolve, reject) => {
        const fullFilePath = path.join(this.root, filePath)
        fs.writeFile(fullFilePath, `file: ${filePath}\n`, {encoding: 'utf8'}, err => {
          if (err) {
            reject(err)
          } else {
            this.filePathPool.set(filePath, fullFilePath)
            this.filePathPool.set(path.basename(filePath), fullFilePath)
            resolve()
          }
        })
      }))
    )
  }

  async preconditions (source) {
    const app = this.addApplication()
    const windowPromises = []
    for (const windowSpec of this.parseWindowSpecs(source)) {
      const expectOpenEvent = windowSpec.roots.length > 0 || windowSpec.editors.length > 0

      if (windowSpec.editors.length === 0) {
        windowSpec.editors.push(null)
      }

      windowPromises.push((async (theApp, foldersToOpen, pathsToOpen) => {
        const window = await theApp.openPaths({ newWindow: true, foldersToOpen, pathsToOpen })
        if (expectOpenEvent) {
          await emitterEventPromise(window, 'window:locations-opened')
        }
        return window
      })(app, windowSpec.roots, windowSpec.editors))
    }
    for (const window of await Promise.all(windowPromises)) {
      this.windows.add(window)
    }
  }

  async launch (options) {
    const app = this.addApplication()
    if (options.pathsToOpen) {
      options.pathsToOpen = this.convertPaths(options.pathsToOpen)
    }

    const windows = await app.launch(options)
    const openedPromises = []
    for (const window of windows) {
      this.windows.add(window)
      openedPromises.push(emitterEventPromise(window, 'window:locations-opened'))
    }
    await Promise.all(openedPromises)
    return windows
  }

  async open (options) {
    if (this.applications.size === 0) {
      return this.launch(options)
    }

    let app = options.app
    if (!app) {
      const apps = Array.from(this.applications)
      app = apps[apps.length - 1]
    } else {
      delete options.app
    }

    if (options.pathsToOpen) {
      options.pathsToOpen = this.convertPaths(options.pathsToOpen)
    }

    const window = await app.openWithOptions(options)
    this.windows.add(window)
    await emitterEventPromise(window, 'window:locations-opened')
    return window
  }

  async assert (source) {
    const windowSpecs = this.parseWindowSpecs(source)
    let specIndex = 0

    const windowPromises = []
    for (const window of this.windows) {
      windowPromises.push((async (theWindow, theSpec) => {
        const [rootPaths, editorPaths] = await Promise.all([
          this.getProjectRoots(theWindow),
          this.getOpenEditors(theWindow)
        ])

        const comparison = {
          ok: true,
          extraWindow: false,
          missingWindow: false,
          extraRoots: [],
          missingRoots: [],
          extraEditors: [],
          missingEditors: []
        }

        if (!theSpec) {
          comparison.ok = false
          comparison.extraWindow = true
          comparison.extraRoots = rootPaths
          comparison.extraEditors = editorPaths
        } else {
          const [missingRoots, extraRoots] = this.compareSets(theSpec.roots, rootPaths)
          const [missingEditors, extraEditors] = this.compareSets(theSpec.editors, editorPaths)

          comparison.ok = missingRoots.length === 0 &&
            extraRoots.length === 0 &&
            missingEditors.length === 0 &&
            extraEditors.length === 0
          comparison.extraRoots = extraRoots
          comparison.missingRoots = missingRoots
          comparison.extraEditors = extraEditors
          comparison.missingEditors = missingEditors
        }

        return comparison
      })(window, windowSpecs[specIndex++]))
    }

    const comparisons = await Promise.all(windowPromises)
    for (; specIndex < windowSpecs.length; specIndex++) {
      const spec = windowSpecs[specIndex]
      comparisons.push({
        ok: false,
        extraWindow: false,
        missingWindow: true,
        extraRoots: [],
        missingRoots: spec.roots,
        extraEditors: [],
        missingEditors: spec.editors
      })
    }

    const descriptionParts = []
    for (const comparison of comparisons) {
      if (comparison.ok) {
        continue
      }

      let parts = []
      if (comparison.extraWindow) {
        parts.push('extra window\n')
      } else if (comparison.missingWindow) {
        parts.push('missing window\n')
      }

      const shorten = fullPaths => fullPaths.map(fullPath => path.basename(fullPath)).join(', ')

      if (comparison.extraRoots.length > 0) {
        parts.push(`* extra roots ${shorten(comparison.extraRoots)}\n`)
      }
      if (comparison.missingRoots.length > 0) {
        parts.push(`* missing roots ${shorten(comparison.missingRoots)}\n`)
      }
      if (comparison.extraEditors.length > 0) {
        parts.push(`* extra editors ${shorten(comparison.extraEditors)}\n`)
      }
      if (comparison.missingEditors.length > 0) {
        parts.push(`* missing editors ${shorten(comparison.missingEditors)}\n`)
      }

      if (descriptionParts.length === 0) {
        descriptionParts.push('Launched windows did not match spec\n')
      }
      descriptionParts.push(parts.join(''))
    }

    assert.isTrue(descriptionParts.length === 0, descriptionParts.join(''))
  }

  async destroy () {
    await Promise.all(
      Array.from(this.applications, app => app.destroy())
    )
    await this.clearElectronSession()

    process.env.ATOM_HOME = this.originalAtomHome
  }

  addApplication (options = {}) {
    const app = new AtomApplication({
      resourcePath: path.resolve(__dirname, '../..'),
      atomHomeDirPath: this.atomHome,
      ...options
    })
    this.applications.add(app)
    return app
  }

  getApplication (index) {
    const app = Array.from(this.applications)[index]
    if (!app) {
      throw new Error(`Application ${index} does not exist`)
    }
    return app
  }

  getWindow (index) {
    const window = Array.from(this.windows)[index]
    if (!window) {
      throw new Error(`Window ${index} does not exist`)
    }
    return window
  }

  getProjectRoots (window) {
    return this.evalInWebContents(window.browserWindow.webContents, reply => reply(atom.project.getPaths()))
  }

  getOpenEditors (window) {
    return this.evalInWebContents(window.browserWindow.webContents, reply => {
      reply(atom.workspace.getTextEditors().map(editor => editor.getPath()).filter(Boolean))
    })
  }

  evalInWebContents (webContents, source, ...args) {
    const channelId = `eval-result-${channelIdCounter++}`
    return new Promise(resolve => {
      electron.ipcMain.on(channelId, receiveResult)

      function receiveResult (_event, result) {
        electron.ipcMain.removeListener('eval-result', receiveResult)
        resolve(result)
      }

      const js = dedent`
        function sendBackToMainProcess (result) {
          require('electron').ipcRenderer.send('${channelId}', result)
        }
        (${source})(sendBackToMainProcess, ${args.map(JSON.stringify).join(', ')})
      `
      webContents.executeJavaScript(js)
    })
  }

  clearElectronSession () {
    return new Promise(resolve => {
      electron.session.defaultSession.clearStorageData(() => {
        // Resolve promise on next tick, otherwise the process stalls. This
        // might be a bug in Electron, but it's probably fixed on the newer
        // versions.
        process.nextTick(resolve)
      })
    })
  }

  compareSets (expected, actual) {
    const expectedItems = new Set(expected)
    const extra = []
    const missing = []

    for (const actualItem of actual) {
      if (!expectedItems.delete(actualItem)) {
        // actualItem was present, but not expected
        extra.push(actualItem)
      }
    }
    for (const remainingItem of expectedItems) {
      // remainingItem was expected, but not present
      missing.push(remainingItem)
    }
    return [missing, extra]
  }

  convertRootPath (shortRootPath) {
    const fullRootPath = this.projectRootPool.get(shortRootPath)
    if (!fullRootPath) {
      throw new Error(`Unexpected short project root path: ${shortRootPath}`)
    }
    return fullRootPath
  }

  convertEditorPath (shortEditorPath) {
    const fullEditorPath = this.filePathPool.get(shortEditorPath)
    if (!fullEditorPath) {
      throw new Error(`Unexpected short editor path: ${shortEditorPath}`)
    }
    return fullEditorPath
  }

  convertPaths (paths) {
    return paths.map(shortPath => {
      const fullRoot = this.projectRootPool.get(shortPath)
      if (fullRoot) { return fullRoot }
      const fullEditor = this.filePathPool.get(shortPath)
      if (fullEditor) { return fullEditor }
      throw new Error(`Unexpected short path: ${shortPath}`)
    })
  }

  parseWindowSpecs (source) {
    const specs = []

    const rx = /\s*\[(?:_|(\S+)) (?:_|(\S+))\]/g
    let match = rx.exec(source)

    while (match) {
      const roots = match[1] ? match[1].split(',').map(shortPath => this.convertRootPath(shortPath)) : []
      const editors = match[2] ? match[2].split(',').map(shortPath => this.convertEditorPath(shortPath)) : []
      specs.push({ roots, editors })

      match = rx.exec(source)
    }

    return specs
  }
}
<commit_msg>Show "incorrect window" banner for mismatched results<commit_after>/* globals assert */

const temp = require('temp').track()
const season = require('season')
const dedent = require('dedent')
const electron = require('electron')
const fs = require('fs-plus')
const path = require('path')
const AtomApplication = require('../../src/main-process/atom-application')
const parseCommandLine = require('../../src/main-process/parse-command-line')
const {emitterEventPromise} = require('../async-spec-helpers')

describe('AtomApplication', function () {
  this.timeout(60 * 1000)
  let scenario

  beforeEach(async function () {
    scenario = await LaunchScenario.create()
  })

  afterEach(async function () {
    await scenario.destroy()
  })

  describe('command-line interface behavior', function () {
    describe('with no open windows', function () {
      it('opens a file', async function () {
        await scenario.launch(parseCommandLine(['a/1.md']))
        await scenario.assert('[_ 1.md]')
      })

      it('opens a directory', async function () {
        await scenario.launch(parseCommandLine(['a']))
        await scenario.assert('[a _]')
      })

      it('opens a file with --add', async function () {
        await scenario.launch(parseCommandLine(['--add', 'a/1.md']))
        await scenario.assert('[_ 1.md]')
      })

      it('opens a directory with --add', async function () {
        await scenario.launch(parseCommandLine(['--add', 'a']))
        await scenario.assert('[a _]')
      })

      it('opens a file with --new-window', async function () {
        await scenario.launch(parseCommandLine(['--new-window', 'a/1.md']))
        await scenario.assert('[_ 1.md]')
      })

      it('opens a directory with --new-window', async function () {
        await scenario.launch(parseCommandLine(['--new-window', 'a']))
        await scenario.assert('[a _]')
      })

      it('opens a directory with --new-window', async function () {
        await scenario.launch(parseCommandLine(['--new-window', 'a']))
      })
    })
  })
})

let channelIdCounter = 0

class LaunchScenario {
  static async create () {
    const scenario = new this()
    await scenario.init()
    return scenario
  }

  constructor () {
    this.applications = new Set()
    this.windows = new Set()
    this.root = null
    this.atomHome = null
    this.projectRootPool = new Map()
    this.filePathPool = new Map()

    this.originalAtomHome = process.env.ATOM_HOME
  }

  async init () {
    if (this.root !== null) {
      return this.root
    }

    await this.clearElectronSession()

    this.root = await new Promise((resolve, reject) => {
      temp.mkdir('launch-', (err, rootPath) => {
        if (err) { reject(err) } else { resolve(rootPath) }
      })
    })

    this.atomHome = path.join(this.root, '.atom')
    process.env.ATOM_HOME = this.atomHome
    await new Promise((resolve, reject) => {
      season.writeFile(path.join(this.atomHome, 'config.cson'), {
        '*': {
          welcome: { showOnStartup: false },
          core: { telemetryConsent: 'no', automaticallyUpdate: false }
        }
      }, err => {
        if (err) { reject(err) } else { resolve() }
      })
    })

    await new Promise((resolve, reject) => {
      // Symlinking the compile cache into the temporary home dir makes the windows load much faster
      fs.symlink(
        path.join(this.originalAtomHome, 'compile-cache'),
        path.join(this.atomHome, 'compile-cache'),
        'junction',
        err => {
          if (err) { reject(err) } else { resolve() }
        }
      )
    })

    await Promise.all(
      ['a', 'b'].map(dirPath => new Promise((resolve, reject) => {
        const fullDirPath = path.join(this.root, dirPath)
        fs.makeTree(fullDirPath, err => {
          if (err) {
            reject(err)
          } else {
            this.projectRootPool.set(dirPath, fullDirPath)
            resolve()
          }
        })
      }))
    )

    await Promise.all(
      ['a/1.md', 'b/2.md'].map(filePath => new Promise((resolve, reject) => {
        const fullFilePath = path.join(this.root, filePath)
        fs.writeFile(fullFilePath, `file: ${filePath}\n`, {encoding: 'utf8'}, err => {
          if (err) {
            reject(err)
          } else {
            this.filePathPool.set(filePath, fullFilePath)
            this.filePathPool.set(path.basename(filePath), fullFilePath)
            resolve()
          }
        })
      }))
    )
  }

  async preconditions (source) {
    const app = this.addApplication()
    const windowPromises = []
    for (const windowSpec of this.parseWindowSpecs(source)) {
      const expectOpenEvent = windowSpec.roots.length > 0 || windowSpec.editors.length > 0

      if (windowSpec.editors.length === 0) {
        windowSpec.editors.push(null)
      }

      windowPromises.push((async (theApp, foldersToOpen, pathsToOpen) => {
        const window = await theApp.openPaths({ newWindow: true, foldersToOpen, pathsToOpen })
        if (expectOpenEvent) {
          await emitterEventPromise(window, 'window:locations-opened')
        }
        return window
      })(app, windowSpec.roots, windowSpec.editors))
    }
    for (const window of await Promise.all(windowPromises)) {
      this.windows.add(window)
    }
  }

  async launch (options) {
    const app = this.addApplication()
    if (options.pathsToOpen) {
      options.pathsToOpen = this.convertPaths(options.pathsToOpen)
    }

    const windows = await app.launch(options)
    const openedPromises = []
    for (const window of windows) {
      this.windows.add(window)
      openedPromises.push(emitterEventPromise(window, 'window:locations-opened'))
    }
    await Promise.all(openedPromises)
    return windows
  }

  async open (options) {
    if (this.applications.size === 0) {
      return this.launch(options)
    }

    let app = options.app
    if (!app) {
      const apps = Array.from(this.applications)
      app = apps[apps.length - 1]
    } else {
      delete options.app
    }

    if (options.pathsToOpen) {
      options.pathsToOpen = this.convertPaths(options.pathsToOpen)
    }

    const window = await app.openWithOptions(options)
    this.windows.add(window)
    await emitterEventPromise(window, 'window:locations-opened')
    return window
  }

  async assert (source) {
    const windowSpecs = this.parseWindowSpecs(source)
    let specIndex = 0

    const windowPromises = []
    for (const window of this.windows) {
      windowPromises.push((async (theWindow, theSpec) => {
        const [rootPaths, editorPaths] = await Promise.all([
          this.getProjectRoots(theWindow),
          this.getOpenEditors(theWindow)
        ])

        const comparison = {
          ok: true,
          extraWindow: false,
          missingWindow: false,
          extraRoots: [],
          missingRoots: [],
          extraEditors: [],
          missingEditors: []
        }

        if (!theSpec) {
          comparison.ok = false
          comparison.extraWindow = true
          comparison.extraRoots = rootPaths
          comparison.extraEditors = editorPaths
        } else {
          const [missingRoots, extraRoots] = this.compareSets(theSpec.roots, rootPaths)
          const [missingEditors, extraEditors] = this.compareSets(theSpec.editors, editorPaths)

          comparison.ok = missingRoots.length === 0 &&
            extraRoots.length === 0 &&
            missingEditors.length === 0 &&
            extraEditors.length === 0
          comparison.extraRoots = extraRoots
          comparison.missingRoots = missingRoots
          comparison.extraEditors = extraEditors
          comparison.missingEditors = missingEditors
        }

        return comparison
      })(window, windowSpecs[specIndex++]))
    }

    const comparisons = await Promise.all(windowPromises)
    for (; specIndex < windowSpecs.length; specIndex++) {
      const spec = windowSpecs[specIndex]
      comparisons.push({
        ok: false,
        extraWindow: false,
        missingWindow: true,
        extraRoots: [],
        missingRoots: spec.roots,
        extraEditors: [],
        missingEditors: spec.editors
      })
    }

    const descriptionParts = []
    for (const comparison of comparisons) {
      if (comparison.ok) {
        continue
      }

      let parts = []
      if (comparison.extraWindow) {
        parts.push('extra window\n')
      } else if (comparison.missingWindow) {
        parts.push('missing window\n')
      } else {
        parts.push('incorrect window\n')
      }

      const shorten = fullPaths => fullPaths.map(fullPath => path.basename(fullPath)).join(', ')

      if (comparison.extraRoots.length > 0) {
        parts.push(`* extra roots ${shorten(comparison.extraRoots)}\n`)
      }
      if (comparison.missingRoots.length > 0) {
        parts.push(`* missing roots ${shorten(comparison.missingRoots)}\n`)
      }
      if (comparison.extraEditors.length > 0) {
        parts.push(`* extra editors ${shorten(comparison.extraEditors)}\n`)
      }
      if (comparison.missingEditors.length > 0) {
        parts.push(`* missing editors ${shorten(comparison.missingEditors)}\n`)
      }

      if (descriptionParts.length === 0) {
        descriptionParts.push('Launched windows did not match spec\n')
      }
      descriptionParts.push(parts.join(''))
    }

    assert.isTrue(descriptionParts.length === 0, descriptionParts.join(''))
  }

  async destroy () {
    await Promise.all(
      Array.from(this.applications, app => app.destroy())
    )
    await this.clearElectronSession()

    process.env.ATOM_HOME = this.originalAtomHome
  }

  addApplication (options = {}) {
    const app = new AtomApplication({
      resourcePath: path.resolve(__dirname, '../..'),
      atomHomeDirPath: this.atomHome,
      ...options
    })
    this.applications.add(app)
    return app
  }

  getApplication (index) {
    const app = Array.from(this.applications)[index]
    if (!app) {
      throw new Error(`Application ${index} does not exist`)
    }
    return app
  }

  getWindow (index) {
    const window = Array.from(this.windows)[index]
    if (!window) {
      throw new Error(`Window ${index} does not exist`)
    }
    return window
  }

  getProjectRoots (window) {
    return this.evalInWebContents(window.browserWindow.webContents, reply => reply(atom.project.getPaths()))
  }

  getOpenEditors (window) {
    return this.evalInWebContents(window.browserWindow.webContents, reply => {
      reply(atom.workspace.getTextEditors().map(editor => editor.getPath()).filter(Boolean))
    })
  }

  evalInWebContents (webContents, source, ...args) {
    const channelId = `eval-result-${channelIdCounter++}`
    return new Promise(resolve => {
      electron.ipcMain.on(channelId, receiveResult)

      function receiveResult (_event, result) {
        electron.ipcMain.removeListener('eval-result', receiveResult)
        resolve(result)
      }

      const js = dedent`
        function sendBackToMainProcess (result) {
          require('electron').ipcRenderer.send('${channelId}', result)
        }
        (${source})(sendBackToMainProcess, ${args.map(JSON.stringify).join(', ')})
      `
      webContents.executeJavaScript(js)
    })
  }

  clearElectronSession () {
    return new Promise(resolve => {
      electron.session.defaultSession.clearStorageData(() => {
        // Resolve promise on next tick, otherwise the process stalls. This
        // might be a bug in Electron, but it's probably fixed on the newer
        // versions.
        process.nextTick(resolve)
      })
    })
  }

  compareSets (expected, actual) {
    const expectedItems = new Set(expected)
    const extra = []
    const missing = []

    for (const actualItem of actual) {
      if (!expectedItems.delete(actualItem)) {
        // actualItem was present, but not expected
        extra.push(actualItem)
      }
    }
    for (const remainingItem of expectedItems) {
      // remainingItem was expected, but not present
      missing.push(remainingItem)
    }
    return [missing, extra]
  }

  convertRootPath (shortRootPath) {
    const fullRootPath = this.projectRootPool.get(shortRootPath)
    if (!fullRootPath) {
      throw new Error(`Unexpected short project root path: ${shortRootPath}`)
    }
    return fullRootPath
  }

  convertEditorPath (shortEditorPath) {
    const fullEditorPath = this.filePathPool.get(shortEditorPath)
    if (!fullEditorPath) {
      throw new Error(`Unexpected short editor path: ${shortEditorPath}`)
    }
    return fullEditorPath
  }

  convertPaths (paths) {
    return paths.map(shortPath => {
      const fullRoot = this.projectRootPool.get(shortPath)
      if (fullRoot) { return fullRoot }
      const fullEditor = this.filePathPool.get(shortPath)
      if (fullEditor) { return fullEditor }
      throw new Error(`Unexpected short path: ${shortPath}`)
    })
  }

  parseWindowSpecs (source) {
    const specs = []

    const rx = /\s*\[(?:_|(\S+)) (?:_|(\S+))\]/g
    let match = rx.exec(source)

    while (match) {
      const roots = match[1] ? match[1].split(',').map(shortPath => this.convertRootPath(shortPath)) : []
      const editors = match[2] ? match[2].split(',').map(shortPath => this.convertEditorPath(shortPath)) : []
      specs.push({ roots, editors })

      match = rx.exec(source)
    }

    return specs
  }
}
<|endoftext|>


<commit_before>// FT.InlineEditor
// =========================================================================================================
// Replaces an element with an editable version of itself
//
// Usage:
//   new FT.InlineEditor(url, element, editor_writer)
//     url            the URL where edited materials will be posted to using the HTTP verb PUT
//     element        the HTML element which contains the information to be replaced with an inline editor
//     editor_writer  a function that creates an inline editor from the element
//
// Events:
//   after_init       passes the element to observers before the editor is created
//   before_init      passes the element and the editor to observers after the editor is created and added to the DOM
//   close            passes the element and the editor to observers just before the editor is hidden and the element restored
//
//

var FT=FT||{};
FT.InlineEditor = (function() {
  var CURRENT_ELEMENT = null;
  var CURRENT_EDITOR = null;
  var observer = new Observer();
  var _$;

  var constructor = function(url, element, editor_writer) {
    if(!element) { return; }

    _$ = _$ || (function() {
      var a = FT.adapter();
      a.loaded(function() { // Close InlineEditors when the ESC key is pressed
        a.on(document.body, 'keydown', function(e) {
          (e.keyCode == Event.KEY_ESC) && FT.InlineEditor.close();
        });
      });
      return a;
    })();

    if(!_$) { throw new 'FT.adapter() is not defined!' }

    element.edit_inline = function() {

      // close any existing editors
      FT.InlineEditor.close();

      // before_init callback
      // TODO: can return false to cancel the edit?
      observer.fire('before_init', element);

      // Create editor
      var editor = editor_writer(element); if(!editor) {return;}
      editor.id = 'edit_row';

      // Hide the view-only element
      _$.addClass(element, 'in-edit');

      // Insert the editor
      _$.insert_after(element, editor);

      // Save the contents of the editor...
      editor.save = function(callback) {
        var form = _$.up(editor, 'form'),
            params = _$.serialize(form);
        FT.xhr(url, 'put', params, {
          onSuccess: function() {
            (CURRENT_EDITOR == editor) && FT.InlineEditor.close();
          },
          onComplete: function(response) {
            (response.status != 400) && callback && callback();
          }
        });
      }

      // ...on clicking a submit button
      var submits = _$.find(editor, '*[type="submit"]');
      for(var i=0, ii=submits.length; i<ii; i++) {
        _$.on(submits[i], 'click', function(e) {
          _$.stop(e);
          editor.save();
        });
      }

      // ...or on hitting the Return key
      _$.on(editor, 'keydown', function(e) {
        // window.console.log('kd: ' + e.which);
        if(e.keyCode == Event.KEY_RETURN) {
          _$.stop(e);
          editor.save();
        }
        if(e.keyCode == Event.KEY_UP) {
          observer.fire('up', [e, element, editor]);
        }
        if(e.keyCode == Event.KEY_DOWN) {
          observer.fire('down', [e, element, editor]);
        }
      });

      // after_init callback
      observer.fire('after_init', [element, editor]);

      // Finally, select the first Form element in the editor
      FT.selectFirstFieldIn(editor);

      // Remember the row being edited
      CURRENT_ELEMENT = element;
      CURRENT_EDITOR = editor;
    }

    // Edit the row when it is clicked (but not if a link or button was clicked)
    _$.on(element, 'click', function(e) {
      var target = _$.target(e);
      target && !_$.match(target, 'input, button, a') && element.edit_inline();
    });
  };

  constructor.close = function() {
    if(CURRENT_ELEMENT || CURRENT_EDITOR) {
      observer.fire('close', [CURRENT_ELEMENT, CURRENT_EDITOR]);
      CURRENT_ELEMENT && _$.removeClass(CURRENT_ELEMENT, 'in-edit');
      CURRENT_EDITOR  && CURRENT_EDITOR.parentNode && CURRENT_EDITOR.parentNode.removeChild(CURRENT_EDITOR);
      CURRENT_ELEMENT = null;
      CURRENT_EDITOR  = null;
    }
  };
  constructor.observe = function(name,func){ observer.observe(name, func); };
  constructor.unobserve = function(name,func){ observer.unobserve(name, func); };

  return constructor;
})();<commit_msg>don't rely on Prototype's Event constants<commit_after>// FT.InlineEditor
// =========================================================================================================
// Replaces an element with an editable version of itself
//
// Usage:
//   new FT.InlineEditor(url, element, editor_writer)
//     url            the URL where edited materials will be posted to using the HTTP verb PUT
//     element        the HTML element which contains the information to be replaced with an inline editor
//     editor_writer  a function that creates an inline editor from the element
//
// Events:
//   after_init       passes the element to observers before the editor is created
//   before_init      passes the element and the editor to observers after the editor is created and added to the DOM
//   close            passes the element and the editor to observers just before the editor is hidden and the element restored
//
//

var FT=FT||{};
FT.InlineEditor = (function() {
  var CURRENT_ELEMENT = null;
  var CURRENT_EDITOR = null;
  var observer = new Observer();
  var _$;

  var KEY_BACKSPACE =  8,
      KEY_TAB       =  9,
      KEY_RETURN    = 13,
      KEY_ESC       = 27,
      KEY_LEFT      = 37,
      KEY_UP        = 38,
      KEY_RIGHT     = 39,
      KEY_DOWN      = 40,
      KEY_DELETE    = 46,
      KEY_HOME      = 36,
      KEY_END       = 35,
      KEY_PAGEUP    = 33,
      KEY_PAGEDOWN  = 34,
      KEY_INSERT    = 45;

  var constructor = function(url, element, editor_writer) {
    if(!element) { return; }

    _$ = _$ || (function() {
      var a = FT.adapter();
      a.loaded(function() { // Close InlineEditors when the ESC key is pressed
        a.on(document.body, 'keydown', function(e) {
          (e.keyCode == KEY_ESC) && FT.InlineEditor.close();
        });
      });
      return a;
    })();

    if(!_$) { throw new 'FT.adapter() is not defined!' }

    element.edit_inline = function() {

      // close any existing editors
      FT.InlineEditor.close();

      // before_init callback
      // TODO: can return false to cancel the edit?
      observer.fire('before_init', element);

      // Create editor
      var editor = editor_writer(element); if(!editor) {return;}
      editor.id = 'edit_row';

      // Hide the view-only element
      _$.addClass(element, 'in-edit');

      // Insert the editor
      _$.insert_after(element, editor);

      // Save the contents of the editor...
      editor.save = function(callback) {
        var form = _$.up(editor, 'form'),
            params = _$.serialize(form);
        FT.xhr(url, 'put', params, {
          onSuccess: function() {
            (CURRENT_EDITOR == editor) && FT.InlineEditor.close();
          },
          onComplete: function(response) {
            (response.status != 400) && callback && callback();
          }
        });
      }

      // ...on clicking a submit button
      var submits = _$.find(editor, '*[type="submit"]');
      for(var i=0, ii=submits.length; i<ii; i++) {
        _$.on(submits[i], 'click', function(e) {
          _$.stop(e);
          editor.save();
        });
      }

      // ...or on hitting the Return key
      _$.on(editor, 'keydown', function(e) {
        if(e.keyCode == KEY_RETURN) {
          _$.stop(e);
          editor.save();
        }
        if(e.keyCode == KEY_UP) {
          observer.fire('up', [e, element, editor]);
        }
        if(e.keyCode == KEY_DOWN) {
          observer.fire('down', [e, element, editor]);
        }
      });

      // after_init callback
      observer.fire('after_init', [element, editor]);

      // Finally, select the first Form element in the editor
      FT.selectFirstFieldIn(editor);

      // Remember the row being edited
      CURRENT_ELEMENT = element;
      CURRENT_EDITOR = editor;
    }

    // Edit the row when it is clicked (but not if a link or button was clicked)
    _$.on(element, 'click', function(e) {
      var target = _$.target(e);
      target && !_$.is_in(target, 'input, button, a') && element.edit_inline();
    });
  };

  constructor.close = function() {
    if(CURRENT_ELEMENT || CURRENT_EDITOR) {
      observer.fire('close', [CURRENT_ELEMENT, CURRENT_EDITOR]);
      CURRENT_ELEMENT && _$.removeClass(CURRENT_ELEMENT, 'in-edit');
      CURRENT_EDITOR  && CURRENT_EDITOR.parentNode && CURRENT_EDITOR.parentNode.removeChild(CURRENT_EDITOR);
      CURRENT_ELEMENT = null;
      CURRENT_EDITOR  = null;
    }
  };
  constructor.observe = function(name,func){ observer.observe(name, func); };
  constructor.unobserve = function(name,func){ observer.unobserve(name, func); };

  return constructor;
})();<|endoftext|>


<commit_before>(function(){
    var

    /* Dynamic page elements */
    dash_content = $('#dash-content'),
    messages     = $('#messages'),

    /* Static Templates */
    tpl_spinner   = $('#tpl-spinner').html(),
    tpl_dashboard = $('#tpl-dashboard').html(),
    tpl_help      = $('#tpl-help').html(),

    /* Handlebars Templates */
    tpl_settings          = Handlebars.compile($('#tpl-settings').html()),
    tpl_message           = Handlebars.compile($('#tpl-message').html()),
    tpl_google_sheets     = Handlebars.compile($('#tpl-google-sheets').html()),
    tpl_google_worksheets = Handlebars.compile($('#tpl-google-worksheets').html()),
    tpl_google_table      = Handlebars.compile($('#tpl-google-table').html()),

    /* Show a styled alert message in the navbar */
    alertMsg = function(message, type){
        message  = message || '';
        type     = type    || 'info';
        messages.html(tpl_message({message: message, type: type}));
    },

    /* Show spinner in navbar */
    showSpinner = function(){
        messages.html(tpl_spinner);
    },

    /* Hide spinner in navbar */
    hideSpinner = function(){
        messages.html('');
    },

    /* Show error in nav */
    showError = function(response){
        alertMsg('Error: ' + response.responseJSON.body, 'danger');
        dash_content.html(tpl_help);
    };

    /* Handlebars Helpers */

    /* Iterate key-value pairs in an object */
    Handlebars.registerHelper('key_value', function(obj, bars){
        var buffer = '';
        for(key in obj){
            buffer += bars.fn({key:key, value:obj[key]});
        }
        return buffer;
    });

    /* Iterate the first n elements in an array */
    Handlebars.registerHelper('first', function(count, array, bars){
        var buffer = '';
        for(var i=0; i<count; i++){
            buffer += bars.fn(array[i]);
        }
        return buffer
    });

    /* URL Route Handlers */
    new Router()

    // Reset dashboard before following route
    .before(function(req, next){
        messages.html('');
        dash_content.html(tpl_spinner);
        next();
    })

    // Helper route for testing errors
    .addRoute('#/404', function(req, next){
        $.ajax('/api/0/404')
        .error(function(res){ showError(res); });
    })

    // Profile settings
    .addRoute('#/settings', function(req, next){
        $.ajax('/api/0/user')
        .success(function(res){
            dash_content.html(tpl_settings(res.body));
        })
        .error(function(res){ showError(res); });
    })

    // Show spreadsheets in Google Drive
    .addRoute('#/drive', function(req, next){
        $.ajax('/api/0/google/sheets')
        .success(function(res){
            dash_content.html(tpl_google_sheets(res.body));
        })
        .error(function(res){ showError(res); });
    })

    // Show worksheets in Drive spreadsheet
    .addRoute('#/drive/:key', function(req, next){
        $.ajax('/api/0/google/sheets/' + req.params.key)
        .success(function(res){
            dash_content.html(tpl_google_worksheets(res.body));
        })
        .error(function(res){ showError(res); });
    })

    // Show preview of data in Drive worksheet
    .addRoute('#/drive/:key/:id', function(req, next){
        $.ajax('/api/0/google/sheets/' + req.params.key + '/' + req.params.id)
        .success(function(res){
            dash_content.html(tpl_google_table(res.body));
        })
        .error(function(res){ showError(res); });
    })

    // Create new Data Source using Drive worksheet
    .addRoute('#/import/:key/:id', function(req, next){
        dash_content.html("TODO Import worksheet
Key: " + req.params.key + "
Id: " + req.params.id);
    })

    // Show all data sources
    .addRoute('#/data_source', function(req, next){
        console.log(req);
        dash_content.html('All data sources');
    })

    // View/edit a data source
    .addRoute('#/data_source/:data_source_id', function(req, next){
        console.log(req);
        dash_content.html('Data Source ' + req.params.data_source_id);
    })

    // Show all data views
    .addRoute('#/data_view', function(req, next){
        console.log(req);
        dash_content.html('All data views');
    })

    // View/Edit a data view
    .addRoute('#/data_view/:data_view_id', function(req, next){
        console.log(req);
        dash_content.html('Data View ' + req.params.data_view_id);
    })

    // Missing routes default to dashboard home page
    .errors(404, function(){
        dash_content.html(tpl_dashboard);
    })

    .run()

    /* Event Handlers */
    $(document)

    // Save profile settings
    .on('submit', 'form#settings', function(){
        payload = {
            google_id           : $('form #google_id').val(),
            profile_name        : $('form #profile_name').val(),
            profile_slug        : $('form #profile_slug').val(),
            profile_description : $('form #profile_description').val(),
            profile_email       : $('form #profile_email').val(),
            profile_web_address : $('form #profile_web_address').val()
        }

        $.ajax({
            url: '/api/0/user',
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            alertMsg('Changes Saved!', 'success');
        })
        .error(function(res){ showError(res); });

        return false;
    })

})()<commit_msg>Fixed broken routes<commit_after>(function(){
    var

    /* Dynamic page elements */
    dash_content = $('#dash-content'),
    messages     = $('#messages'),

    /* Static Templates */
    tpl_spinner   = $('#tpl-spinner').html(),
    tpl_dashboard = $('#tpl-dashboard').html(),
    tpl_help      = $('#tpl-help').html(),

    /* Handlebars Templates */
    tpl_settings          = Handlebars.compile($('#tpl-settings').html()),
    tpl_message           = Handlebars.compile($('#tpl-message').html()),
    tpl_google_sheets     = Handlebars.compile($('#tpl-google-sheets').html()),
    tpl_google_worksheets = Handlebars.compile($('#tpl-google-worksheets').html()),
    tpl_google_table      = Handlebars.compile($('#tpl-google-table').html()),

    /* Show a styled alert message in the navbar */
    alertMsg = function(message, type){
        message  = message || '';
        type     = type    || 'info';
        messages.html(tpl_message({message: message, type: type}));
    },

    /* Show spinner in navbar */
    showSpinner = function(){
        messages.html(tpl_spinner);
    },

    /* Hide spinner in navbar */
    hideSpinner = function(){
        messages.html('');
    },

    /* Show error in nav */
    showError = function(response){
        alertMsg('Error: ' + response.responseJSON.body, 'danger');
        dash_content.html(tpl_help);
    };

    /* Handlebars Helpers */

    /* Iterate key-value pairs in an object */
    Handlebars.registerHelper('key_value', function(obj, bars){
        var buffer = '';
        for(key in obj){
            buffer += bars.fn({key:key, value:obj[key]});
        }
        return buffer;
    });

    /* Iterate the first n elements in an array */
    Handlebars.registerHelper('first', function(count, array, bars){
        var buffer = '';
        for(var i=0; i<count; i++){
            buffer += bars.fn(array[i]);
        }
        return buffer
    });

    /* URL Route Handlers */
    new Router()

    // Reset dashboard before following route
    .before(function(req, next){
        messages.html('');
        dash_content.html(tpl_spinner);
        next();
    })

    // Helper route for testing errors
    .addRoute('#/404', function(req, next){
        $.ajax('/api/0/404')
        .error(function(res){ showError(res); });
    })

    // Profile settings
    .addRoute('#/settings', function(req, next){
        $.ajax('/api/0/user')
        .success(function(res){
            dash_content.html(tpl_settings(res.body));
        })
        .error(function(res){ showError(res); });
    })

    // Show spreadsheets in Google Drive
    .addRoute('#/drive', function(req, next){
        $.ajax('/api/0/google/sheets')
        .success(function(res){
            dash_content.html(tpl_google_sheets(res.body));
        })
        .error(function(res){ showError(res); });
    })

    // Show worksheets in Drive spreadsheet
    .addRoute('#/drive/:key', function(req, next){
        $.ajax('/api/0/google/sheets/' + req.params.key)
        .success(function(res){
            dash_content.html(tpl_google_worksheets(res.body));
        })
        .error(function(res){ showError(res); });
    })

    // Show preview of data in Drive worksheet
    .addRoute('#/drive/:key/:id', function(req, next){
        $.ajax('/api/0/google/sheets/' + req.params.key + '/' + req.params.id)
        .success(function(res){
            dash_content.html(tpl_google_table(res.body));
        })
        .error(function(res){ showError(res); });
    })

    // Create new Data Source using Drive worksheet
    .addRoute('#/import/:key/:id', function(req, next){
        dash_content.html("TODO Import worksheet
Key: " + req.params.key + "
Id: " + req.params.id);
    })

    // Show all data sources
    .addRoute('#/data-source', function(req, next){
        console.log(req);
        dash_content.html('All data sources');
    })

    // View/edit a data source
    .addRoute('#/data-source/:data_source_id', function(req, next){
        console.log(req);
        dash_content.html('Data Source ' + req.params.data_source_id);
    })

    // Show all data views
    .addRoute('#/data-view', function(req, next){
        console.log(req);
        dash_content.html('All data views');
    })

    // View/Edit a data view
    .addRoute('#/data-view/:data_view_id', function(req, next){
        console.log(req);
        dash_content.html('Data View ' + req.params.data_view_id);
    })

    // Missing routes default to dashboard home page
    .errors(404, function(){
        dash_content.html(tpl_dashboard);
    })

    .run()

    /* Event Handlers */
    $(document)

    // Save profile settings
    .on('submit', 'form#settings', function(){
        payload = {
            google_id           : $('form #google_id').val(),
            profile_name        : $('form #profile_name').val(),
            profile_slug        : $('form #profile_slug').val(),
            profile_description : $('form #profile_description').val(),
            profile_email       : $('form #profile_email').val(),
            profile_web_address : $('form #profile_web_address').val()
        }

        $.ajax({
            url: '/api/0/user',
            type: 'POST',
            data: {payload: JSON.stringify(payload)}
        })
        .success(function(res){
            alertMsg('Changes Saved!', 'success');
        })
        .error(function(res){ showError(res); });

        return false;
    })

})()<|endoftext|>


<commit_before>import React, { Component } from 'react'

export default class ClientsSection extends Component {

  render () {
    return (

Our Clients

    )
  }
}

<commit_msg>add qualcomm to client list<commit_after>import React, { Component } from 'react'

export default class ClientsSection extends Component {

  render () {
    return (

Our Clients

    )
  }
}

<|endoftext|>


<commit_before>"use strict";

class PokemonColumn {
	constructor(columnHeader, column) {
		this.columnHeader = columnHeader
		this.column = column
	}
}

class ListSection {
	constructor() {
		this.nextPoke = 0
		this.nextLimit = 50

		this.basePokemonColumns = [
			new PokemonColumn("", (pokemon) => ""),
			new PokemonColumn("Pokemon", (pokemon) => PokeText.formName(pokemon) + (pokemon.nickname ? " [" + pokemon.nickname + "]" : "")),
			new PokemonColumn("Types", (pokemon) => PokeText.types(pokemon)),
			new PokemonColumn("Abilities", (pokemon) => PokeText.abilities(pokemon)),
			new PokemonColumn("HP", (pokemon) => PokeText.stat(pokemon.stats.hp)),
			new PokemonColumn("Atk", (pokemon) => PokeText.stat(pokemon.stats.atk)),
			new PokemonColumn("Def", (pokemon) => PokeText.stat(pokemon.stats.def)),
			new PokemonColumn("SpA", (pokemon) => PokeText.stat(pokemon.stats.spa)),
			new PokemonColumn("SpD", (pokemon) => PokeText.stat(pokemon.stats.spd)),
			new PokemonColumn("Spe", (pokemon) => PokeText.stat(pokemon.stats.spe)),
			new PokemonColumn("Egg groups", (pokemon) => PokeText.eggGroups(pokemon))
		]

		this.tabPokemonColumns = [
			new PokemonColumn("", (pokemon) => ""),
			new PokemonColumn("Pokemon", (pokemon) =>
				PokeText.formName(pokemon) +
				(pokemon.gender && pokemon.gender != "—" ? " " + PokeText.gender(pokemon) : "") +
				PokeText.amountShiny(pokemon) +
				(pokemon.nickname ? " [" + pokemon.nickname + "]" : "")
			),
			new PokemonColumn("Types", (pokemon) => PokeText.types(pokemon)),
			new PokemonColumn("Abilities", (pokemon) => {
				if (pokemon.ability)
					return PokeText.ability(pokemon.ability, pokemon.abilities[2] ? pokemon.abilities[2].toLowerCase() == pokemon.ability.split("(")[0].trim().toLowerCase() : false)
				return PokeText.abilities(pokemon)
			}),
			new PokemonColumn("Nature", (pokemon) => pokemon.nature ? pokemon.nature : ""),
			new PokemonColumn("HP", (pokemon) => PokeText.IVEV("hp", pokemon)),
			new PokemonColumn("Atk", (pokemon) => PokeText.IVEV("atk", pokemon)),
			new PokemonColumn("Def", (pokemon) => PokeText.IVEV("def", pokemon)),
			new PokemonColumn("SpA", (pokemon) => PokeText.IVEV("spa", pokemon)),
			new PokemonColumn("SpD", (pokemon) => PokeText.IVEV("spd", pokemon)),
			new PokemonColumn("Spe", (pokemon) => PokeText.IVEV("spe", pokemon)),
			new PokemonColumn("Moves", (pokemon) => pokemon.learntMoves ? pokemon.learntMoves.join(", ") : ""),
			new PokemonColumn("Ball", (pokemon) => PokeText.balls(pokemon))
		]

		this.listElement = document.getElementById("pokemon-list")
		this.gridElement = document.getElementById("pokemon-grid")
	}

	show() {
		this.nextPoke = 0
		this.nextLimit = 50
		stuff.infoSection.moveAway()
		while (this.listElement.children[0].firstChild)
			this.listElement.children[0].removeChild(this.listElement.children[0].firstChild)
		while (this.listElement.children[1].firstChild)
			this.listElement.children[1].removeChild(this.listElement.children[1].firstChild)
		while (this.gridElement.firstChild)
			this.gridElement.removeChild(this.gridElement.firstChild)
		if (stuff.state.mode == "table") {
			this.listElement.style.display = "table"
			this.gridElement.style.display = "none"
			this.setUpTableHeader()
		} else {
			this.listElement.style.display = "none"
			this.gridElement.style.display = "initial"
		}
		this.addNextPokemonEntry()
	}

	addNextPokemonEntry() {
		if (!stuff.state.currentPokemons[this.nextPoke]) {
			this.nextPoke = 0
			return
		}
		if (this.nextPoke > this.nextLimit) {
			this.nextLimit += stuff.state.mode == "grid" ? 50 : 25
			return
		}
		if (stuff.state.mode == "table")
			this.addPokemonListElement(stuff.state.currentPokemons[this.nextPoke])
		else
			this.addPokemonGridElement(stuff.state.currentPokemons[this.nextPoke])
		this.nextPoke++
		setTimeout(() => { this.addNextPokemonEntry() }, 0)
	}

	setUpTableHeader() {
		var tableHeader = newTag("tr", this.listElement.children[0])
		tableHeader.onclick = ()=>{
			document.getElementById("copy").style.display = ""
			document.getElementById("pokemon-copy-table").value = this.getMarkdownTable()
		}
		var columns = this.basePokemonColumns
		if (stuff.state.currentPokemons[0] && stuff.state.currentPokemons[0].base && stuff.state.completionMode == "normal")
			columns = this.tabPokemonColumns
		for (var i in columns) {
			var element = newTag("th", tableHeader)
			element.innerHTML = columns[i].columnHeader
		}
	}

	loadMoreWhenScrolledDown() {
		var main = document.getElementById("main")
		if (main.scrollTop > main.scrollHeight - main.clientHeight - 200) {
			if (this.nextPoke)
				this.addNextPokemonEntry()
		}
	}

	addPokemonListElement(pokemon) {
		var pokeElement = newTag("tr", this.listElement.children[1])
		var columns = this.basePokemonColumns
		if (stuff.state.currentPokemons[0] && stuff.state.currentPokemons[0].base && stuff.state.completionMode == "normal")
			columns = this.tabPokemonColumns
		for (var i in columns) {
			var element = newTag("th", pokeElement)
			element.innerHTML = columns[i].column(pokemon)
		}
		pokeElement.onclick = function () {
			stuff.selectPokemon(pokemon, pokeElement)
		}
		if (this.nextPoke % 2)
			pokeElement.className = pokemon.got ? "got-odd" : "odd"
		else
			pokeElement.className = pokemon.got ? "got-even" : "even"
	}

	addPokemonGridElement(pokemon) {
		var pokeElement = newTag("li", this.gridElement)
		if (pokemon.got)
			pokeElement.className = "got"
		pokeElement.innerHTML = ""
		pokeElement.onclick = function () {
			stuff.selectPokemon(pokemon)
		}
	}

	getMarkdownTable(){
		var table = `Pokemon| Ability| Nature| IVs| Moves| Pokeball
---|---|----|----|----|----
`
		for(var n in stuff.state.currentPokemons){
			var pokemon = stuff.state.currentPokemons[n]
			table += (pokemon.shiny ? "★ " : "") +
				PokeText.formName(pokemon) +
				(pokemon.gender ? " " + pokemon.gender : "") +
				(pokemon.amount ? " (" + pokemon.amount + ")" : "") + "| "
			if(pokemon.ability)
				table += pokemon.ability
			table += "| "
			if(pokemon.nature)
				table += pokemon.nature
			table += "| "
			if(pokemon.ivs)
				table += pokemon.ivs.hp + "/" + pokemon.ivs.atk + "/" + pokemon.ivs.def + "/" +
					pokemon.ivs.spa + "/" + pokemon.ivs.spd + "/" + pokemon.ivs.spe
			table += "| "
			if(pokemon.learntMoves)
				table += pokemon.learntMoves.join(", ")
			table += "| "
			for(var i in pokemon.balls)
				table += "[](/" + pokemon.balls[i].replace(" ","").replace("é","e").toLowerCase() + ") "
			table += "\n"
		}
		return table
	}
}<commit_msg>Notes now show when hovering over row<commit_after>"use strict";

class PokemonColumn {
	constructor(columnHeader, column) {
		this.columnHeader = columnHeader
		this.column = column
	}
}

class ListSection {
	constructor() {
		this.nextPoke = 0
		this.nextLimit = 50

		this.basePokemonColumns = [
			new PokemonColumn("", (pokemon) => ""),
			new PokemonColumn("Pokemon", (pokemon) => PokeText.formName(pokemon) + (pokemon.nickname ? " [" + pokemon.nickname + "]" : "")),
			new PokemonColumn("Types", (pokemon) => PokeText.types(pokemon)),
			new PokemonColumn("Abilities", (pokemon) => PokeText.abilities(pokemon)),
			new PokemonColumn("HP", (pokemon) => PokeText.stat(pokemon.stats.hp)),
			new PokemonColumn("Atk", (pokemon) => PokeText.stat(pokemon.stats.atk)),
			new PokemonColumn("Def", (pokemon) => PokeText.stat(pokemon.stats.def)),
			new PokemonColumn("SpA", (pokemon) => PokeText.stat(pokemon.stats.spa)),
			new PokemonColumn("SpD", (pokemon) => PokeText.stat(pokemon.stats.spd)),
			new PokemonColumn("Spe", (pokemon) => PokeText.stat(pokemon.stats.spe)),
			new PokemonColumn("Egg groups", (pokemon) => PokeText.eggGroups(pokemon))
		]

		this.tabPokemonColumns = [
			new PokemonColumn("", (pokemon) => ""),
			new PokemonColumn("Pokemon", (pokemon) =>
				PokeText.formName(pokemon) +
				(pokemon.gender && pokemon.gender != "—" ? " " + PokeText.gender(pokemon) : "") +
				PokeText.amountShiny(pokemon) +
				(pokemon.nickname ? " [" + pokemon.nickname + "]" : "")
			),
			new PokemonColumn("Types", (pokemon) => PokeText.types(pokemon)),
			new PokemonColumn("Abilities", (pokemon) => {
				if (pokemon.ability)
					return PokeText.ability(pokemon.ability, pokemon.abilities[2] ? pokemon.abilities[2].toLowerCase() == pokemon.ability.split("(")[0].trim().toLowerCase() : false)
				return PokeText.abilities(pokemon)
			}),
			new PokemonColumn("Nature", (pokemon) => pokemon.nature ? pokemon.nature : ""),
			new PokemonColumn("HP", (pokemon) => PokeText.IVEV("hp", pokemon)),
			new PokemonColumn("Atk", (pokemon) => PokeText.IVEV("atk", pokemon)),
			new PokemonColumn("Def", (pokemon) => PokeText.IVEV("def", pokemon)),
			new PokemonColumn("SpA", (pokemon) => PokeText.IVEV("spa", pokemon)),
			new PokemonColumn("SpD", (pokemon) => PokeText.IVEV("spd", pokemon)),
			new PokemonColumn("Spe", (pokemon) => PokeText.IVEV("spe", pokemon)),
			new PokemonColumn("Moves", (pokemon) => pokemon.learntMoves ? pokemon.learntMoves.join(", ") : ""),
			new PokemonColumn("Ball", (pokemon) => PokeText.balls(pokemon))
		]

		this.listElement = document.getElementById("pokemon-list")
		this.gridElement = document.getElementById("pokemon-grid")
	}

	show() {
		this.nextPoke = 0
		this.nextLimit = 50
		stuff.infoSection.moveAway()
		while (this.listElement.children[0].firstChild)
			this.listElement.children[0].removeChild(this.listElement.children[0].firstChild)
		while (this.listElement.children[1].firstChild)
			this.listElement.children[1].removeChild(this.listElement.children[1].firstChild)
		while (this.gridElement.firstChild)
			this.gridElement.removeChild(this.gridElement.firstChild)
		if (stuff.state.mode == "table") {
			this.listElement.style.display = "table"
			this.gridElement.style.display = "none"
			this.setUpTableHeader()
		} else {
			this.listElement.style.display = "none"
			this.gridElement.style.display = "initial"
		}
		this.addNextPokemonEntry()
	}

	addNextPokemonEntry() {
		if (!stuff.state.currentPokemons[this.nextPoke]) {
			this.nextPoke = 0
			return
		}
		if (this.nextPoke > this.nextLimit) {
			this.nextLimit += stuff.state.mode == "grid" ? 50 : 25
			return
		}
		if (stuff.state.mode == "table")
			this.addPokemonListElement(stuff.state.currentPokemons[this.nextPoke])
		else
			this.addPokemonGridElement(stuff.state.currentPokemons[this.nextPoke])
		this.nextPoke++
		setTimeout(() => { this.addNextPokemonEntry() }, 0)
	}

	setUpTableHeader() {
		var tableHeader = newTag("tr", this.listElement.children[0])
		tableHeader.onclick = ()=>{
			document.getElementById("copy").style.display = ""
			document.getElementById("pokemon-copy-table").value = this.getMarkdownTable()
		}
		var columns = this.basePokemonColumns
		if (stuff.state.currentPokemons[0] && stuff.state.currentPokemons[0].base && stuff.state.completionMode == "normal")
			columns = this.tabPokemonColumns
		for (var i in columns) {
			var element = newTag("th", tableHeader)
			element.innerHTML = columns[i].columnHeader
		}
	}

	loadMoreWhenScrolledDown() {
		var main = document.getElementById("main")
		if (main.scrollTop > main.scrollHeight - main.clientHeight - 200) {
			if (this.nextPoke)
				this.addNextPokemonEntry()
		}
	}

	addPokemonListElement(pokemon) {
		var pokeElement = newTag("tr", this.listElement.children[1])
		var columns = this.basePokemonColumns
		if (stuff.state.currentPokemons[0] && stuff.state.currentPokemons[0].base && stuff.state.completionMode == "normal")
			columns = this.tabPokemonColumns
		for (var i in columns) {
			var element = newTag("th", pokeElement)
			if(pokemon.notes)
				element.title = pokemon.notes
			element.innerHTML = columns[i].column(pokemon)
		}
		pokeElement.onclick = function () {
			stuff.selectPokemon(pokemon, pokeElement)
		}
		if (this.nextPoke % 2)
			pokeElement.className = pokemon.got ? "got-odd" : "odd"
		else
			pokeElement.className = pokemon.got ? "got-even" : "even"
	}

	addPokemonGridElement(pokemon) {
		var pokeElement = newTag("li", this.gridElement)
		if (pokemon.got)
			pokeElement.className = "got"
		pokeElement.innerHTML = ""
		pokeElement.onclick = function () {
			stuff.selectPokemon(pokemon)
		}
	}

	getMarkdownTable(){
		var table = `Pokemon| Ability| Nature| IVs| Moves| Pokeball
---|---|----|----|----|----
`
		for(var n in stuff.state.currentPokemons){
			var pokemon = stuff.state.currentPokemons[n]
			table += (pokemon.shiny ? "★ " : "") +
				PokeText.formName(pokemon) +
				(pokemon.gender ? " " + pokemon.gender : "") +
				(pokemon.amount ? " (" + pokemon.amount + ")" : "") + "| "
			if(pokemon.ability)
				table += pokemon.ability
			table += "| "
			if(pokemon.nature)
				table += pokemon.nature
			table += "| "
			if(pokemon.ivs)
				table += pokemon.ivs.hp + "/" + pokemon.ivs.atk + "/" + pokemon.ivs.def + "/" +
					pokemon.ivs.spa + "/" + pokemon.ivs.spd + "/" + pokemon.ivs.spe
			table += "| "
			if(pokemon.learntMoves)
				table += pokemon.learntMoves.join(", ")
			table += "| "
			for(var i in pokemon.balls)
				table += "[](/" + pokemon.balls[i].replace(" ","").replace("é","e").toLowerCase() + ") "
			table += "\n"
		}
		return table
	}
}<|endoftext|>


<commit_before>module.exports = {
  hosturl: 'http://206.253.166.149/',
  // Stats Sessions are valid for only 3 hours
  statsSessionTimeout: 3*60*60*1000
};<commit_msg>Fixed hosturl.<commit_after>module.exports = {
  hosturl: 'http://sizzlingstats.com/',
  // Stats Sessions are valid for only 3 hours
  statsSessionTimeout: 3*60*60*1000
};<|endoftext|>