<commit_before>'use strict';

var common         = require('./common');
var NIL            = common.NIL;
var YAMLException  = require('./exception');
var DEFAULT_SCHEMA = require('./schema/default');
var SAFE_SCHEMA    = require('./schema/safe');

var _hasOwnProperty = Object.prototype.hasOwnProperty;

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(map) {
  var result, keys, index, length, tagName, tagPrefix, fullTagName;

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

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

  for (index = 0, length = keys.length; index < length; index += 1) {
    tagName = keys[index];
    tagPrefix = tagName.slice(0, 2);

    if ('!!' === tagPrefix) {
      fullTagName = 'tag:yaml.org,2002:' + tagName.slice(2);
      result[fullTagName] = map[tagName];
    } else {
      result[tagName] = map[tagName];
    }
  }

  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, settings) {
  var schema    = common.getOption(settings, 'schema', DEFAULT_SCHEMA),
      indent    = Math.max(1, common.getOption(settings, 'indent', 2)),
      flowLevel = common.getOption(settings, 'flowLevel', -1),
      styleMap  = compileStyleMap(common.getOption(settings, 'styles', null)),

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

      kind,
      tag,
      result;

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

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

    result = '';
    checkpoint = 0;

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

      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;
      }
    }

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

    result = '"' + result + '"';
  }

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

    for (index = 0, length = object.length; index < length; index += 1) {
      if (0 !== index) {
        _result += ', ';
      }

      writeNode(level, object[index], false, false);
      _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) {
      if (!compact || 0 !== index) {
        _result += generateNextLine(level);
      }

      writeNode(level + 1, object[index], true, true);
      _result += '- ' + result;
    }

    tag = _tag;
    result = _result;
  }

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

    for (index = 0, length = objectKeyList.length; index < length; index += 1) {
      if (0 !== index) {
        _result += ', ';
      }

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

      writeNode(level, objectKey, false, false);

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

      _result += result + ': ';
      writeNode(level, objectValue, false, false);
      _result += result;
    }

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

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

    for (index = 0, length = objectKeyList.length; index < length; index += 1) {
      if (!compact || 0 !== index) {
        _result += generateNextLine(level);
      }

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

      writeNode(level + 1, objectKey, true, true);
      explicitPair = (null !== tag && '?' !== tag && result.length <= 1024);

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

      _result += result;

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

      writeNode(level + 1, objectValue, true, explicitPair);
      _result += ': ' + result;
    }

    tag = _tag;
    result = _result;
  }

  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;
  }

  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) {
        writeBlockMapping(level, result, compact);
      } else {
        writeFlowMapping(level, result);
      }
    } else if ('array' === kind) {
      if (block) {
        writeBlockSequence(level, result, compact);
      } else {
        writeFlowSequence(level, result);
      }
    } else if ('string' === kind) {
      if ('?' !== tag) {
        writeQuotedScalar(result);
      }
    } else {
      throw new YAMLException('unacceptabe kind of an object to dump (' + kind + ')');
    }

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

  writeNode(0, input, true, true);
  return result;
}

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

module.exports.dump     = dump;
module.exports.safeDump = safeDump;
<commit_msg>[dumper] Add trailing line feed to the result;<commit_after>'use strict';

var common         = require('./common');
var NIL            = common.NIL;
var YAMLException  = require('./exception');
var DEFAULT_SCHEMA = require('./schema/default');
var SAFE_SCHEMA    = require('./schema/safe');

var _hasOwnProperty = Object.prototype.hasOwnProperty;

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(map) {
  var result, keys, index, length, tagName, tagPrefix, fullTagName;

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

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

  for (index = 0, length = keys.length; index < length; index += 1) {
    tagName = keys[index];
    tagPrefix = tagName.slice(0, 2);

    if ('!!' === tagPrefix) {
      fullTagName = 'tag:yaml.org,2002:' + tagName.slice(2);
      result[fullTagName] = map[tagName];
    } else {
      result[tagName] = map[tagName];
    }
  }

  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, settings) {
  var schema    = common.getOption(settings, 'schema', DEFAULT_SCHEMA),
      indent    = Math.max(1, common.getOption(settings, 'indent', 2)),
      flowLevel = common.getOption(settings, 'flowLevel', -1),
      styleMap  = compileStyleMap(common.getOption(settings, 'styles', null)),

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

      kind,
      tag,
      result;

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

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

    result = '';
    checkpoint = 0;

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

      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;
      }
    }

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

    result = '"' + result + '"';
  }

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

    for (index = 0, length = object.length; index < length; index += 1) {
      if (0 !== index) {
        _result += ', ';
      }

      writeNode(level, object[index], false, false);
      _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) {
      if (!compact || 0 !== index) {
        _result += generateNextLine(level);
      }

      writeNode(level + 1, object[index], true, true);
      _result += '- ' + result;
    }

    tag = _tag;
    result = _result;
  }

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

    for (index = 0, length = objectKeyList.length; index < length; index += 1) {
      if (0 !== index) {
        _result += ', ';
      }

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

      writeNode(level, objectKey, false, false);

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

      _result += result + ': ';
      writeNode(level, objectValue, false, false);
      _result += result;
    }

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

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

    for (index = 0, length = objectKeyList.length; index < length; index += 1) {
      if (!compact || 0 !== index) {
        _result += generateNextLine(level);
      }

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

      writeNode(level + 1, objectKey, true, true);
      explicitPair = (null !== tag && '?' !== tag && result.length <= 1024);

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

      _result += result;

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

      writeNode(level + 1, objectValue, true, explicitPair);
      _result += ': ' + result;
    }

    tag = _tag;
    result = _result;
  }

  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;
  }

  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) {
        writeBlockMapping(level, result, compact);
      } else {
        writeFlowMapping(level, result);
      }
    } else if ('array' === kind) {
      if (block) {
        writeBlockSequence(level, result, compact);
      } else {
        writeFlowSequence(level, result);
      }
    } else if ('string' === kind) {
      if ('?' !== tag) {
        writeQuotedScalar(result);
      }
    } else {
      throw new YAMLException('unacceptabe kind of an object to dump (' + kind + ')');
    }

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

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

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

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


<commit_before>(function(root) {

  var winston = require('winston');
  require('winston-daily-rotate-file');
  require('./winston-logstash.js');
  var util = require('./log-util.js'),
      _ = require('underscore');
  var stdoutOld = process.stdout.write,
      stderrOld = process.stderr.write;

  var overrideConsole = function(logger) {
    // override console.debug
    console.debug = console.debug || function() {
      try {
        logger.debug(util
          .convert(Array.prototype.slice.call(arguments)));
      } catch (e) {}
    };

    // override stdout
    process.stdout.write = (function(write) {
      return function(string, encoding, fd) {
        write.apply(process.stdout, arguments);
        logger.info((string || '').trim());
      };
    }(stdoutOld));

    // override stderr
    process.stderr.write = (function(write) {
      return function(string, encoding, fd) {
        write.apply(process.stderr, arguments);
        logger.error((string || '').trim());
      };
    }(stderrOld));
  };

  var def = {
    level: 'debug',                                   // log level
    file: process.pid + '.log',                       // default file name
    maxSize: 50000000,                                // default single file max size, 50m
    maxFiles: 10,                                     // default max files, 10
    logstash: {                                       // logstash configuration
      enable: false,                                  // if add logstash transport
      port: 9500,                                     // default logstash port, 9500
      host: '127.0.0.1'                               // default logstash host, 127.0.0.1
    },
    removeConsole: false,                             // remove console trasport
    overrideConsole: false,                           // override default console functions
    formatter: util.defFormatter,                     // log message formatter
    timestamp: util.defTimestamp,                     // log timestamp formatter
    json: false                                       // json format or not
  };

  module.exports = function(option) {

    return (function() {

      var log = function() {},
          opt = {};

      log.prototype.option = function(option) {
        opt = _.extend({}, def, option);
        return this;
      };

      log.prototype.getLogger = function() {
        // using default options if opt is empty
        opt = _.isEmpty(opt) ? def : opt;

        // remove console transport
        if (!!opt.removeConsole)
          winston.remove(winston.transports.Console);

        var transports = [];
        // register daily rotate transports
        transports.push(
          new winston.transports.DailyRotateFile({
            filename: opt.file,
            timestamp: opt.timestamp,
            formatter: opt.formatter,
            json: opt.json,
            maxsize: opt.maxSize,
            maxFiles: opt.maxFiles
          })
        );

        // register logstash transports
        if (!!opt.logstash.enable) {
          var logstash = new winston.transports.Logstash({
            port: opt.logstash.port,
            host: opt.logstash.host
          });
          logstash.setFormatter(opt.formatter);
          transports.push(logstash);
        }

        // get winston logger
        l = new winston.Logger({
          level: opt.level,
          transports: transports
        });

        // override console methods
        if (opt.overrideConsole)
          overrideConsole(l);

        return l;
      };

      log.prototype.lineFormatter = function(opt) {
        return util.lineFormatter(opt);
      };

      log.prototype.reset = function(logger) {
        logger.add(winston.transports.Console);
        logger.remove(winston.transports.DailyRotateFile);
        logger.remove(winston.transports.Logstash);
      };

      return new log();
    }());
  };

}(this));
<commit_msg>Change the logstash parameter<commit_after>(function(root) {

  var winston = require('winston');
  require('winston-daily-rotate-file');
  require('./winston-logstash.js');
  var util = require('./log-util.js'),
      _ = require('underscore');
  var stdoutOld = process.stdout.write,
      stderrOld = process.stderr.write;

  var overrideConsole = function(logger) {
    // override console.debug
    console.debug = console.debug || function() {
      try {
        logger.debug(util
          .convert(Array.prototype.slice.call(arguments)));
      } catch (e) {}
    };

    // override stdout
    process.stdout.write = (function(write) {
      return function(string, encoding, fd) {
        write.apply(process.stdout, arguments);
        logger.info((string || '').trim());
      };
    }(stdoutOld));

    // override stderr
    process.stderr.write = (function(write) {
      return function(string, encoding, fd) {
        write.apply(process.stderr, arguments);
        logger.error((string || '').trim());
      };
    }(stderrOld));
  };

  var def = {
    level: 'debug',                                   // log level
    file: process.pid + '.log',                       // default file name
    maxSize: 50000000,                                // default single file max size, 50m
    maxFiles: 10,                                     // default max files, 10
    logstash: {                                       // logstash configuration
      enable: false,                                  // if add logstash transport
      port: 9500,                                     // default logstash port, 9500
      host: '127.0.0.1'                               // default logstash host, 127.0.0.1
    },
    removeConsole: false,                             // remove console trasport
    overrideConsole: false,                           // override default console functions
    formatter: util.defFormatter,                     // log message formatter
    timestamp: util.defTimestamp,                     // log timestamp formatter
    json: false                                       // json format or not
  };

  module.exports = function(option) {

    return (function() {

      var log = function() {},
          opt = {};

      log.prototype.option = function(option) {
        opt = _.extend({}, def, option);
        return this;
      };

      log.prototype.getLogger = function() {
        // using default options if opt is empty
        opt = _.isEmpty(opt) ? def : opt;

        // remove console transport
        if (!!opt.removeConsole)
          winston.remove(winston.transports.Console);

        var transports = [];
        // register daily rotate transports
        transports.push(
          new winston.transports.DailyRotateFile({
            filename: opt.file,
            timestamp: opt.timestamp,
            formatter: opt.formatter,
            json: opt.json,
            maxsize: opt.maxSize,
            maxFiles: opt.maxFiles
          })
        );

        // register logstash transports
        if (!!opt.logstash.enable) {
          var logstash = new winston.transports.Logstash(opt.logstash);
          logstash.setFormatter(opt.formatter);
          transports.push(logstash);
        }

        // get winston logger
        l = new winston.Logger({
          level: opt.level,
          transports: transports
        });

        // override console methods
        if (opt.overrideConsole)
          overrideConsole(l);

        return l;
      };

      log.prototype.lineFormatter = function(opt) {
        return util.lineFormatter(opt);
      };

      log.prototype.reset = function(logger) {
        logger.add(winston.transports.Console);
        logger.remove(winston.transports.DailyRotateFile);
        logger.remove(winston.transports.Logstash);
      };

      return new log();
    }());
  };

}(this));
<|endoftext|>


<commit_before>(function(root) {

  var winston = require('winston');
  require('winston-daily-rotate-file');
  require('./winston-logstash.js');
  var util = require('./log-util.js'),
      _ = require('underscore');
  var stdoutOld = process.stdout.write,
      stderrOld = process.stderr.write;

  var overrideConsole = function(logger) {
    // override console.debug
    console.debug = console.debug || function() {
      try {
        logger.debug(util
          .convert(Array.prototype.slice.call(arguments)));
      } catch (e) {}
    };

    // override stdout
    process.stdout.write = (function(write) {
      return function(string, encoding, fd) {
        write.apply(process.stdout, arguments);
        logger.info((string || '').trim());
      };
    }(stdoutOld));

    // override stderr
    process.stderr.write = (function(write) {
      return function(string, encoding, fd) {
        write.apply(process.stderr, arguments);
        logger.error((string || '').trim());
      };
    }(stderrOld));
  };

  var def = {
    level: 'debug',                                   // log level
    file: process.pid + '.log',                       // default file name
    maxSize: 50000000,                                // default single file max size, 50m
    maxFiles: 10,                                     // default max files, 10
    logstash: {                                       // logstash configuration
      enable: false,                                  // if add logstash transport
      port: 9500,                                     // default logstash port, 9500
      host: '127.0.0.1'                               // default logstash host, 127.0.0.1
    },
    removeConsole: false,                             // remove console trasport
    overrideConsole: false,                           // override default console functions
    formatter: util.defFormatter,                     // log message formatter
    timestamp: util.defTimestamp,                     // log timestamp formatter
    json: false                                       // json format or not
  };

  module.exports = function(option) {

    return (function() {

      var log = function() {},
          opt = {};

      log.prototype.option = function(option) {
        opt = _.extend({}, def, option);
        return this;
      };

      log.prototype.getLogger = function() {
        // using default options if opt is empty
        opt = _.isEmpty(opt) ? def : opt;

        // remove console transport
        if (!!opt.removeConsole)
          winston.remove(winston.transports.Console);

        var transports = [];
        // register daily rotate transports
        transports.push(
          new winston.transports.DailyRotateFile({
            filename: opt.file,
            timestamp: opt.timestamp,
            formatter: opt.formatter,
            json: opt.json,
            maxsize: opt.maxSize,
            maxFiles: opt.maxFiles
          })
        );

        // register logstash transports
        if (!!opt.logstash.enable) {
          var logstash = new winston.transports.Logstash(opt.logstash);
          logstash.setFormatter(opt.formatter);
          transports.push(logstash);
        }

        // get winston logger
        l = new winston.Logger({
          level: opt.level,
          transports: transports
        });

        // override console methods
        if (opt.overrideConsole)
          overrideConsole(l);

        return l;
      };

      log.prototype.lineFormatter = function(opt) {
        return util.lineFormatter(opt);
      };

      log.prototype.reset = function(logger) {
        logger.add(winston.transports.Console);
        logger.remove(winston.transports.DailyRotateFile);
        logger.remove(winston.transports.Logstash);
      };

      return new log();
    }());
  };

}(this));
<commit_msg>Add the default error handler for transports<commit_after>(function(root) {

  var winston = require('winston');
  require('winston-daily-rotate-file');
  require('./winston-logstash.js');
  var util = require('./log-util.js'),
      _ = require('underscore');
  var stdoutOld = process.stdout.write,
      stderrOld = process.stderr.write;

  var overrideConsole = function(logger) {
    // override console.debug
    console.debug = console.debug || function() {
      try {
        logger.debug(util
          .convert(Array.prototype.slice.call(arguments)));
      } catch (e) {}
    };

    // override stdout
    process.stdout.write = (function(write) {
      return function(string, encoding, fd) {
        write.apply(process.stdout, arguments);
        logger.info((string || '').trim());
      };
    }(stdoutOld));

    // override stderr
    process.stderr.write = (function(write) {
      return function(string, encoding, fd) {
        write.apply(process.stderr, arguments);
        logger.error((string || '').trim());
      };
    }(stderrOld));
  };

  var def = {
    level: 'debug',                                   // log level
    filename: process.pid + '.log',                       // default file name
    maxsize: 50000000,                                // default single file max size, 50m
    maxFiles: 10,                                     // default max files, 10
    logstash: {                                       // logstash configuration
      enable: false,                                  // if add logstash transport
      port: 9500,                                     // default logstash port, 9500
      host: '127.0.0.1'                               // default logstash host, 127.0.0.1
    },
    removeConsole: false,                             // remove console trasport
    overrideConsole: false,                           // override default console functions
    formatter: util.defFormatter,                     // log message formatter
    timestamp: util.defTimestamp,                     // log timestamp formatter
    json: false                                       // json format or not
  };

  module.exports = function(option) {

    return (function() {

      var log = function() {},
          opt = {};

      log.prototype.option = function(option) {
        opt = _.extend({}, def, option);
        return this;
      };

      log.prototype.getLogger = function() {
        // using default options if opt is empty
        opt = _.isEmpty(opt) ? def : opt;

        // remove console transport
        if (!!opt.removeConsole)
          winston.remove(winston.transports.Console);

        var transports = [];
        // register daily rotate transports
        // pass the options to DailyRotateFile transports directly
        // so that all the options supported by DailyRotateFile can
        // be passed
        var daily = new winston.transports.DailyRotateFile(opt);
        transports.push(daily);

        // DailyRotateFile is inherited from winston Transport
        // register the error event handler by default
        // you can add your own handler by
        // this.getLogger.transports.dailyRotateFile.on('error', function(err) {...})
        daily.on('error', function(err) {
          console.log(err); // default just catch the error and print
        });

        // register logstash transports
        if (!!opt.logstash.enable) {
          var logstash = new winston.transports.Logstash(opt.logstash);
          logstash.setFormatter(opt.formatter);
          transports.push(logstash);

          // Logstash is inherited from winston Transport
          // register the error event handler by default
          // you can add your own handler by
          // this.getLogger.transports.logstash.on('error', function(err) {...})
          logstash.on('error', function(err) {
            console.log(err); // default just catch the error and print
          });
        }

        // get winston logger
        l = new winston.Logger({
          level: opt.level,
          transports: transports
        });

        // override console methods
        if (opt.overrideConsole)
          overrideConsole(l);

        return l;
      };

      log.prototype.lineFormatter = function(opt) {
        return util.lineFormatter(opt);
      };

      log.prototype.reset = function(logger) {
        logger.add(winston.transports.Console);
        logger.remove(winston.transports.DailyRotateFile);
        logger.remove(winston.transports.Logstash);
      };

      return new log();
    }());
  };

}(this));
<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react';
import {IndexLink, Link} from 'react-router';
import {connect} from 'react-redux';

@connect(
  state => ({
    loggedIn: state.auth.loggedIn
  })
)
export default class Header extends Component {
  static propTypes = {
    loggedIn: PropTypes.bool
  }

  render() {
    let links = [
      {
        to: '/trends',
        title: 'Github trends'
      },
      {
        to: '/about',
        title: 'About'
      }
    ];

    if (this.props.loggedIn) {
      links.push({
        to: '/profile',
        title: 'Profile'
      });
      links.push({
        to: '/logout',
        title: 'Logout'
      });
    } else {
      links.push({
        to: '/login',
        title: 'Login'
      });
    }

    return (

Redux universal boilerplate

          <IndexLink to="/" className="item" activeClassName="active">Homepage</IndexLink>
          {
            links.map(function(link, i) {
              return <Link to={link.to} key={i} className="item" activeClassName="active">{link.title}</Link>;
            })
          }

    );
  }
}
<commit_msg>Add link to 404 example page<commit_after>import React, {Component, PropTypes} from 'react';
import {IndexLink, Link} from 'react-router';
import {connect} from 'react-redux';

@connect(
  state => ({
    loggedIn: state.auth.loggedIn
  })
)
export default class Header extends Component {
  static propTypes = {
    loggedIn: PropTypes.bool
  }

  render() {
    let links = [
      {
        to: '/trends',
        title: 'Github trends'
      },
      {
        to: '/about',
        title: 'About'
      },
      {
        to: '/404',
        title: 'Non-exists page'
      }
    ];

    if (this.props.loggedIn) {
      links.push({
        to: '/profile',
        title: 'Profile'
      });
      links.push({
        to: '/logout',
        title: 'Logout'
      });
    } else {
      links.push({
        to: '/login',
        title: 'Login'
      });
    }

    return (

Redux universal boilerplate

          <IndexLink to="/" className="item" activeClassName="active">Homepage</IndexLink>
          {
            links.map(function(link, i) {
              return <Link to={link.to} key={i} className="item" activeClassName="active">{link.title}</Link>;
            })
          }

    );
  }
}
<|endoftext|>


<commit_before>function timeSpent() {
  // TODO: This should be the month selected, not today
  var today = new Date();
  var daysInMonth = new Date(today.getYear(), today.getMonth(), 0).getDate();
  var day = today.getDate();
  return day/daysInMonth;
}

(function addPacingColumnToBudget() {
  if (typeof Em !== 'undefined' && typeof Ember !== 'undefined' && typeof $ !== 'undefined') {
		$('.budget-table-cell-pacing').remove()

		$('.budget-table-header .budget-table-cell-available').after($("
PACING
"));

		$('.budget-table-row').each(function(){
			var available = parseFloat($(this).find('.budget-table-cell-available').text().replace("$","").replace(",",""));
			var activity = -parseFloat($(this).find('.budget-table-cell-activity').text().replace("$","").replace(",",""));
			var budgeted = available+activity;
			var burned = activity/budgeted;
			var pace = burned/timeSpent();

			var displayType = "dollars";
			if(displayType == "percentage") {
				if(pace > 1.25) {
					var temperature = "hot";
				} else if(pace > .75) {
					var temperature = "warm";
				} else {
					var temperature = "cool";
				}
				if(!isFinite(pace)) {
					var display = 999;
				} else {
					var display = Math.max(0,Math.round(pace*100));
				}
				if(pace > 0) {
					$(this).append("
"+display+"%
");
				}
			} else if (displayType == "dollars") {
				display = Math.round((budgeted*timeSpent()-activity)*1000);
				if(pace > 1.25) {
					var temperature = "hot";
				} else if(pace > 1) {
					var temperature = "warm";
				} else if(activity > 0) {
					var temperature = "cool";
				} else {
					var temperature = "neutral";
				}
				if(display >= 0) {
					var tooltip = "You have spent $"+ynab.formatCurrency(display)+" less than your available budget for this category "+Math.round(timeSpent()*100)+"% of the way through the month.";
				} else if(display < 0) {
					var tooltip = "You have spent $"+(ynab.formatCurrency(-display))+" more than your available budget for this category "+Math.round(timeSpent()*100)+"% of the way through the month.";
				}
				$(this).append("
$"+ynab.formatCurrency(display)+"
");
			}
		});

  }

	console.info("Updating pacing...");

  setTimeout(addPacingColumnToBudget, 500);
})();

<commit_msg>Clean up<commit_after>function timeSpent() {
  // TODO: This should be the month selected, not today
  var today = new Date();
  var daysInMonth = new Date(today.getYear(), today.getMonth(), 0).getDate();
  var day = today.getDate();
  return day/daysInMonth;
}

(function addPacingColumnToBudget() {
  if (typeof Em !== 'undefined' && typeof Ember !== 'undefined' && typeof $ !== 'undefined') {
    $('.budget-table-cell-pacing').remove()

    $('.budget-table-header .budget-table-cell-available').after($("
PACING
"));

    $('.budget-table-row').each(function(){
      var available = parseFloat($(this).find('.budget-table-cell-available').text().replace("$","").replace(",",""));
      var activity = -parseFloat($(this).find('.budget-table-cell-activity').text().replace("$","").replace(",",""));
      var budgeted = available+activity;
      var burned = activity/budgeted;
      var pace = burned/timeSpent();

      var displayType = "dollars";
      if(displayType == "percentage") {
        if(pace > 1.25) {
          var temperature = "hot";
        } else if(pace > .75) {
          var temperature = "warm";
        } else {
          var temperature = "cool";
        }
        if(!isFinite(pace)) {
          var display = 999;
        } else {
          var display = Math.max(0,Math.round(pace*100));
        }
        if(pace > 0) {
          $(this).append("
"+display+"%
");
        }
      } else if (displayType == "dollars") {
        display = Math.round((budgeted*timeSpent()-activity)*1000);
        if(pace > 1.25) {
          var temperature = "hot";
        } else if(pace > 1) {
          var temperature = "warm";
        } else if(activity > 0) {
          var temperature = "cool";
        } else {
          var temperature = "neutral";
        }
        if(display >= 0) {
          var tooltip = "You have spent $"+ynab.formatCurrency(display)+" less than your available budget for this category "+Math.round(timeSpent()*100)+"% of the way through the month.";
        } else if(display < 0) {
          var tooltip = "You have spent $"+(ynab.formatCurrency(-display))+" more than your available budget for this category "+Math.round(timeSpent()*100)+"% of the way through the month.";
        }
        $(this).append("
$"+ynab.formatCurrency(display)+"
");
      }
    });

  }

  setTimeout(addPacingColumnToBudget, 500);
})();

<|endoftext|>


<commit_before>"use strict";
define(["objects/Object",
		"objects/Module",
		"objects/Application",
		"objects/Router",
		"objects/View",
		"loaders/TemplateLoader",
		"loaders/AppLoader",
		"utils/MobileDetection",
		"utils/BrowserDetection",
		'openbiz.custom',
		'i18n!./nls/locale'
		],
	function(Object,
		Module,
		Application,
		Router,
		View,
		TemplateLoader,
		AppLoader,
		MobileDetection,
		BrowserDetection,
		updateUI,
		locale
		){
	return {
		apps:{},
		session:{},
		locale:locale,
		loaders:{
			TemplateLoader : TemplateLoader,
			AppLoader : AppLoader
		},
		objects:{
			Object : 	 Object,
			Application: Application,
			Module : 	 Module,
			Router : 	 Router,
			View   : 	 View
		},
		utils:{
			MobileDetection: MobileDetection,
			BrowserDetection: BrowserDetection
		},
		ui:{
			update: updateUI
		},
		baseUrl:openbizUrl,
		//shortcut alias
		Application: Application,
		Module: Module,
		Object: Object,
		Router: Router,
		View: 	View,
		isMobile: MobileDetection,
		Browser: BrowserDetection,
		loadApps: AppLoader.load,
		validator:{
			defaults:{
				messages:locale.validation,
				showErrors:false,
				validateIfUnchanged:true,
				listeners:{
					onFieldError:function(elem, constraints, ParsleyField){
						ParsleyField.manageValidationResult();
						$(elem).attr('data-validation-result','invalid');
						var showErrorPopup = function(){
							var message = $("#"+ParsleyField.hash);
							if(message.get(0)){
								var msgStr =message.find('li').last().text();
								message.hide();
								var popupElem = elem;
								if(ParsleyField.isRadioOrCheckbox){
									popupElem = elem.closest(".iCheck");
								}
								$(popupElem).attr("data-content",msgStr);
								if(!$(popupElem).attr('placement')){
									$(popupElem).attr('placement','auto');
								}
								$(popupElem).popover({
											html:false,
							    			trigger: 'manual'
							    		})
							    		.popover('show');
							}else{
								setTimeout(showErrorPopup,5);
							}

						}
						var highlightError = function(){
							if($(elem).closest(".input-group").length){
						    	$(elem).removeClass("parsley-error");
						    	$(elem).closest(".input-group").removeClass("parsley-success");
						    	$(elem).closest(".input-group").addClass("parsley-error");
						    }
						}
						highlightError();
						showErrorPopup();

					},
					onFieldSuccess:function(elem, constraints, ParsleyField){
						for(var i in constraints){
							if(constraints[i].valid==false) return;
						}
						var popupElem = elem;
						if(ParsleyField.isRadioOrCheckbox){
							popupElem = elem.closest(".iCheck");
							elem.closest(".iCheck").find("input").attr('data-validation-result','valid');
						}
						$(popupElem).attr('data-content','');
						$(popupElem).popover('hide');
						$(elem).attr('data-validation-result','valid');
						if($(elem).closest(".input-group").length){
							if($(elem).closest(".input-group").find("input[data-validation-result='invalid']").length==0){
								$(elem).removeClass("parsley-success");
					    		$(elem).closest(".input-group").removeClass("parsley-error");
					    		$(elem).closest(".input-group").addClass("parsley-success");
					    	}
					    }
					}
				}
			},
			init:function(){
				$.fn.parsley.defaults.showErrors = this.defaults.showErrors;
				$.fn.parsley.defaults.validateIfUnchanged = this.defaults.validateIfUnchanged;
				$.fn.parsley.defaults.messages = this.defaults.messages;
				$.fn.parsley.defaults.listeners.onFieldError = this.defaults.listeners.onFieldError;
				$.fn.parsley.defaults.listeners.onFieldSuccess = this.defaults.listeners.onFieldSuccess;
			}
		},
		init:function(){
			this.validator.init();
			this.ui.update();
		}
	}
});<commit_msg>update ui<commit_after>"use strict";
define(["objects/Object",
		"objects/Module",
		"objects/Application",
		"objects/Router",
		"objects/View",
		"loaders/TemplateLoader",
		"loaders/AppLoader",
		"utils/MobileDetection",
		"utils/BrowserDetection",
		'openbiz.custom',
		'i18n!./nls/locale'
		],
	function(Object,
		Module,
		Application,
		Router,
		View,
		TemplateLoader,
		AppLoader,
		MobileDetection,
		BrowserDetection,
		updateUI,
		locale
		){
	return {
		apps:{},
		session:{},
		locale:locale,
		loaders:{
			TemplateLoader : TemplateLoader,
			AppLoader : AppLoader
		},
		objects:{
			Object : 	 Object,
			Application: Application,
			Module : 	 Module,
			Router : 	 Router,
			View   : 	 View
		},
		utils:{
			MobileDetection: MobileDetection,
			BrowserDetection: BrowserDetection
		},
		ui:{
			update: updateUI
		},
		baseUrl:openbizUrl,
		//shortcut alias
		Application: Application,
		Module: Module,
		Object: Object,
		Router: Router,
		View: 	View,
		isMobile: MobileDetection,
		Browser: BrowserDetection,
		loadApps: AppLoader.load,
		validator:{
			defaults:{
				messages:locale.validation,
				showErrors:false,
				validateIfUnchanged:true,
				listeners:{
					onFieldError:function(elem, constraints, ParsleyField){
						ParsleyField.manageValidationResult();
						$(elem).attr('data-validation-result','invalid');
						var showErrorPopup = function(){
							var message = $("#"+ParsleyField.hash);
							if(message.get(0)){
								var msgStr =message.find('li').last().text();
								message.hide();
								var popupElem = elem;
								if(ParsleyField.isRadioOrCheckbox){
									popupElem = elem.closest(".iCheck");
								}
								$(popupElem).attr("data-content",msgStr);
								// if(!$(popupElem).attr('placement')){
								// 	$(popupElem).attr('placement','auto');
								// }
								$(popupElem).popover({
											html:false,
											placement:'auto',
							    			trigger: 'manual'
							    		})
							    		.popover('show');
							}else{
								setTimeout(showErrorPopup,5);
							}

						}
						var highlightError = function(){
							if($(elem).closest(".input-group").length){
						    	$(elem).removeClass("parsley-error");
						    	$(elem).closest(".input-group").removeClass("parsley-success");
						    	$(elem).closest(".input-group").addClass("parsley-error");
						    }
						}
						highlightError();
						showErrorPopup();

					},
					onFieldSuccess:function(elem, constraints, ParsleyField){
						for(var i in constraints){
							if(constraints[i].valid==false) return;
						}
						var popupElem = elem;
						if(ParsleyField.isRadioOrCheckbox){
							popupElem = elem.closest(".iCheck");
							elem.closest(".iCheck").find("input").attr('data-validation-result','valid');
						}
						$(popupElem).attr('data-content','');
						$(popupElem).popover('hide');
						$(elem).attr('data-validation-result','valid');
						if($(elem).closest(".input-group").length){
							if($(elem).closest(".input-group").find("input[data-validation-result='invalid']").length==0){
								$(elem).removeClass("parsley-success");
					    		$(elem).closest(".input-group").removeClass("parsley-error");
					    		$(elem).closest(".input-group").addClass("parsley-success");
					    	}
					    }
					}
				}
			},
			init:function(){
				$.fn.parsley.defaults.showErrors = this.defaults.showErrors;
				$.fn.parsley.defaults.validateIfUnchanged = this.defaults.validateIfUnchanged;
				$.fn.parsley.defaults.messages = this.defaults.messages;
				$.fn.parsley.defaults.listeners.onFieldError = this.defaults.listeners.onFieldError;
				$.fn.parsley.defaults.listeners.onFieldSuccess = this.defaults.listeners.onFieldSuccess;
			}
		},
		init:function(){
			this.validator.init();
			this.ui.update();
		}
	}
});<|endoftext|>


<commit_before>import {BindingEngine, inject} from 'aurelia-framework';
import {logger}                from '../../aurelia-form';

@inject(BindingEngine)
export class Conditional {

  constructor(bindingEngine) {
    this.bindingEngine = bindingEngine;
  }

  activate(field) {
    this.model  = field.value;
    this.schema = [];

    let calculateSchema = () => {
      let schema = field.element.schema(this.model);

      if (Array.isArray(schema)) {
        this.schema = schema;
        return schema;
      }

      // support promise
      // @todo check for type
      if (isPromise(schema)) {
        return schema.then(resolved => {
          this.schema = resolved;
        });
      }

      logger.error(`${field.element.type} does not return a schema`);
    };

    calculateSchema();

    if (typeof this.model === 'object' && field.element.observe) {
      this.observer = this.bindingEngine
        .propertyObserver(this.model, field.element.observe)
        .subscribe(calculateSchema);
    }
  }

  deactivate() {
    this.observer && this.observer.dispose();
  }

}

function isPromise(value) {
  return (typeof value === 'object' && value.then);
}
<commit_msg>fix(computed): check if instanceof Promise to check if is Promise<commit_after>import {BindingEngine, inject} from 'aurelia-framework';
import {logger}                from '../../aurelia-form';

@inject(BindingEngine)
export class Conditional {

  constructor(bindingEngine) {
    this.bindingEngine = bindingEngine;
  }

  activate(field) {
    this.model  = field.value;
    this.schema = [];

    let calculateSchema = () => {
      let schema = field.element.schema(this.model);

      if (Array.isArray(schema)) {
        this.schema = schema;
        return schema;
      }

      if (isPromise(schema)) {
        return schema.then(resolved => {
          this.schema = resolved;
        });
      }

      logger.error(`${field.element.type} does not return a schema`);
    };

    calculateSchema();

    if (typeof this.model === 'object' && field.element.observe) {
      this.observer = this.bindingEngine
        .propertyObserver(this.model, field.element.observe)
        .subscribe(calculateSchema);
    }
  }

  deactivate() {
    this.observer && this.observer.dispose();
  }

}

function isPromise(value) {
  return (value instanceof Promise)
}
<|endoftext|>


<commit_before>import React from "react";

import { push } from "redux-router";
import { connect } from "react-redux";

import DropDownMenu from 'material-ui/DropDownMenu';
import MenuItem from 'material-ui/MenuItem';

import {
    Actions as InterfaceActions,
    ActionKeyStore as InterfaceActionKeyStore
} from "../App/redux/actions";

import style from "./styles";

export class FiltersToolBarView extends React.Component {

    getFilteredVisualizationId() {
      const {
          visualizationId
      } = this.props;

      return visualizationId ? visualizationId.replace(/-/g, '') : '';
    }

    updateForceOptionContext(forceOptions, append) {
      const {
          context
      } = this.props;

      let forceContext = {};
      let filteredID = append ? this.getFilteredVisualizationId() : '';

      for(let key in forceOptions) {
        if(forceOptions.hasOwnProperty(key) && (!context[key] || context[key] !== forceOptions[key])) {
            forceContext[`${filteredID}${key}`] = forceOptions[key];
        }
      }

      return forceContext;
    }

    componentDidMount() {
        const {
            context,
            filterOptions,
            filterContext,
            visualizationId,
            saveFilterContext
        } = this.props;

        let configContexts = {};
        let filteredID = this.getFilteredVisualizationId();

        for(let name in filterOptions) {
            if (filterOptions.hasOwnProperty(name)) {
                let configOptions = filterOptions[name],
                    paramName     = visualizationId && configOptions.append ? `${filteredID}${configOptions.parameter}` : configOptions.parameter,
                    currentValue  = context[paramName],
                    defaultOption = []

                if (configOptions.options) {
                    let value = currentValue ? currentValue : configOptions.default;
                    // check value present in config. If not, then set value from default option
                    for(let i = 0; i < configOptions.options.length; i++) {
                        let option = configOptions.options[i];

                        if(option.value === value) {
                            defaultOption = []
                            defaultOption.push(option)
                            break;
                        }

                        if(option.default) {
                            defaultOption.push(option)
                        }
                    }

                    if(defaultOption.length) {
                        if(currentValue !== defaultOption[0].value) {
                            configContexts[paramName] = defaultOption[0].value
                        }

                        if(defaultOption[0].forceOptions) {
                            configContexts = Object.assign({}, configContexts, this.updateForceOptionContext(defaultOption[0].forceOptions, configOptions.append));
                        }
                    }
                }
            }
        };

        if(Object.keys(configContexts).length !== 0) {

            if(!Object.keys(filterContext).length) {
                saveFilterContext(configContexts)
            }
            this.props.goTo(window.location.pathname, Object.assign({}, context, configContexts))
        }
    }

    render() {
        const {
            filterOptions,
            context,
            visualizationId
        } = this.props

        let filteredID = this.getFilteredVisualizationId();

        if (!filterOptions || Object.keys(filterOptions).lengh === 0)
            return (

            );
        return (

                {

                    Object.keys(filterOptions).map((name, i) => {

                        let configOptions = filterOptions[name],
                            paramName = visualizationId && configOptions.append  ? `${filteredID}${configOptions.parameter}` : configOptions.parameter,
                            currentValue  = context[paramName] || configOptions.default;
                        return (

                                    {name}

                                <DropDownMenu
                                    name={name}
                                    value={currentValue}
                                    style={style.dropdownMenu}
                                    disabled={configOptions.disabled}
                                    >

                                    {configOptions.options.map((option, index) => {

                                        let queryParams = {};

                                        let forceOptions = option.forceOptions;

                                        if (forceOptions)
                                            queryParams = Object.assign({}, {[paramName]: option.value}, this.updateForceOptionContext(forceOptions, configOptions.append));

                                        return (
                                            <MenuItem
                                                key={index}
                                                value={option.value}
                                                primaryText={option.label}
                                                style={style.menuItem}
                                                disabled={option.disabled}
                                                onTouchTap={() => { this.props.saveFilterContext(queryParams); this.props.goTo(window.location.pathname, Object.assign({}, context, queryParams));}}
                                                />
                                        )
                                    })}
                                </DropDownMenu>

                        )
                    })}

        )
    }
}

FiltersToolBarView.propTypes = {
    filterOptions: React.PropTypes.object
};

const mapStateToProps = (state, ownProps) => ({
    context: state.interface.get(InterfaceActionKeyStore.CONTEXT),
    filterContext: state.interface.get(InterfaceActionKeyStore.FILTER_CONTEXT),
})

const actionCreators = (dispatch) => ({

    goTo: function(link, context) {
        dispatch(push({pathname:link, query:context}));
    },
    saveFilterContext: function(context) {
        dispatch(InterfaceActions.filterContext(context));
    }

});

export default connect(mapStateToProps, actionCreators)(FiltersToolBarView);
<commit_msg>Fixed empty forceOptions issue<commit_after>import React from "react";

import { push } from "redux-router";
import { connect } from "react-redux";

import DropDownMenu from 'material-ui/DropDownMenu';
import MenuItem from 'material-ui/MenuItem';

import {
    Actions as InterfaceActions,
    ActionKeyStore as InterfaceActionKeyStore
} from "../App/redux/actions";

import style from "./styles";

export class FiltersToolBarView extends React.Component {

    getFilteredVisualizationId() {
      const {
          visualizationId
      } = this.props;

      return visualizationId ? visualizationId.replace(/-/g, '') : '';
    }

    updateForceOptionContext(forceOptions, append) {
      const {
          context
      } = this.props;

      let forceContext = {};
      let filteredID = append ? this.getFilteredVisualizationId() : '';

      for(let key in forceOptions) {
        if(forceOptions.hasOwnProperty(key) && (!context[key] || context[key] !== forceOptions[key])) {
            forceContext[`${filteredID}${key}`] = forceOptions[key];
        }
      }

      return forceContext;
    }

    componentDidMount() {
        const {
            context,
            filterOptions,
            filterContext,
            visualizationId,
            saveFilterContext
        } = this.props;

        let configContexts = {};
        let filteredID = this.getFilteredVisualizationId();

        for(let name in filterOptions) {
            if (filterOptions.hasOwnProperty(name)) {
                let configOptions = filterOptions[name],
                    paramName     = visualizationId && configOptions.append ? `${filteredID}${configOptions.parameter}` : configOptions.parameter,
                    currentValue  = context[paramName],
                    defaultOption = []

                if (configOptions.options) {
                    let value = currentValue ? currentValue : configOptions.default;
                    // check value present in config. If not, then set value from default option
                    for(let i = 0; i < configOptions.options.length; i++) {
                        let option = configOptions.options[i];

                        if(option.value === value) {
                            defaultOption = []
                            defaultOption.push(option)
                            break;
                        }

                        if(option.default) {
                            defaultOption.push(option)
                        }
                    }

                    if(defaultOption.length) {
                        if(currentValue !== defaultOption[0].value) {
                            configContexts[paramName] = defaultOption[0].value
                        }

                        if(defaultOption[0].forceOptions) {
                            configContexts = Object.assign({}, configContexts, this.updateForceOptionContext(defaultOption[0].forceOptions, configOptions.append));
                        }
                    }
                }
            }
        };

        if(Object.keys(configContexts).length !== 0) {

            if(!Object.keys(filterContext).length) {
                saveFilterContext(configContexts)
            }
            this.props.goTo(window.location.pathname, Object.assign({}, context, configContexts))
        }
    }

    render() {
        const {
            filterOptions,
            context,
            visualizationId
        } = this.props

        let filteredID = this.getFilteredVisualizationId();

        if (!filterOptions || Object.keys(filterOptions).lengh === 0)
            return (

            );
        return (

                {

                    Object.keys(filterOptions).map((name, i) => {

                        let configOptions = filterOptions[name],
                            paramName = visualizationId && configOptions.append  ? `${filteredID}${configOptions.parameter}` : configOptions.parameter,
                            currentValue  = context[paramName] || configOptions.default;
                        return (

                                    {name}

                                <DropDownMenu
                                    name={name}
                                    value={currentValue}
                                    style={style.dropdownMenu}
                                    disabled={configOptions.disabled}
                                    >

                                    {configOptions.options.map((option, index) => {

                                        let queryParams = {[paramName]: option.value};

                                        let forceOptions = option.forceOptions;

                                        if (forceOptions)
                                            queryParams = Object.assign({}, queryParams, this.updateForceOptionContext(forceOptions, configOptions.append));

                                        return (
                                            <MenuItem
                                                key={index}
                                                value={option.value}
                                                primaryText={option.label}
                                                style={style.menuItem}
                                                disabled={option.disabled}
                                                onTouchTap={() => { this.props.saveFilterContext(queryParams); this.props.goTo(window.location.pathname, Object.assign({}, context, queryParams));}}
                                                />
                                        )
                                    })}
                                </DropDownMenu>

                        )
                    })}

        )
    }
}

FiltersToolBarView.propTypes = {
    filterOptions: React.PropTypes.object
};

const mapStateToProps = (state, ownProps) => ({
    context: state.interface.get(InterfaceActionKeyStore.CONTEXT),
    filterContext: state.interface.get(InterfaceActionKeyStore.FILTER_CONTEXT),
})

const actionCreators = (dispatch) => ({

    goTo: function(link, context) {
        dispatch(push({pathname:link, query:context}));
    },
    saveFilterContext: function(context) {
        dispatch(InterfaceActions.filterContext(context));
    }

});

export default connect(mapStateToProps, actionCreators)(FiltersToolBarView);
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { View, Text, StyleSheet, CameraRoll } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import IonicIcon from 'react-native-vector-icons/Ionicons';
import RNFetchBlob from 'react-native-fetch-blob';
import PXBottomSheet from '../components/PXBottomSheet';
import PXTouchable from '../components/PXTouchable';

const styles = StyleSheet.create({
  bottomSheetListItem: {
    flexDirection: 'row',
    justifyContent: 'flex-start',
    alignItems: 'center',
    height: 48,
  },
  bottomSheetText: {
    marginLeft: 32,
  },
  bottomSheetCancelIcon: {
    marginLeft: 3,
  },
  bottomSheetCancelText: {
    marginLeft: 36,
  },
});

class SaveImageBottomSheet extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isShowBottomSheet: false,
      imageUrls: [],
    };
  }

  openSaveImageBottomSheet = imageUrls => {
    this.setState({ isShowBottomSheet: true, imageUrls });
  };

  closeSaveImageBottomSheet = () => {
    this.setState({ isShowBottomSheet: false });
  };

  handleOnPressSaveImages = () => {
    const { imageUrls } = this.state;
    console.log('dl images ', imageUrls);
    const { dirs } = RNFetchBlob.fs;
    this.closeSaveImageBottomSheet();
    const downloadImagePromises = imageUrls.map(url => {
      const fileName = url.split('/').pop().split('#')[0].split('?')[0];
      return RNFetchBlob.config({
        path: `${dirs.DocumentDir}/${fileName}`,
      })
        .fetch('GET', url, {
          referer: 'http://www.pixiv.net',
          //'Cache-Control' : 'no-store'
        })
        .then(res => {
          console.log('The file saved to ', res.path());
          CameraRoll.saveToCameraRoll(res.path())
            .then(result => {
              console.log('save succeeded to camera roll ', result);
            })
            .catch(err => {
              console.log('save failed to camera roll ', err);
            });
        })
        .catch((err, statusCode) => {
          // error handling
          console.log('error fetch blob ', err, statusCode);
        })
        .then(() => null);
    });
    return Promise.all(downloadImagePromises).then(results => {
      console.log('finish download all images ', results);
    });
  };

  render() {
    const { isShowBottomSheet, imageUrls } = this.state;
    return (
      <PXBottomSheet
        visible={isShowBottomSheet}
        onCancel={this.closeSaveImageBottomSheet}
      >
        <View>
          <PXTouchable onPress={this.handleOnPressSaveImages}>
            <View style={styles.bottomSheetListItem}>
              <Icon name="floppy-o" size={24} />
              <Text style={styles.bottomSheetText}>
                {imageUrls.length > 1 ? 'Save All Images' : 'Save Image'}
              </Text>
            </View>
          </PXTouchable>
          <PXTouchable onPress={this.closeSaveImageBottomSheet}>
            <View style={styles.bottomSheetListItem}>
              <IonicIcon
                name="md-close"
                size={24}
                style={styles.bottomSheetCancelIcon}
              />
              <Text
                style={[styles.bottomSheetText, styles.bottomSheetCancelText]}
              >
                Cancel
              </Text>
            </View>
          </PXTouchable>
        </View>
      </PXBottomSheet>
    );
  }
}

export default SaveImageBottomSheet;
<commit_msg>fixed android save image<commit_after>import React, { Component } from 'react';
import {
  View,
  Text,
  StyleSheet,
  CameraRoll,
  Platform,
  PermissionsAndroid,
  Alert,
} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import IonicIcon from 'react-native-vector-icons/Ionicons';
import RNFetchBlob from 'react-native-fetch-blob';
import PXBottomSheet from '../components/PXBottomSheet';
import PXTouchable from '../components/PXTouchable';

const styles = StyleSheet.create({
  bottomSheetListItem: {
    flexDirection: 'row',
    justifyContent: 'flex-start',
    alignItems: 'center',
    height: 48,
  },
  bottomSheetText: {
    marginLeft: 32,
  },
  bottomSheetCancelIcon: {
    marginLeft: 3,
  },
  bottomSheetCancelText: {
    marginLeft: 36,
  },
});

class SaveImageBottomSheet extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isShowBottomSheet: false,
      imageUrls: [],
    };
  }

  openSaveImageBottomSheet = imageUrls => {
    this.setState({ isShowBottomSheet: true, imageUrls });
  };

  closeSaveImageBottomSheet = () => {
    this.setState({ isShowBottomSheet: false });
  };

  requestWriteExternalStoragePermission = async () => {
    try {
      const granted = await PermissionsAndroid.request(
        PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
        {
          title: 'Pixiv RN Storage Permission',
          message: 'Pixiv RN needs access to your storage ' +
            'so you can save your favorite images',
        },
      );
      return granted;
    } catch (err) {
      console.log('Failed to request Write External Storage Permission ', err);
      return null;
    }
  };

  handleOnPressSaveImages = async () => {
    const { imageUrls } = this.state;
    console.log('dl images ', imageUrls);
    this.closeSaveImageBottomSheet();
    if (Platform.OS === 'android') {
      const granted = await this.requestWriteExternalStoragePermission();
      if (granted === PermissionsAndroid.RESULTS.DENIED) {
        return null;
      }
      if (granted === PermissionsAndroid.RESULTS.NEVER_ASK_AGAIN) {
        Alert.alert(
          'Pixiv RN Storage Permission',
          'Storage Permission is required for download image feature, please enable it from system app settings',
          [{ text: 'OK' }],
          { cancelable: false },
        );
      }
    }
    const { dirs } = RNFetchBlob.fs;
    const imagesBaseDir = Platform.OS === 'android'
      ? dirs.PictureDir
      : dirs.DocumentDir;
    const imagesDir = `${imagesBaseDir}/pixivrn`;
    try {
      const imagesDirExists = await RNFetchBlob.fs.isDir(imagesDir);
      console.log('imagesDir ', imagesDir, imagesDirExists);
      if (!imagesDirExists) {
        await RNFetchBlob.fs.mkdir(imagesDir);
      }
    } catch (err) {
      console.log('failed to create imagesDir ', err);
    }
    const downloadImagePromises = imageUrls.map(async url => {
      const fileName = url.split('/').pop().split('#')[0].split('?')[0];
      try {
        const res = await RNFetchBlob.config({
          path: `${imagesDir}/${fileName}`,
        }).fetch('GET', url, {
          referer: 'http://www.pixiv.net',
        });
        const filePath = res.path();
        console.log('The file saved to ', filePath);
        if (Platform.OS === 'ios') {
          try {
            const cameraRollResult = await CameraRoll.saveToCameraRoll(
              filePath,
            );
            console.log('save succeeded to camera roll ', cameraRollResult);
          } catch (err) {
            console.log('save failed to camera roll ', err);
          }
        } else if (Platform.OS === 'android') {
          try {
            await RNFetchBlob.fs.scanFile([{ path: filePath }]);
            console.log('scan success ', filePath);
          } catch (err) {
            console.log('failed to scan ', filePath, err);
          }
        }
      } catch (err) {
        console.log('error fetch blob ', err);
      }
    });
    return Promise.all(downloadImagePromises).then(results => {
      console.log('finish download all images ', results);
    });
  };

  render() {
    const { isShowBottomSheet, imageUrls } = this.state;
    return (
      <PXBottomSheet
        visible={isShowBottomSheet}
        onCancel={this.closeSaveImageBottomSheet}
      >
        <View>
          <PXTouchable onPress={this.handleOnPressSaveImages}>
            <View style={styles.bottomSheetListItem}>
              <Icon name="floppy-o" size={24} />
              <Text style={styles.bottomSheetText}>
                {imageUrls.length > 1 ? 'Save All Images' : 'Save Image'}
              </Text>
            </View>
          </PXTouchable>
          <PXTouchable onPress={this.closeSaveImageBottomSheet}>
            <View style={styles.bottomSheetListItem}>
              <IonicIcon
                name="md-close"
                size={24}
                style={styles.bottomSheetCancelIcon}
              />
              <Text
                style={[styles.bottomSheetText, styles.bottomSheetCancelText]}
              >
                Cancel
              </Text>
            </View>
          </PXTouchable>
        </View>
      </PXBottomSheet>
    );
  }
}

export default SaveImageBottomSheet;
<|endoftext|>


<commit_before>var vumigo = require('vumigo_v02');
var events = vumigo.events;
var Eventable = events.Eventable;

var MetricsHelper = Eventable.extend(function(self, im) {
    /** class:MetricsHelper

    A helper for common metrics tasks.

    :param InteractionMachine im:
        The interaction machine that the metrics should be run on.

    */
    self.im = im;

    self.add = {};

    self.add.total_unique_users = function(label) {
        /** MetricsHelper.add.total_unique_users(label)

            Adds an inc metric that fires every time a new session is started
            with a new user.

            :param string label:
                The label for the metric. Defaults to ``unique_users``
        */
        label = typeof label !== 'undefined' ? label: 'unique_users';
        self.im.on('user user:new', function(e) {
            return e.user.im.metrics.fire.inc(label, 1);
        });
        return self;
    };

    self.add.total_sessions = function(label) {
        /** MetricsHelper.add.total_sessions(label)

            Adds an inc metric that fires every time a new session is started.

            :param string label:
                The label for the metric. Defaults to ``total_sessions``
        */
        label = typeof label !== 'undefined' ? label: 'total_sessions';
        self.im.on('session:new', function(e) {
            return e.im.metrics.fire.inc(label, 1);
        });
        return self;
    };

    self._validate_state_action = function(action) {
        /*
        Validates that ``action`` is a valid state action. Throws an exception
        if it is not a valid state action.
        */
        formatted_action = (typeof action === 'undefined'?'enter':action)
            .match(/(enter|exit|input|resume|show)/i);
        try {
            return formatted_action[0].toLowerCase();
        } catch(e) {
            throw "Invalid state action " + action;
        }
    };

    self._create_metric_label = function(pre, action, state) {
        /*
        Creates a label ``$pre_$action_$state`` that is valid for a metric.
        */
        return [pre, action, state.replace(/[^a-zA-Z0-9._]/g, '_')]
                    .join('_').substring(0,100);
    };

    self.add.total_state_actions = function(state, label) {
        /** MetricsHelper.add.total_state_actions(state, label)

            Adds an inc metric that fires every time the specified state action
            is triggered.

            :param object state:
                The name and action of the state to count actions for, e.g.

                .. code-block:: javascript

                {
                    state: 'states:foo',
                    action: 'exit'
                }

            :param string state.state:
                The name of the state to count the action for. Required.
            :param string state.action:
                The state action that should increment the count. Can be one of
                ``enter``, ``exit``, ``input``, ``resume``, and ``show``.
                Defaults to ``enter``.
            :param string label:
                The label for the metric. Defaults to
                ``total_action_$ACTION_$STATE`` where ``$ACTION`` is the
                specified action, and ``$STATE`` is the name of the state with
                all characters that are not ``a-zA-Z._`` replaced with ``_``.
        */
        var action = self._validate_state_action(state.action);

        label = typeof label !== 'undefined'
            ? label
            : self._create_metric_label('total_action', action, state.state);

        self.im.on('state:' + action, function(e) {
            if(e.state.name === state.state) {
                return e.state.im.metrics.fire.inc(label, 1);
            }
        });
        return self;
    };

    self._increment_metadata = function(user, label) {
    // Increments the specified metadata value
        var metadata = user.metadata;

        if (typeof metadata[label] === 'undefined'){
            metadata[label] = 0;
        }

        user.metadata[label] += 1;
    };

    self._get_metadata = function(user, label) {
    // Gets the specified metadata value, resets to zero, and returns value
        var metadata_value = user.metadata[label];
        user.metadata[label] = 0;
        return metadata_value;
    };

    self._set_metadata = function(user, label, value) {
        user.metadata[label] = value;
    };

    self.add.sessions_until_state = function(state, label) {
        /** MetricsHelper.add.sessions_until_state(state, label)

            Adds an average metric that counts the amount of sessions
            taken to reach the specified state action.

            :param object state:
                The name and action of the state to count actions for, e.g.

                .. code-block:: javascript

                {
                    state: 'states:foo',
                    action: 'exit'
                }

            :param string state.state:
                The name of the state to count the action for. Required.
            :param string state.action:
                The state action that should increment the count. Can be one of
                ``enter``, ``exit``, ``input``, ``resume``, and ``show``.
                Defaults to ``enter``.
            :param string label:
                The label for the metric. Defaults to
                ``sessions_until_$ACTION_$STATE`` where ``$ACTION`` is the
                specified action, and ``$STATE`` is the name of the state with
                all characters that are not ``a-zA-Z._`` replaced with ``_``.
        */
        var action = self._validate_state_action(state.action);
        label = typeof label !== 'undefined'
            ? label
            : self._create_metric_label('sessions_until', action, state.state);
        var metadata_label = 'sessions_until_state_metric_' + label;

        self.im.on('session:new', function(e) {
            /* Increment sessions counter */
            self._increment_metadata(e.im.user, metadata_label);
        });

        self.im.on('state:' + action, function(e) {
            /* Reset sessions counter and fire metric */
            if(e.state.name === state.state) {
                var metadata_value = self._get_metadata(
                    e.state.im.user, metadata_label);
                return e.state.im.metrics.fire.avg(label, metadata_value);
            }
        });

        return self;
    };

    self.add.time_between_states = function(state_from, state_to, label) {
        /** MetricsHelper.add.time_between_states(state_from, state_to, label)

            Adds an average metric that measures the amount of time taken
            between two state events. Metric stored as milliseconds.

            :param object state_from:
                The state where timing should start.
            :param object state_to:
                The state where timing should end.
            :param object state_*:
                The name and action of the state, e.g.

                .. code-block:: javascript

                {
                    state: 'states:foo',
                    action: 'exit'
                }

            :param string state_*.state:
                The name of the state. Required.
            :param string state_*.action:
                The state action. Can be one of ``enter``, ``exit``, ``input``,
                ``resume``, and ``show``. Defaults to ``enter``.
            :param string label:
                The label for the metric. Defaults to
                ``time_between_$ACTIONFROM_$STATEFROM_$ACTIONTO_$STATETO``
                where ``$ACTION_*`` is the specified action, and ``$STATE_*``
                is the name of the state with all characters that are not
                ``a-zA-Z._`` replaced with ``_``.
        */
        var from_action = self._validate_state_action(state_from.action);
        var to_action = self._validate_state_action(state_to.action);
        label = typeof label !== 'undefined'
            ? label
            : self._create_metric_label(
                'time_between', from_action, state_from.state) +
              self._create_metric_label('', to_action, state_to.state);
        var metadata_label = 'time_between_states_metric_' + label;

        self.im.on('state:' + from_action, function(e) {
            // Set timestamp
            if(e.state.name === state_from.state) {
                self._set_metadata(
                    e.state.im.user, metadata_label, Date.now());
            }
        });

        self.im.on('state:' + to_action, function(e) {
            // Fire metric with time difference
            if(e.state.name === state_to.state) {
                var time_from = self._get_metadata(
                    e.state.im.user, metadata_label);
                return e.state.im.metrics.fire.avg(
                    label, Date.now() - time_from);
            }
        });

        return self;
    };

});

this.MetricsHelper = MetricsHelper;
<commit_msg>Renamed _get_metadata to _reset_metadata<commit_after>var vumigo = require('vumigo_v02');
var events = vumigo.events;
var Eventable = events.Eventable;

var MetricsHelper = Eventable.extend(function(self, im) {
    /** class:MetricsHelper

    A helper for common metrics tasks.

    :param InteractionMachine im:
        The interaction machine that the metrics should be run on.

    */
    self.im = im;

    self.add = {};

    self.add.total_unique_users = function(label) {
        /** MetricsHelper.add.total_unique_users(label)

            Adds an inc metric that fires every time a new session is started
            with a new user.

            :param string label:
                The label for the metric. Defaults to ``unique_users``
        */
        label = typeof label !== 'undefined' ? label: 'unique_users';
        self.im.on('user user:new', function(e) {
            return e.user.im.metrics.fire.inc(label, 1);
        });
        return self;
    };

    self.add.total_sessions = function(label) {
        /** MetricsHelper.add.total_sessions(label)

            Adds an inc metric that fires every time a new session is started.

            :param string label:
                The label for the metric. Defaults to ``total_sessions``
        */
        label = typeof label !== 'undefined' ? label: 'total_sessions';
        self.im.on('session:new', function(e) {
            return e.im.metrics.fire.inc(label, 1);
        });
        return self;
    };

    self._validate_state_action = function(action) {
        /*
        Validates that ``action`` is a valid state action. Throws an exception
        if it is not a valid state action.
        */
        formatted_action = (typeof action === 'undefined'?'enter':action)
            .match(/(enter|exit|input|resume|show)/i);
        try {
            return formatted_action[0].toLowerCase();
        } catch(e) {
            throw "Invalid state action " + action;
        }
    };

    self._create_metric_label = function(pre, action, state) {
        /*
        Creates a label ``$pre_$action_$state`` that is valid for a metric.
        */
        return [pre, action, state.replace(/[^a-zA-Z0-9._]/g, '_')]
                    .join('_').substring(0,100);
    };

    self.add.total_state_actions = function(state, label) {
        /** MetricsHelper.add.total_state_actions(state, label)

            Adds an inc metric that fires every time the specified state action
            is triggered.

            :param object state:
                The name and action of the state to count actions for, e.g.

                .. code-block:: javascript

                {
                    state: 'states:foo',
                    action: 'exit'
                }

            :param string state.state:
                The name of the state to count the action for. Required.
            :param string state.action:
                The state action that should increment the count. Can be one of
                ``enter``, ``exit``, ``input``, ``resume``, and ``show``.
                Defaults to ``enter``.
            :param string label:
                The label for the metric. Defaults to
                ``total_action_$ACTION_$STATE`` where ``$ACTION`` is the
                specified action, and ``$STATE`` is the name of the state with
                all characters that are not ``a-zA-Z._`` replaced with ``_``.
        */
        var action = self._validate_state_action(state.action);

        label = typeof label !== 'undefined'
            ? label
            : self._create_metric_label('total_action', action, state.state);

        self.im.on('state:' + action, function(e) {
            if(e.state.name === state.state) {
                return e.state.im.metrics.fire.inc(label, 1);
            }
        });
        return self;
    };

    self._increment_metadata = function(user, label) {
    // Increments the specified metadata value
        var metadata = user.metadata;

        if (typeof metadata[label] === 'undefined'){
            metadata[label] = 0;
        }

        user.metadata[label] += 1;
    };

    self._reset_metadata = function(user, label) {
    // Gets the specified metadata value, resets to zero, and returns value
        var metadata_value = user.metadata[label];
        user.metadata[label] = 0;
        return metadata_value;
    };

    self._set_metadata = function(user, label, value) {
        user.metadata[label] = value;
    };

    self.add.sessions_until_state = function(state, label) {
        /** MetricsHelper.add.sessions_until_state(state, label)

            Adds an average metric that counts the amount of sessions
            taken to reach the specified state action.

            :param object state:
                The name and action of the state to count actions for, e.g.

                .. code-block:: javascript

                {
                    state: 'states:foo',
                    action: 'exit'
                }

            :param string state.state:
                The name of the state to count the action for. Required.
            :param string state.action:
                The state action that should increment the count. Can be one of
                ``enter``, ``exit``, ``input``, ``resume``, and ``show``.
                Defaults to ``enter``.
            :param string label:
                The label for the metric. Defaults to
                ``sessions_until_$ACTION_$STATE`` where ``$ACTION`` is the
                specified action, and ``$STATE`` is the name of the state with
                all characters that are not ``a-zA-Z._`` replaced with ``_``.
        */
        var action = self._validate_state_action(state.action);
        label = typeof label !== 'undefined'
            ? label
            : self._create_metric_label('sessions_until', action, state.state);
        var metadata_label = 'sessions_until_state_metric_' + label;

        self.im.on('session:new', function(e) {
            /* Increment sessions counter */
            self._increment_metadata(e.im.user, metadata_label);
        });

        self.im.on('state:' + action, function(e) {
            /* Reset sessions counter and fire metric */
            if(e.state.name === state.state) {
                var metadata_value = self._reset_metadata(
                    e.state.im.user, metadata_label);
                return e.state.im.metrics.fire.avg(label, metadata_value);
            }
        });

        return self;
    };

    self.add.time_between_states = function(state_from, state_to, label) {
        /** MetricsHelper.add.time_between_states(state_from, state_to, label)

            Adds an average metric that measures the amount of time taken
            between two state events. Metric stored as milliseconds.

            :param object state_from:
                The state where timing should start.
            :param object state_to:
                The state where timing should end.
            :param object state_*:
                The name and action of the state, e.g.

                .. code-block:: javascript

                {
                    state: 'states:foo',
                    action: 'exit'
                }

            :param string state_*.state:
                The name of the state. Required.
            :param string state_*.action:
                The state action. Can be one of ``enter``, ``exit``, ``input``,
                ``resume``, and ``show``. Defaults to ``enter``.
            :param string label:
                The label for the metric. Defaults to
                ``time_between_$ACTIONFROM_$STATEFROM_$ACTIONTO_$STATETO``
                where ``$ACTION_*`` is the specified action, and ``$STATE_*``
                is the name of the state with all characters that are not
                ``a-zA-Z._`` replaced with ``_``.
        */
        var from_action = self._validate_state_action(state_from.action);
        var to_action = self._validate_state_action(state_to.action);
        label = typeof label !== 'undefined'
            ? label
            : self._create_metric_label(
                'time_between', from_action, state_from.state) +
              self._create_metric_label('', to_action, state_to.state);
        var metadata_label = 'time_between_states_metric_' + label;

        self.im.on('state:' + from_action, function(e) {
            // Set timestamp
            if(e.state.name === state_from.state) {
                self._set_metadata(
                    e.state.im.user, metadata_label, Date.now());
            }
        });

        self.im.on('state:' + to_action, function(e) {
            // Fire metric with time difference
            if(e.state.name === state_to.state) {
                var time_from = self._reset_metadata(
                    e.state.im.user, metadata_label);
                return e.state.im.metrics.fire.avg(
                    label, Date.now() - time_from);
            }
        });

        return self;
    };

});

this.MetricsHelper = MetricsHelper;
<|endoftext|>