<commit_before>module.exports = {
  extends: 'eslint:recommended',
  parser: 'babel-eslint',
  plugins: [
    'react',
    'objects'
  ],
  env: {
    browser: true,
    node: true,
    es6: true,
    mocha: true
  },
  ecmaFeatures: {
    arrowFunctions: true,
    blockBindings: true,
    classes: true,
    defaultParams: true,
    destructuring: true,
    forOf: true,
    generators: false,
    modules: true,
    objectLiteralComputedProperties: true,
    objectLiteralDuplicateProperties: false,
    objectLiteralShorthandMethods: true,
    objectLiteralShorthandProperties: true,
    spread: true,
    superInFunctions: true,
    templateStrings: true,
    jsx: true
  },
  globals: {
    React: true
  },
  rules: {
    'arrow-spacing': [2, {'before': true, 'after': true}],
    'block-scoped-var': 2,
    'brace-style': [2, '1tbs', {'allowSingleLine': true}],
    'camelcase': [1, {'properties': 'always'}],
    'comma-dangle': [2, 'never'],
    'comma-spacing': [2, {'before': false, 'after': true}],
    'comma-style': [2, 'last'],
    'consistent-return': 2,
    'curly': [2, 'multi-line'],
    'default-case': 2,
    'dot-notation': [2, {'allowKeywords': true}],
    'eol-last': 2,
    'eqeqeq': 2,
    'func-names': 1,
    'guard-for-in': 2,
    'indent': [2, 2, { 'SwitchCase': 1 }],
    'init-declarations': [2, 'always'],
    'jsx-quotes': [2, 'prefer-double'],
    'key-spacing': [2],
    'max-len': [1, 80, 4],
    'new-cap': [2, {'newIsCap': true}],
    'no-alert': 1,
    'no-caller': 2,
    'no-class-assign': 2,
    'no-cond-assign': [2, 'always'],
    'no-console': 1,
    'no-const-assign': 2,
    'no-constant-condition': 1,
    'no-debugger': 1,
    'no-dupe-keys': 2,
    'no-duplicate-case': 2,
    'no-else-return': 2,
    'no-empty': 2,
    'no-eq-null': 2,
    'no-eval': 2,
    'no-ex-assign': 2,
    'no-extend-native': 2,
    'no-extra-bind': 2,
    'no-extra-boolean-cast': 0,
    'no-extra-parens': 0,
    'no-extra-semi': 2,
    'no-fallthrough': 2,
    'no-floating-decimal': 2,
    'no-func-assign': 2,
    'no-implicit-coercion': 2,
    'no-implied-eval': 2,
    'no-inner-declarations': 2,
    'no-invalid-regexp': 2,
    'no-irregular-whitespace': 2,
    'no-lone-blocks': 2,
    'no-loop-func': 2,
    'no-multi-str': 2,
    'no-multiple-empty-lines': [2, {'max': 2}],
    'no-native-reassign': 2,
    'no-nested-ternary': 2,
    'no-new-func': 2,
    'no-new-object': 2,
    'no-new-wrappers': 2,
    'no-new': 2,
    'no-obj-calls': 2,
    'no-octal-escape': 2,
    'no-octal': 2,
    'no-param-reassign': 2,
    'no-proto': 2,
    'no-redeclare': 2,
    'no-return-assign': 2,
    'no-script-url': 2,
    'no-self-compare': 2,
    'no-sequences': 2,
    'no-shadow-restricted-names': 2,
    'no-shadow': 2,
    'no-spaced-func': 2,
    'no-sparse-arrays': 2,
    'no-throw-literal': 2,
    'no-trailing-spaces': 2,
    'no-underscore-dangle': 0,
    'no-unreachable': 2,
    'no-unused-vars': [2, {'vars': 'local', 'args': 'after-used'}],
    'no-use-before-define': 2,
    'no-var': 2,
    'no-with': 2,
    'one-var': [2, 'never'],
    'padded-blocks': [2, 'never'],
    'prefer-reflect': [2],
    'prefer-spread': 2,
    'quote-props': [2, 'consistent-as-needed'],
    'quotes': [2, 'single', 'avoid-escape'],
    'radix': 2,
    'semi-spacing': [2, {'before': false, 'after': true}],
    'semi': [2, 'always'],
    'keyword-spacing': 2,
    'space-before-blocks': 2,
    'space-before-function-paren': [2, 'never'],
    'space-infix-ops': 2,
    'spaced-comment': 2,
    'strict': [2, 'never'],
    'use-isnan': 2,
    'vars-on-top': 2,
    'wrap-iife': [2, 'any'],
    'yoda': 2,
    'react/display-name': 0,
    'react/forbid-prop-types': 0,
    'react/jsx-boolean-value': 2,
    'react/jsx-closing-bracket-location': 2,
    'react/jsx-curly-spacing': [2, 'never'],
    'react/jsx-handler-names': 0,
    'react/jsx-indent-props': [2, 2],
    'react/jsx-indent': [2, 2],
    'react/jsx-key': 2,
    'react/jsx-max-props-per-line': 0,
    'react/jsx-no-bind': 2,
    'react/jsx-no-duplicate-props': 2,
    'react/jsx-no-literals': 2,
    'react/jsx-no-undef': 2,
    'react/jsx-pascal-case': 2,
    'react/jsx-sort-prop-types': 0,
    'react/jsx-sort-props': 0,
    'react/jsx-uses-react': 2,
    'react/jsx-uses-vars': 2,
    'react/no-danger': 0,
    'react/no-deprecated': 2,
    'react/no-did-mount-set-state': [2, 'allow-in-func'],
    'react/no-did-update-set-state': 2,
    'react/no-direct-mutation-state': 2,
    'react/no-is-mounted': 2,
    'react/no-multi-comp': 2,
    'react/no-set-state': 0,
    'react/no-string-refs': 2,
    'react/no-unknown-property': 2,
    'react/prefer-es6-class': 2,
    'react/prop-types': 2,
    'react/react-in-jsx-scope': 2,
    'react/require-extension': 0,
    'react/self-closing-comp': 2,
    'react/wrap-multilines': 2,
    'react/sort-comp': [2, {
      'order': [
        'constructor',
        'lifecycle',
        'everything-else',
        'render'
      ],
      'groups': {
        'lifecycle': [
          'displayName',
          'propTypes',
          'defaultProps',
          'contextTypes',
          'state',
          'childContextTypes',
          'mixins',
          'statics',
          'getDefaultProps',
          'getInitialState',
          'getChildContext',
          'componentWillMount',
          'componentDidMount',
          'componentWillReceiveProps',
          'shouldComponentUpdate',
          'componentWillUpdate',
          'componentDidUpdate',
          'componentWillUnmount'
        ]
      }
    }]
  }
};
<commit_msg>Added new rules<commit_after>module.exports = {
  extends: 'eslint:recommended',
  parser: 'babel-eslint',
  plugins: [
    'react',
    'objects'
  ],
  env: {
    browser: true,
    node: true,
    es6: true,
    mocha: true
  },
  ecmaFeatures: {
    arrowFunctions: true,
    blockBindings: true,
    classes: true,
    defaultParams: true,
    destructuring: true,
    forOf: true,
    generators: false,
    modules: true,
    objectLiteralComputedProperties: true,
    objectLiteralDuplicateProperties: false,
    objectLiteralShorthandMethods: true,
    objectLiteralShorthandProperties: true,
    spread: true,
    superInFunctions: true,
    templateStrings: true,
    jsx: true
  },
  globals: {
    React: true
  },
  rules: {
    'no-unused-labels': 2,
    'no-self-assign': 2,
    'no-new-symbol': 2,
    'arrow-spacing': [2, {'before': true, 'after': true}],
    'block-scoped-var': 2,
    'brace-style': [2, '1tbs', {'allowSingleLine': true}],
    'camelcase': [1, {'properties': 'always'}],
    'comma-dangle': [2, 'never'],
    'comma-spacing': [2, {'before': false, 'after': true}],
    'comma-style': [2, 'last'],
    'consistent-return': 2,
    'curly': [2, 'multi-line'],
    'default-case': 2,
    'dot-notation': [2, {'allowKeywords': true}],
    'eol-last': 2,
    'eqeqeq': 2,
    'func-names': 1,
    'guard-for-in': 2,
    'indent': [2, 2, { 'SwitchCase': 1 }],
    'init-declarations': [2, 'always'],
    'jsx-quotes': [2, 'prefer-double'],
    'key-spacing': [2],
    'max-len': [1, 80, 4],
    'new-cap': [2, {'newIsCap': true}],
    'no-alert': 1,
    'no-caller': 2,
    'no-class-assign': 2,
    'no-cond-assign': [2, 'always'],
    'no-console': 1,
    'no-const-assign': 2,
    'no-constant-condition': 1,
    'no-debugger': 1,
    'no-dupe-keys': 2,
    'no-duplicate-case': 2,
    'no-else-return': 2,
    'no-empty': 2,
    'no-eq-null': 2,
    'no-eval': 2,
    'no-ex-assign': 2,
    'no-extend-native': 2,
    'no-extra-bind': 2,
    'no-extra-boolean-cast': 0,
    'no-extra-parens': 0,
    'no-extra-semi': 2,
    'no-fallthrough': 2,
    'no-floating-decimal': 2,
    'no-func-assign': 2,
    'no-implicit-coercion': 2,
    'no-implied-eval': 2,
    'no-inner-declarations': 2,
    'no-invalid-regexp': 2,
    'no-irregular-whitespace': 2,
    'no-lone-blocks': 2,
    'no-loop-func': 2,
    'no-multi-str': 2,
    'no-multiple-empty-lines': [2, {'max': 2}],
    'no-native-reassign': 2,
    'no-nested-ternary': 2,
    'no-new-func': 2,
    'no-new-object': 2,
    'no-new-wrappers': 2,
    'no-new': 2,
    'no-obj-calls': 2,
    'no-octal-escape': 2,
    'no-octal': 2,
    'no-param-reassign': 2,
    'no-proto': 2,
    'no-redeclare': 2,
    'no-return-assign': 2,
    'no-script-url': 2,
    'no-self-compare': 2,
    'no-sequences': 2,
    'no-shadow-restricted-names': 2,
    'no-shadow': 2,
    'no-spaced-func': 2,
    'no-sparse-arrays': 2,
    'no-throw-literal': 2,
    'no-trailing-spaces': 2,
    'no-underscore-dangle': 0,
    'no-unreachable': 2,
    'no-unused-vars': [2, {'vars': 'local', 'args': 'after-used'}],
    'no-use-before-define': 2,
    'no-var': 2,
    'no-with': 2,
    'one-var': [2, 'never'],
    'padded-blocks': [2, 'never'],
    'prefer-reflect': [2],
    'prefer-spread': 2,
    'quote-props': [2, 'consistent-as-needed'],
    'quotes': [2, 'single', 'avoid-escape'],
    'radix': 2,
    'semi-spacing': [2, {'before': false, 'after': true}],
    'semi': [2, 'always'],
    'keyword-spacing': 2,
    'space-before-blocks': 2,
    'space-before-function-paren': [2, 'never'],
    'space-infix-ops': 2,
    'spaced-comment': 2,
    'strict': [2, 'never'],
    'use-isnan': 2,
    'vars-on-top': 2,
    'wrap-iife': [2, 'any'],
    'yoda': 2,
    'react/display-name': 0,
    'react/forbid-prop-types': 0,
    'react/jsx-boolean-value': 2,
    'react/jsx-closing-bracket-location': 2,
    'react/jsx-curly-spacing': [2, 'never'],
    'react/jsx-handler-names': 0,
    'react/jsx-indent-props': [2, 2],
    'react/jsx-indent': [2, 2],
    'react/jsx-key': 2,
    'react/jsx-max-props-per-line': 0,
    'react/jsx-no-bind': 2,
    'react/jsx-no-duplicate-props': 2,
    'react/jsx-no-literals': 2,
    'react/jsx-no-undef': 2,
    'react/jsx-pascal-case': 2,
    'react/jsx-sort-prop-types': 0,
    'react/jsx-sort-props': 0,
    'react/jsx-uses-react': 2,
    'react/jsx-uses-vars': 2,
    'react/no-danger': 0,
    'react/no-deprecated': 2,
    'react/no-did-mount-set-state': [2, 'allow-in-func'],
    'react/no-did-update-set-state': 2,
    'react/no-direct-mutation-state': 2,
    'react/no-is-mounted': 2,
    'react/no-multi-comp': 2,
    'react/no-set-state': 0,
    'react/no-string-refs': 2,
    'react/no-unknown-property': 2,
    'react/prefer-es6-class': 2,
    'react/prop-types': 2,
    'react/react-in-jsx-scope': 2,
    'react/require-extension': 0,
    'react/self-closing-comp': 2,
    'react/wrap-multilines': 2,
    'react/sort-comp': [2, {
      'order': [
        'constructor',
        'lifecycle',
        'everything-else',
        'render'
      ],
      'groups': {
        'lifecycle': [
          'displayName',
          'propTypes',
          'defaultProps',
          'contextTypes',
          'state',
          'childContextTypes',
          'mixins',
          'statics',
          'getDefaultProps',
          'getInitialState',
          'getChildContext',
          'componentWillMount',
          'componentDidMount',
          'componentWillReceiveProps',
          'shouldComponentUpdate',
          'componentWillUpdate',
          'componentDidUpdate',
          'componentWillUnmount'
        ]
      }
    }]
  }
};
<|endoftext|>


<commit_before>var Nanocomponent = require('nanocomponent')
var nanologger = require('nanologger')
var nanomorph = require('nanomorph')
var assert = require('assert')

var Nanotiming = require('./lib/timing')

module.exports = Microcomponent

function Microcomponent (opts) {
  if (!(this instanceof Microcomponent)) return new Microcomponent(opts)
  Nanocomponent.call(this)

  opts = opts || {}
  this.name = opts.name || 'component'
  this.oldProps = {}
  this.props = opts.props || {}
  this.state = opts.state || {}

  this._timing = new Nanotiming(this._name)
  this._log = nanologger(this._name)
  this._log.debug('initialized')
}
Microcomponent.prototype = Object.create(Nanocomponent.prototype)

Microcomponent.prototype.on = function (eventname, handler) {
  assert.equal(typeof eventname, 'string', 'microcomponent.on eventname should be type string')
  assert.equal(typeof handler, 'function', 'microcomponent.on handler should be type function')

  if (eventname === 'render') {
    this._render = function (props) {
      this._timing.start(eventname)
      this._log.debug(eventname, props)
      this.oldProps = this.props
      this.props = props

      if (this._element) {
        nanomorph(this._element, handler.call(this))
        this._timing.end(eventname)
      } else {
        var el = handler.call(this)
        this._timing.end(eventname)
        return el
      }
    }
  } else {
    this['_' + eventname] = function () {
      this._timing.start(eventname)
      var len = arguments.length
      var args = new Array(len)
      for (var i = 0; i < len; i++) args[i] = arguments[i]
      args.length
        ? this._log.debug(eventname, args)
        : this._log.debug(eventname)
      var res = handler.apply(this, args)
      this._timing.end(eventname)
      return res
    }
  }
}

Microcomponent.prototype.emit = function (eventname) {
  assert.equal(typeof eventname, 'string', 'microcomponent.emit eventname should be type string')
  var len = arguments.length - 1
  var args = new Array(len)
  for (var i = 0; i < len; i++) args[i] = arguments[i + 1]
  return this['_' + eventname].apply(this, args)
}
<commit_msg>fix typo (#5)<commit_after>var Nanocomponent = require('nanocomponent')
var nanologger = require('nanologger')
var nanomorph = require('nanomorph')
var assert = require('assert')

var Nanotiming = require('./lib/timing')

module.exports = Microcomponent

function Microcomponent (opts) {
  if (!(this instanceof Microcomponent)) return new Microcomponent(opts)
  Nanocomponent.call(this)

  opts = opts || {}
  this.name = opts.name || 'component'
  this.oldProps = {}
  this.props = opts.props || {}
  this.state = opts.state || {}

  this._timing = new Nanotiming(this.name)
  this._log = nanologger(this.name)
  this._log.debug('initialized')
}
Microcomponent.prototype = Object.create(Nanocomponent.prototype)

Microcomponent.prototype.on = function (eventname, handler) {
  assert.equal(typeof eventname, 'string', 'microcomponent.on eventname should be type string')
  assert.equal(typeof handler, 'function', 'microcomponent.on handler should be type function')

  if (eventname === 'render') {
    this._render = function (props) {
      this._timing.start(eventname)
      this._log.debug(eventname, props)
      this.oldProps = this.props
      this.props = props

      if (this._element) {
        nanomorph(this._element, handler.call(this))
        this._timing.end(eventname)
      } else {
        var el = handler.call(this)
        this._timing.end(eventname)
        return el
      }
    }
  } else {
    this['_' + eventname] = function () {
      this._timing.start(eventname)
      var len = arguments.length
      var args = new Array(len)
      for (var i = 0; i < len; i++) args[i] = arguments[i]
      args.length
        ? this._log.debug(eventname, args)
        : this._log.debug(eventname)
      var res = handler.apply(this, args)
      this._timing.end(eventname)
      return res
    }
  }
}

Microcomponent.prototype.emit = function (eventname) {
  assert.equal(typeof eventname, 'string', 'microcomponent.emit eventname should be type string')
  var len = arguments.length - 1
  var args = new Array(len)
  for (var i = 0; i < len; i++) args[i] = arguments[i + 1]
  return this['_' + eventname].apply(this, args)
}
<|endoftext|>


<commit_before>'use strict';

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

/*
 * function readSsl (options, callback)
 * Reads the SSL certificate information in the
 * specified options:
 *
 * options.root
 * options.cert
 * options.key
 * options.ca
 */
module.exports = function (options, callback) {
  var read = {};

  function readCertFile(key, file, next) {
    fs.readFile(file, function (err, data) {
      if (err) {
        return next(err);
      } else if (read[key]) {
        if (!Array.isArray(read[key])) {
          read[key] = [read[key]];
        }

        read[key].push(data);
        return next();
      }

      read[key] = data;
      next();
    });
  }

  var sources = ['cert', 'key', 'ca']
    .reduce(function (acc, key) {
      var list = !Array.isArray(options[key])
        ? [options[key]]
        : options[key];

      acc.push.apply(acc, list.map(function (file) {
        return { key: key, file: path.join(options.root, file) };
      }));

      return acc;
    }, []);

  (function readUntilEmpty(err) {
    if (err) {
      return callback(err);
    } else if (!sources.length) {
      return callback(null, read);
    }

    var source = sources.shift();
    readCertFile(source.key, source.file, readUntilEmpty);
  })();
};
<commit_msg>[fix] Add fix for "no ca" case.<commit_after>'use strict';

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

/*
 * function readSsl (options, callback)
 * Reads the SSL certificate information in the
 * specified options:
 *
 * options.root
 * options.cert
 * options.key
 * options.ca
 */
module.exports = function (options, callback) {
  var read = {};

  function readCertFile(key, file, next) {
    fs.readFile(file, function (err, data) {
      if (err) {
        return next(err);
      } else if (read[key]) {
        if (!Array.isArray(read[key])) {
          read[key] = [read[key]];
        }

        read[key].push(data);
        return next();
      }

      read[key] = data;
      next();
    });
  }

  var sources = ['cert', 'key', 'ca']
    .reduce(function (acc, key) {
      if (!options[key]) { return acc; }

      var list = !Array.isArray(options[key])
        ? [options[key]]
        : options[key];

      acc.push.apply(acc, list.map(function (file) {
        return { key: key, file: path.join(options.root, file) };
      }));

      return acc;
    }, []);

  (function readUntilEmpty(err) {
    if (err) {
      return callback(err);
    } else if (!sources.length) {
      return callback(null, read);
    }

    var source = sources.shift();
    readCertFile(source.key, source.file, readUntilEmpty);
  })();
};
<|endoftext|>


<commit_before>'use strict';

var ease = require('ease').ease;

(function () {
  var scrolling = false;

  exports.scrollToOffset = function (offset, duration) {
    if (offset === undefined) {
      throw new Error('missing scroll offset');
    }
    if (duration === undefined) {
      throw new Error('missing scroll duration');
    }
    if (scrolling) {
      return;
    }
    var startY = window.scrollY;
    var maxY = document.body.scrollHeight - window.innerHeight;
    var targetY = Math.min(offset, maxY);
    var distance = targetY - startY;
    var startT = Date.now();
    var targetT = startT + duration;
    var onAnimationFrame = function () {
      if (!scrolling) {
        return;
      }
      if (Date.now() >= targetT) {
        scrolling = false;
        window.scrollTo(window.scrollX, targetY);
        return;
      }
      var t = (Date.now() - startT) / duration;
      var y = startY + distance * ease(t);
      window.scrollTo(window.scrollX, y);
      window.requestAnimationFrame(onAnimationFrame);
    };
    scrolling = true;
    window.requestAnimationFrame(onAnimationFrame);
  };

  document.addEventListener('mousewheel', function () {
    scrolling = false;
  });
  // NOTE: This also enables :active pseudo-classes on links in Safari on iOS.
  document.addEventListener('touchstart', function () {
    scrolling = false;
  });
})();

exports.getElementOffsetById = function (id) {
  var target = document.getElementById(id);
  if (!target) {
    return undefined;
  }
  var y = 0;
  do {
    y += target.offsetTop;
    target = target.offsetParent;
  } while (target);
  return y;
};

exports.scrollToElementById = function (id, duration) {
  var offset = exports.getElementOffsetById(id);
  if (offset !== undefined) {
    exports.scrollToOffset(offset, duration, id);
  }
};
<commit_msg>Set target hash on scroll end<commit_after>'use strict';

var ease = require('ease').ease;

(function () {
  var scrolling = false;

  exports.scrollToOffset = function (offset, duration, target) {
    if (offset === undefined) {
      throw new Error('missing scroll offset');
    }
    if (duration === undefined) {
      throw new Error('missing scroll duration');
    }
    if (scrolling) {
      return;
    }
    var startY = window.scrollY;
    var maxY = document.body.scrollHeight - window.innerHeight;
    var targetY = Math.min(offset, maxY);
    var distance = targetY - startY;
    var startT = Date.now();
    var targetT = startT + duration;
    var onAnimationFrame = function () {
      if (!scrolling) {
        return;
      }
      if (Date.now() >= targetT) {
        scrolling = false;
        window.scrollTo(window.scrollX, targetY);
        if (target !== undefined) {
          window.location.hash = target;
        }
        return;
      }
      var t = (Date.now() - startT) / duration;
      var y = startY + distance * ease(t);
      window.scrollTo(window.scrollX, y);
      window.requestAnimationFrame(onAnimationFrame);
    };
    scrolling = true;
    window.requestAnimationFrame(onAnimationFrame);
  };

  document.addEventListener('mousewheel', function () {
    scrolling = false;
  });
  // NOTE: This also enables :active pseudo-classes on links in Safari on iOS.
  document.addEventListener('touchstart', function () {
    scrolling = false;
  });
})();

exports.getElementOffsetById = function (id) {
  var target = document.getElementById(id);
  if (!target) {
    return undefined;
  }
  var y = 0;
  do {
    y += target.offsetTop;
    target = target.offsetParent;
  } while (target);
  return y;
};

exports.scrollToElementById = function (id, duration) {
  var offset = exports.getElementOffsetById(id);
  if (offset !== undefined) {
    exports.scrollToOffset(offset, duration, id);
  }
};
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

(function (root, factory) {

    var MessageFormat = factory();

    // register in -all- the module systems (at once)
    if (typeof define === 'function' && define.amd) {
        define(MessageFormat);
    }

    if (typeof module === 'object' && typeof module.exports === 'object') {
        module.exports = MessageFormat;
    }

    if (root) {
        root.IntlMessageFormat = MessageFormat;
    }

})(typeof global !== 'undefined' ? global : this, function() {

    "use strict";

    var DEFAULT_LOCALE = null,
        // localeData registered by __addLocaleData()
        localeData = {};

    /**
     Creates MessageFormat object from a pattern, locale and field formatters.
     String patterns are broken down Arrays. Objects should match the
     following pattern:

     ```
     {
        type: 'plural|gender|select',
        valueName: 'string',
        offset: 1, // consistent offsets for plurals
        options: {}, // keys match options for plurals, gender and selects
        formatter: 'string|function' // strings are matched to internal formatters
     }
     ```

     @constructor

     @param {Array|String} pattern Array or string that serves as formatting pattern.
         Use array for plural and select messages, otherwise use string form.
     @param {LocaleList|String} locale Locale for string formatting.
     @param {Object} optFieldFormatters Holds user defined formatters for each field (Dojo like).
     */
    function MessageFormat (pattern, locale, optFieldFormatters) {
        var chunks,
            len,
            i,
            p;

        // store locale
        this.locale = locale;

        // Recommend to always provide a locale
        if (!locale) {
            this._log('It is recommended to provide a locale.', 'warn');
        }

        // We calculate the pluralization function used for the specific locale.
        // Since this is a bit expensive (if repeated too much) and since the
        // locale can change on us without notice, we need to keep track of
        // which locale was used in choosing the pluralization function.
        // (It's expected that the locale will change very infrequently for
        // each MessageFormat object.)
        this._pluralLocale = undefined;
        this._pluralFunc = undefined;

        // Assume the string passed in is a simple pattern for replacement.
        if (typeof pattern === 'string') {
            // break apart the string into chunks and tokens
            chunks = pattern.match(/((\$?\{)?[^\$\{\}]*\}?)/gi);

            // loop through each chunk and replace tokens when found
            for (i = 0, len = chunks.length; i < len; i++) {
                // create an object for the token when found
                if (/\$?\{(\w*):?(\w*)?\}/.test(chunks[i])) {

                    chunks[i] = {
                        // the valuename is the "key" for the token ... ${key}
                        valueName: chunks[i].match(/\$?\{(\w*):?(\w*)?\}/)[1],
                        formatter: chunks[i].match(/\$?\{(\w*):?(\w*)?\}/)[2],
                    };
                }
            }

            // our pattern should now be the chunked array
            pattern = chunks;
        }

        // save the pattern internally
        this.pattern = pattern;

        // store formatters
        this.formatters = {};

        if (optFieldFormatters) {
            for (p in optFieldFormatters) {
                if (optFieldFormatters.hasOwnProperty(p)) {
                    this.formatters[p] = optFieldFormatters[p];
                }
            }
        }
    }

    /**
     Formats pattern with supplied parameters.
     Dates, times and numbers are formatted in locale sensitive way.
     @param {Array|Object} params
     @return {String}
     */
    MessageFormat.prototype.format = function (obj) {

        var pattern = this.pattern,
            tokens,
            key,
            len,
            i;

        // the pattern we have is an array, we need to stitch it together
        // before moving forward
        if (Object.prototype.toString.call(pattern) === '[object Array]') {
            // let's not destroy the local pattern
            pattern = pattern.concat();

            // turn the array into a string
            pattern = this._processArray.call(this, pattern, obj);
        }

        // make sure we have a string
        pattern += '';

        // find tokens and replace with the object
        tokens = pattern.match(/\$?\{([^\} ]*)\}/g);

        // if there were any tokens found, we need to replace them with the
        if (tokens) {
            for (i = 0, len = tokens.length; i < len; i++) {
                // extract key out of ${key} or {key}
                key = tokens[i].charAt(0) === '$' ?
                        tokens[i].substr(2) :
                        tokens[i].substr(1);

                // remove trailing }
                key = key.substr(0, key.length - 1);

                // replace the token with obj[key]
                if (obj.hasOwnProperty(key)) {
                    pattern = pattern.replace(tokens[i], obj[key]);
                }
            }
        }

        return pattern;
    };

    /**
     Returns resolved options, in this case supported locale.
     @return {Object}
     */
    MessageFormat.prototype.resolvedOptions = function () {
        // TODO: Figure out what options should be returned for messages
        return {};
    };

    /**
     Normalizes the number to option values for plural identification
     @param {Number} count Number to normalize
     @return {String}
     */
    MessageFormat.prototype._normalizeCount = function (count) {
        var locale = this.locale || DEFAULT_LOCALE,
            data,
            fn,
            parts;

        // if the locale isn't set, and there is no default locale set, throw
        if (typeof locale === 'undefined' || locale === null) {
            throw new ReferenceError('No locale data has been provided for this object yet.');
        }

        // cache the choice of pluralization function
        if (this._pluralLocale !== locale) {
            if (locale !== DEFAULT_LOCALE) {
                parts = this.locale.toLowerCase().split('-');
                while (parts.length) {
                    data = localeData[parts.join('_')];
                    if (data && data.pluralFunction) {
                        fn = data.pluralFunction;
                        break;
                    }
                    parts.pop();
                }
            }
            if (!fn) {
                // While this seems excessive, it's possible the user has a
                // complex default locale (such as "zh-hans-CN") since the
                // default locale can come from a browser setting.
                parts = DEFAULT_LOCALE.toLowerCase().split('-');
                while (parts.length) {
                    data = localeData[parts.join('_')];
                    if (data && data.pluralFunction) {
                        fn = data.pluralFunction;
                        break;
                    }
                    parts.pop();
                }
            }
            if (!fn) {
                data = localeData[DEFAULT_LOCALE];
                fn = (data && data.pluralFunction) || function() {
                    return 'other';
                };
            }
            this._pluralLocale = locale;
            this._pluralFunc = fn;
        }
        return this._pluralFunc(count) || 'other';
    };

    /**
     Processes an array to return a string back once it's located. Arrays are
     concatenated. Each item is also processed based on whether it is an
     object or an array.
     @param {Array} arr
     @param {Object} obj
     @return {String}
     */
    MessageFormat.prototype._processArray = function (arr, obj) {
        var str = '',
            valType,
            val,
            len,
            i;

        // parse through the array to get the appropriate string value for each index
        for (i = 0, len = arr.length; i < len; i++) {

            val = arr[i];

            // If we don't already have a string, let's try to make it one
            if (typeof val !== 'string') {
                while (typeof val !== 'string') {
                    // let's find out what we are working with in the loop
                    valType = Object.prototype.toString.call(val);

                    if (valType === '[object Array]') {
                        val = this._processArray.call(this, val, obj);
                    } else if (valType === '[object Object]') {
                        val = this._processObject.call(this, val, obj);
                    } else {
                        // not an array or object, let's cast it and move on
                        val += '';
                    }
                }
            }

            // concat our new value to the return string
            str += val;
        }

        return str;
    };

    /**
     Processes the Object based on the lookUp object. Each object should have
     a `valueName` property; this property is used to located the value in the
     lookUp object.

     If the lookUp object returns a string, it will be sandwiched between
     `obj.prefix` and `obj.postfix` if they exist.

     @param {Ojbect} obj
     @param {Object} lookUp
     @return {String|Array|Object}
     */
    MessageFormat.prototype._processObject = function (obj, lookUp) {
        var val = lookUp[obj.valueName],
            valName = val,
            valType,
            formatterFn;

        // our look up object isn't in the provided lookUp object
        if (typeof val === 'undefined' || val === null) {
            throw new ReferenceError('The valueName `' + obj.valueName + '` was not found.');
        }

        // if we are dealing with plurals and we have a number, we need to
        // normalize the number's value based on the locale
        if (obj.type === 'plural' && typeof val === 'number') {
            if (obj.offset) {
                val += obj.offset;
            }

            val = this._normalizeCount(val);
        }

        // if we have an options property, we need the value from this object
        // as it relates to our value
        if (obj.options) {
            // options should always fallback to an "other" option when not found
            val = obj.options[val] || obj.options.other;
        }

        valType = typeof val;

        // if we have a string or number to return, we need to sandwich it
        // with (pre|post)fix
        if (valType === 'string' || valType === 'number') {

            // strings should be checked for hash tokens
            if (valType === 'string') {
                // We need to make sure we aren't doing a context look up `${#}`
                val = val.replace('${#}', valName);
            }

            // process with a formatter if one exists
            if (obj.formatter) {
                formatterFn = Object.prototype.toString.call(obj.formatter) === '[object Function]' ? obj.formatter : this.formatters[obj.formatter];

                if (formatterFn) {
                    val = formatterFn.call(this, val, this.locale);
                }
            }

            // sandwich
            val = (obj.prefix || '') + val + (obj.postfix || '');
        }

        return val;
    };

    /**
     Registers localization data for a particular locale.
     The format is:

     ```
     {
        locale: 'the locale',
        messageformat: {
            // This function takes a number (count) and turns it into a
            // pluralization group (e.g. 'one', 'few', 'many', 'other').
            pluralFunction: function(count) { return 'plural group' }
        }
     }
     ```

     @method __addLocaleData
     @param {Object} The locale data as described above.
     @return {nothing}
     */
    MessageFormat.__addLocaleData = function(data) {

        // if there isn't a default locale set, set it out of the data.locale
        if (DEFAULT_LOCALE === null) {
            DEFAULT_LOCALE = data.locale;
        }

        localeData[data.locale] = data.messageformat;
    };

    MessageFormat.__purge = function () {
        DEFAULT_LOCALE = null;
        localeData = {};
    };

    MessageFormat.prototype._log = function (msg, type) {
        if (!console) {
            // no console; fail silently
            return;
        }

        if (console.hasOwnProperty(type)) {
            console[type](msg);
        } else {
            console.log(msg);
        }
    };

    return MessageFormat;
});

<commit_msg>Use typeof instead of Object...toString() to check for Function<commit_after>/*
 * Copyright (c) 2011-2013, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */

(function (root, factory) {

    var MessageFormat = factory();

    // register in -all- the module systems (at once)
    if (typeof define === 'function' && define.amd) {
        define(MessageFormat);
    }

    if (typeof module === 'object' && typeof module.exports === 'object') {
        module.exports = MessageFormat;
    }

    if (root) {
        root.IntlMessageFormat = MessageFormat;
    }

})(typeof global !== 'undefined' ? global : this, function() {

    "use strict";

    var DEFAULT_LOCALE = null,
        // localeData registered by __addLocaleData()
        localeData = {};

    /**
     Creates MessageFormat object from a pattern, locale and field formatters.
     String patterns are broken down Arrays. Objects should match the
     following pattern:

     ```
     {
        type: 'plural|gender|select',
        valueName: 'string',
        offset: 1, // consistent offsets for plurals
        options: {}, // keys match options for plurals, gender and selects
        formatter: 'string|function' // strings are matched to internal formatters
     }
     ```

     @constructor

     @param {Array|String} pattern Array or string that serves as formatting pattern.
         Use array for plural and select messages, otherwise use string form.
     @param {LocaleList|String} locale Locale for string formatting.
     @param {Object} optFieldFormatters Holds user defined formatters for each field (Dojo like).
     */
    function MessageFormat (pattern, locale, optFieldFormatters) {
        var chunks,
            len,
            i,
            p;

        // store locale
        this.locale = locale;

        // Recommend to always provide a locale
        if (!locale) {
            this._log('It is recommended to provide a locale.', 'warn');
        }

        // We calculate the pluralization function used for the specific locale.
        // Since this is a bit expensive (if repeated too much) and since the
        // locale can change on us without notice, we need to keep track of
        // which locale was used in choosing the pluralization function.
        // (It's expected that the locale will change very infrequently for
        // each MessageFormat object.)
        this._pluralLocale = undefined;
        this._pluralFunc = undefined;

        // Assume the string passed in is a simple pattern for replacement.
        if (typeof pattern === 'string') {
            // break apart the string into chunks and tokens
            chunks = pattern.match(/((\$?\{)?[^\$\{\}]*\}?)/gi);

            // loop through each chunk and replace tokens when found
            for (i = 0, len = chunks.length; i < len; i++) {
                // create an object for the token when found
                if (/\$?\{(\w*):?(\w*)?\}/.test(chunks[i])) {

                    chunks[i] = {
                        // the valuename is the "key" for the token ... ${key}
                        valueName: chunks[i].match(/\$?\{(\w*):?(\w*)?\}/)[1],
                        formatter: chunks[i].match(/\$?\{(\w*):?(\w*)?\}/)[2],
                    };
                }
            }

            // our pattern should now be the chunked array
            pattern = chunks;
        }

        // save the pattern internally
        this.pattern = pattern;

        // store formatters
        this.formatters = {};

        if (optFieldFormatters) {
            for (p in optFieldFormatters) {
                if (optFieldFormatters.hasOwnProperty(p)) {
                    this.formatters[p] = optFieldFormatters[p];
                }
            }
        }
    }

    /**
     Formats pattern with supplied parameters.
     Dates, times and numbers are formatted in locale sensitive way.
     @param {Array|Object} params
     @return {String}
     */
    MessageFormat.prototype.format = function (obj) {

        var pattern = this.pattern,
            tokens,
            key,
            len,
            i;

        // the pattern we have is an array, we need to stitch it together
        // before moving forward
        if (Object.prototype.toString.call(pattern) === '[object Array]') {
            // let's not destroy the local pattern
            pattern = pattern.concat();

            // turn the array into a string
            pattern = this._processArray.call(this, pattern, obj);
        }

        // make sure we have a string
        pattern += '';

        // find tokens and replace with the object
        tokens = pattern.match(/\$?\{([^\} ]*)\}/g);

        // if there were any tokens found, we need to replace them with the
        if (tokens) {
            for (i = 0, len = tokens.length; i < len; i++) {
                // extract key out of ${key} or {key}
                key = tokens[i].charAt(0) === '$' ?
                        tokens[i].substr(2) :
                        tokens[i].substr(1);

                // remove trailing }
                key = key.substr(0, key.length - 1);

                // replace the token with obj[key]
                if (obj.hasOwnProperty(key)) {
                    pattern = pattern.replace(tokens[i], obj[key]);
                }
            }
        }

        return pattern;
    };

    /**
     Returns resolved options, in this case supported locale.
     @return {Object}
     */
    MessageFormat.prototype.resolvedOptions = function () {
        // TODO: Figure out what options should be returned for messages
        return {};
    };

    /**
     Normalizes the number to option values for plural identification
     @param {Number} count Number to normalize
     @return {String}
     */
    MessageFormat.prototype._normalizeCount = function (count) {
        var locale = this.locale || DEFAULT_LOCALE,
            data,
            fn,
            parts;

        // if the locale isn't set, and there is no default locale set, throw
        if (typeof locale === 'undefined' || locale === null) {
            throw new ReferenceError('No locale data has been provided for this object yet.');
        }

        // cache the choice of pluralization function
        if (this._pluralLocale !== locale) {
            if (locale !== DEFAULT_LOCALE) {
                parts = this.locale.toLowerCase().split('-');
                while (parts.length) {
                    data = localeData[parts.join('_')];
                    if (data && data.pluralFunction) {
                        fn = data.pluralFunction;
                        break;
                    }
                    parts.pop();
                }
            }
            if (!fn) {
                // While this seems excessive, it's possible the user has a
                // complex default locale (such as "zh-hans-CN") since the
                // default locale can come from a browser setting.
                parts = DEFAULT_LOCALE.toLowerCase().split('-');
                while (parts.length) {
                    data = localeData[parts.join('_')];
                    if (data && data.pluralFunction) {
                        fn = data.pluralFunction;
                        break;
                    }
                    parts.pop();
                }
            }
            if (!fn) {
                data = localeData[DEFAULT_LOCALE];
                fn = (data && data.pluralFunction) || function() {
                    return 'other';
                };
            }
            this._pluralLocale = locale;
            this._pluralFunc = fn;
        }
        return this._pluralFunc(count) || 'other';
    };

    /**
     Processes an array to return a string back once it's located. Arrays are
     concatenated. Each item is also processed based on whether it is an
     object or an array.
     @param {Array} arr
     @param {Object} obj
     @return {String}
     */
    MessageFormat.prototype._processArray = function (arr, obj) {
        var str = '',
            valType,
            val,
            len,
            i;

        // parse through the array to get the appropriate string value for each index
        for (i = 0, len = arr.length; i < len; i++) {

            val = arr[i];

            // If we don't already have a string, let's try to make it one
            if (typeof val !== 'string') {
                while (typeof val !== 'string') {
                    // let's find out what we are working with in the loop
                    valType = Object.prototype.toString.call(val);

                    if (valType === '[object Array]') {
                        val = this._processArray.call(this, val, obj);
                    } else if (valType === '[object Object]') {
                        val = this._processObject.call(this, val, obj);
                    } else {
                        // not an array or object, let's cast it and move on
                        val += '';
                    }
                }
            }

            // concat our new value to the return string
            str += val;
        }

        return str;
    };

    /**
     Processes the Object based on the lookUp object. Each object should have
     a `valueName` property; this property is used to located the value in the
     lookUp object.

     If the lookUp object returns a string, it will be sandwiched between
     `obj.prefix` and `obj.postfix` if they exist.

     @param {Ojbect} obj
     @param {Object} lookUp
     @return {String|Array|Object}
     */
    MessageFormat.prototype._processObject = function (obj, lookUp) {
        var val = lookUp[obj.valueName],
            valName = val,
            valType,
            formatterFn;

        // our look up object isn't in the provided lookUp object
        if (typeof val === 'undefined' || val === null) {
            throw new ReferenceError('The valueName `' + obj.valueName + '` was not found.');
        }

        // if we are dealing with plurals and we have a number, we need to
        // normalize the number's value based on the locale
        if (obj.type === 'plural' && typeof val === 'number') {
            if (obj.offset) {
                val += obj.offset;
            }

            val = this._normalizeCount(val);
        }

        // if we have an options property, we need the value from this object
        // as it relates to our value
        if (obj.options) {
            // options should always fallback to an "other" option when not found
            val = obj.options[val] || obj.options.other;
        }

        valType = typeof val;

        // if we have a string or number to return, we need to sandwich it
        // with (pre|post)fix
        if (valType === 'string' || valType === 'number') {

            // strings should be checked for hash tokens
            if (valType === 'string') {
                // We need to make sure we aren't doing a context look up `${#}`
                val = val.replace('${#}', valName);
            }

            // process with a formatter if one exists
            if (obj.formatter) {
                formatterFn = (typeof obj.formatter === 'function') ? obj.formatter : this.formatters[obj.formatter];

                if (formatterFn) {
                    val = formatterFn.call(this, val, this.locale);
                }
            }

            // sandwich
            val = (obj.prefix || '') + val + (obj.postfix || '');
        }

        return val;
    };

    /**
     Registers localization data for a particular locale.
     The format is:

     ```
     {
        locale: 'the locale',
        messageformat: {
            // This function takes a number (count) and turns it into a
            // pluralization group (e.g. 'one', 'few', 'many', 'other').
            pluralFunction: function(count) { return 'plural group' }
        }
     }
     ```

     @method __addLocaleData
     @param {Object} The locale data as described above.
     @return {nothing}
     */
    MessageFormat.__addLocaleData = function(data) {

        // if there isn't a default locale set, set it out of the data.locale
        if (DEFAULT_LOCALE === null) {
            DEFAULT_LOCALE = data.locale;
        }

        localeData[data.locale] = data.messageformat;
    };

    MessageFormat.__purge = function () {
        DEFAULT_LOCALE = null;
        localeData = {};
    };

    MessageFormat.prototype._log = function (msg, type) {
        if (!console) {
            // no console; fail silently
            return;
        }

        if (console.hasOwnProperty(type)) {
            console[type](msg);
        } else {
            console.log(msg);
        }
    };

    return MessageFormat;
});

<|endoftext|>


<commit_before>var base65536 = require('base65536');
var lzma = require('lzma');
var requestify = require('requestify');

var bool_array = new Array(32);
var id_array = new Array(32);
var raw_binary = "";
var int_val;

// Run everything
run_all();

// All the helpers
function printArray() {
    array_to_int();
    int_val = parseInt(raw_binary, 2);
    console.log("Integer value: " + int_val);
    process_ids();
}

function process_ids() {
    var raw_id_string = id_array.join('');
    console.log(raw_id_string);
    raw_id_string = raw_id_string.replace(/-/g, "");
    var compressed = lzma.compress(raw_id_string);
    console.log(compressed.join(''));
    compressed = compressed.replace(" ", "");
    console.log("Compressed ID: " + compressed);
}

var count = 0;
function run_all() {
    for(var i = 0; i < 32; ++i) {
        request_bool(i).then(function(response) {
            count++;
            if(count === 32) {
                printArray();
            }
        }, function(error) {
            console.error(error);
        });
    }
}

function request_bool(index) {
    return new Promise(function(resolve, reject) {
        var ran_val = Math.random()<.5;
        requestify.request('https://api.booleans.io', {
            method: 'POST',
            body: {
                val: ran_val
            },
            headers: {
                'Content-Type': 'application/json'
            },
            dataType: 'json'
        })
        .then(function(response) {
            var body = response.getBody();
            bool_array[index] = body.val;
            id_array[index] = body.id;
            resolve("Success!");
        })
        .fail(function(error) {
            reject("Error getting boolean. " + error);
        });
    });
}

function array_to_int() {
    var output = "";
    for(var index in bool_array) {
        if(bool_array[index]) {
            output = "1" + output;
        } else {
            output = "0" + output;
        }
    }
    raw_binary = output;
    console.log("Assembled binary val: " + output);
}

<commit_msg>working on compression<commit_after>var base65536 = require('base65536');
var requestify = require('requestify');
var LZString = require('lz-string');

var bool_array = new Array(32);
var id_array = new Array(32);
var raw_binary = "";
var int_val;

// Run everything
run_all();

// All the helpers
function printArray() {
    array_to_int();
    int_val = parseInt(raw_binary, 2);
    console.log("Integer value: " + int_val);
    process_ids();
}

function process_ids() {
    var raw_id_string = id_array.join('');
    raw_id_string = raw_id_string.replace(/-/g, "");
    console.log("Length of string is " + raw_id_string.length);
    console.log(raw_id_string);
    var buf = new Buffer(raw_id_string);
    var minified = base65536.encode(buf);
    console.log("Minified length is " + minified.length);
    console.log(minified);
}

var count = 0;
function run_all() {
    for(var i = 0; i < 32; ++i) {
        request_bool(i).then(function(response) {
            count++;
            if(count === 32) {
                printArray();
            }
        }, function(error) {
            console.error(error);
        });
    }
}

function request_bool(index) {
    return new Promise(function(resolve, reject) {
        var ran_val = Math.random()<.5;
        requestify.request('https://api.booleans.io', {
            method: 'POST',
            body: {
                val: ran_val
            },
            headers: {
                'Content-Type': 'application/json'
            },
            dataType: 'json'
        })
        .then(function(response) {
            var body = response.getBody();
            bool_array[index] = body.val;
            id_array[index] = body.id;
            resolve("Success!");
        })
        .fail(function(error) {
            reject("Error getting boolean. " + error);
        });
    });
}

function array_to_int() {
    var output = "";
    for(var index in bool_array) {
        if(bool_array[index]) {
            output = "1" + output;
        } else {
            output = "0" + output;
        }
    }
    raw_binary = output;
    console.log("Assembled binary val: " + output);
}

<|endoftext|>


<commit_before>'use strict'
const UsageStats = require('app-usage-stats')
const os = require('os')

module.exports = function (SuperClass, version) {
  return class JsdocToMarkdownStats extends SuperClass {
    constructor () {
      super()
      this._usage = new UsageStats('UA-70853320-3', {
        name: 'jsdoc2md',
        version: version,
        sendInterval: 1000 * 60 * 60 * 24, // 24 hours
        metricMap: {
          invocation: 1,
          source: 2,
          configure: 3,
          html: 4,
          template: 5,
          'heading-depth': 6,
          'example-lang': 7,
          plugin: 8,
          helper: 9,
          partial: 10,
          'name-format': 11,
          'no-gfm': 12,
          separators: 13,
          'module-index-format': 14,
          'global-index-format': 15,
          'param-list-format': 16,
          'property-list-format': 17,
          'member-index-format': 18,
          private: 19,
          cache: 20
        },
        dimensionMap: {
          interface: 4,
          exception: 5
        }
      })

      this._usage.defaults
        .set('cd1', process.version)
        .set('cd2', os.type())
        .set('cd3', os.release())
        .set('cd4', 'api')

      this._usage.loadSync()
      this._interface = 'api'
      this._sendOptions = { timeout: 2000 }

      process.on('exit', () => this._usage.saveSync())
    }

    _hit (method, options, exception) {
      const metrics = Object.assign({ invocation: 1 }, options)
      for (const key in metrics) {
        metrics[key] = 1
      }
      const dimensions = { name: method.name, interface: this._interface }
      if (exception) dimensions.exception = exception
      this._sendOptions.send = options.send
      return this._usage.hit(dimensions, metrics, this._sendOptions)
    }

    _stats (method, options) {
      options = options || {}
      if (options['no-usage-stats']) this._usage.disable()
      return method.call(SuperClass.prototype, options)
        .then(output => {
          return this._hit(method, options)
            .then(() => output)
            .catch(() => output)
        })
        .catch(err => {
          return this._hit(method, options, err.toString())
            .then(() => { throw err })
            .catch(() => { throw err })
        })
    }

    _statsSync (method, options) {
      options = options || {}
      if (options['no-usage-stats']) this._usage.disable()
      try {
        const output = method.call(SuperClass.prototype, options)
        this._hit(method, options)
        return output
      } catch (err) {
        this._hit(method, options, err.toString())
        throw err
      }
    }

    render (options) {
      return this._stats(super.render, options)
    }

    renderSync (options) {
      return this._statsSync(super.renderSync, options)
    }

    getTemplateData (options) {
      return this._stats(super.getTemplateData, options)
    }

    getTemplateDataSync (options) {
      return this._statsSync(super.getTemplateDataSync, options)
    }

    getJsdocData (options) {
      return this._stats(super.getJsdocData, options)
    }

    getJsdocDataSync (options) {
      return this._statsSync(super.getJsdocDataSync, options)
    }

    clear () {
      return this._stats(super.clear)
    }

    getNamepaths (options) {
      return this._stats(super.getNamepaths, options)
    }
  }
}
<commit_msg>send and method in parallel<commit_after>'use strict'
const UsageStats = require('app-usage-stats')
const os = require('os')

module.exports = function (SuperClass, version) {
  return class JsdocToMarkdownStats extends SuperClass {
    constructor () {
      super()
      this._usage = new UsageStats('UA-70853320-3', {
        name: 'jsdoc2md',
        version: version,
        sendInterval: 1000 * 60 * 60 * 24, // 24 hours
        metricMap: {
          invocation: 1,
          source: 2,
          configure: 3,
          html: 4,
          template: 5,
          'heading-depth': 6,
          'example-lang': 7,
          plugin: 8,
          helper: 9,
          partial: 10,
          'name-format': 11,
          'no-gfm': 12,
          separators: 13,
          'module-index-format': 14,
          'global-index-format': 15,
          'param-list-format': 16,
          'property-list-format': 17,
          'member-index-format': 18,
          private: 19,
          cache: 20
        },
        dimensionMap: {
          interface: 4,
          exception: 5
        }
      })

      this._usage.defaults
        .set('cd1', process.version)
        .set('cd2', os.type())
        .set('cd3', os.release())
        .set('cd4', 'api')

      this._usage.loadSync()
      this._interface = 'api'
      this._sendOptions = { timeout: 2000 }

      process.on('exit', () => this._usage.saveSync())
    }

    _hit (method, options, exception) {
      const metrics = Object.assign({ invocation: 1 }, options)
      for (const key in metrics) {
        metrics[key] = 1
      }
      const dimensions = { name: method.name, interface: this._interface }
      if (exception) dimensions.exception = exception
      this._sendOptions.send = options.send
      return this._usage.hit(dimensions, metrics, this._sendOptions)
    }

    _stats (method, options) {
      options = options || {}
      if (options['no-usage-stats']) this._usage.disable()
      return Promise
        .all([
          this._hit(method, options)
            .catch(err => ''),
          method.call(SuperClass.prototype, options)
            .catch(err => {
              return this._hit(method, options, err.toString())
                .then(() => { throw err })
                .catch(() => { throw err })
            })
        ])
        .then(results => results[1])
    }

    _statsSync (method, options) {
      options = options || {}
      if (options['no-usage-stats']) this._usage.disable()
      try {
        const output = method.call(SuperClass.prototype, options)
        this._hit(method, options)
        return output
      } catch (err) {
        this._hit(method, options, err.toString())
        throw err
      }
    }

    render (options) {
      return this._stats(super.render, options)
    }

    renderSync (options) {
      return this._statsSync(super.renderSync, options)
    }

    getTemplateData (options) {
      return this._stats(super.getTemplateData, options)
    }

    getTemplateDataSync (options) {
      return this._statsSync(super.getTemplateDataSync, options)
    }

    getJsdocData (options) {
      return this._stats(super.getJsdocData, options)
    }

    getJsdocDataSync (options) {
      return this._statsSync(super.getJsdocDataSync, options)
    }

    clear () {
      return this._stats(super.clear)
    }

    getNamepaths (options) {
      return this._stats(super.getNamepaths, options)
    }
  }
}
<|endoftext|>


<commit_before>module.exports = {
    plugins: [
        'jsdoc'
    ],
    rules: {
        'jsdoc/check-param-names': 1,
        'jsdoc/check-tag-names': 1,
        'jsdoc/check-types': 1,
        'jsdoc/newline-after-description': [
            1,
            'always'
        ],
        'jsdoc/require-hyphen-before-description': 0,
        'jsdoc/require-param': 1,
        'jsdoc/require-param-description': 0,
        'jsdoc/require-param-type': 1,
        'jsdoc/require-returns-description': 0,
        'jsdoc/require-returns-type': 1
    }
};
<commit_msg>Type is not required (using Flow type annotations).<commit_after>module.exports = {
    plugins: [
        'jsdoc'
    ],
    rules: {
        'jsdoc/check-param-names': 1,
        'jsdoc/check-tag-names': 1,
        'jsdoc/check-types': 1,
        'jsdoc/newline-after-description': [
            1,
            'always'
        ],
        'jsdoc/require-hyphen-before-description': 0,
        'jsdoc/require-param': 1,
        'jsdoc/require-param-description': 0,
        'jsdoc/require-param-type': 0,
        'jsdoc/require-returns-description': 0,
        'jsdoc/require-returns-type': 0
    }
};
<|endoftext|>


<commit_before>module.exports = jsFlowTracker

var debug = require('debug')('bittorrent-tracker:websocket-tracker')
var EventEmitter = require('events').EventEmitter
var hat = require('hat')
var inherits = require('inherits')
var jsFlow = require('./jsFlow')
var Peer = require('simple-peer')
//var Peer = require('jsflow-peer') // No changes yet.. :)

function jsFlowTracker (client, announceUrl, opts) {
  console.log('jsFlowTracker constructor is now running')
	var self=this
	EventEmitter.call(self)

  self.client=client
  self._opts = opts
  self._announceUrl = announceUrl
  self._peers = {} // peers (peer id -> peer)
  self._intervalMs = self.client._intervalMs // use client interval initially
  self._interval = null

  console.log(self);

  jsFlow.onRecievedUserId = function(userId) {
    console.log('userId', userId);
    self._peerID = userId;
  };

  // Starts jsFlow and handles the user ID
  jsFlow.run("31bc728296d8da7e14e132k",{sessionAuthURL: 'http://corslabs.com/jsflow',
                  debugMsg: true});

  jsFlow.addHandler('list', self._onData.bind(self)) // These messages are only sent by the TRACKER

  //Handlers for peer-2-peer WebRTC signalling using jsFlow
  jsFlow.addHandler('webrtc_offer', self._onWebRtcOffer.bind(self)) // only sent from other PEERS
  jsFlow.addHandler('webrtc_answer', self._onWebRtcAnswer.bind(self)) // only sent from other PEERS
  jsFlow.addHandler('webrtc_ice', self._onWebRtcIce.bind(self)) // only sent from other PEERS
}

jsFlowTracker.prototype.announce = function(opts){
  var self=this
  opts.info_hash = self.client._infoHash.toString('base64')
  opts.peer_id = self._peerId
  opts.trackerid = 'tracker'

  self._sendAnnounce(opts)
}

jsFlowTracker.prototype.setInterval= function (intervalMs) {
  var self = this
  clearInterval(self._interval)

  self._intervalMs = intervalMs
  if (intervalMs) {
    // HACK
    var update = self.announce.bind(self, self.client._defaultAnnounceOpts())
    self._interval = setInterval(update, self._intervalMs)
  }
}

jsFlowTracker.prototype._onData = function (payload, from) {
  console.log('Got Data from Tracker!!', payload, from);

  var self = this
  if (!(typeof payload === 'object' && payload !== null)) {
    return self.client.emit('warning', new Error('Invalid tracker response'))
  }

  if (payload.info_hash !== self.client._infoHash.toString('base64')) {
    return self.client.emit('warning', new Error('Invalid tracker response'))
  }

  var failure = payload['failure reason']
  if (failure) return self.client.emit('warning', new Error(failure))

  var warning = payload['warning message']
  if (warning) self.client.emit('warning', new Error(warning))

  var interval = payload.interval || payload['min interval']
  if (interval && !self._opts.interval && self._intervalMs !== 0) { //TODO: Fix so tracker can set interval (now defaults to 30 min)
  //if(interval) { // ALWAYS use the interval recommended by tracker
    self.setInterval(interval)
  }

  var trackerId = payload['tracker id']
  if (trackerId) {
    // If absent, do not discard previous trackerId value
    self._trackerId = trackerId
  }

  if (payload.complete) {
    self.client.emit('update', {
    announce: self._announceUrl,
    complete: payload.complete,
    incomplete: payload.incomplete
    })
  }

  // Handle received peers
  if (Array.isArray(payload.peers)) {
    payload.peers.forEach(function (peerInfo) { //For all peers we receive - Open a WebRTC peer connection

      console.log('Will handle connection for peer: ', peerInfo.peerId);

      var peer = self._peers[peerId] = new Peer({
        initiator: true,
        trickle: true,
        config: self.client._rtcConfig,
        wrtc: self.client._wrtc
      })
      peer.id = peerInfo.peerId

      peer.on('signal', function (signalObject) {
        if(signalObject.candidate) { // The signalling is for ICE
          var params = {
            info_hash: self.client._infoHash.toString('base64'),
            peer_id: self._peerID,
            candidate: candidate
          }

          jsFlow.messageUser(peerId, params, 'webrtc_ice');
        }
        else { // The signalling is for an OFFER
          offer = signalObject;
          var params = {
            info_hash: self.client._infoHash.toString('base64'),
            peer_id: self._peerID,
            offer: offer
          }

          jsFlow.messageUser(peerId, params, 'webrtc_offer');
        }
      })
    })
  };
}

jsFlowTracker.prototype._onWebRtcOffer = function (payload, from) {
  if(!self._peers[from]) { //Verify we haven't already received an offer from this user
    var peer = self._peers[from] = new Peer({
      trickle: true,
      config: self.client._rtcConfig,
      wrtc: self.client._wrtc
    })
    peer.id = from

    peer.on('signal', function (signalObject) {
      if(signalObject.candidate) { // The signalling is for ICE
        var params = {
          info_hash: self.client._infoHash.toString('base64'),
          peer_id: self._peerID,
          candidate: candidate
        }

        jsFlow.messageUser(from, params, 'webrtc_ice');
      }
      else { // The signalling is for an ANSWER
        answer = signalObject;
        var params = {
          info_hash: self.client._infoHash.toString('base64'),
          peer_id: self._peerID,
          answer: answer
        }

        jsFlow.messageUser(from, params, 'webrtc_answer');
      }
    })

    peer.signal(payload.offer)

    self.client.emit('peer', peer)
  }
  else {
    console.error('Already have peer connection with user: ' + from);
  }
}

jsFlowTracker.prototype._onWebRtcAnswer = function (payload, from) {
  peer = self._peers[from]
  if(peer) {
    peer.id = from
    peer.signal(payload.answer)
    self.client.emit('peer', peer)
  }
  else {
    console.error('Got answer on peer connection that does not exist, from user: ' + from);
  }
}

jsFlowTracker.prototype._onWebRtcIce = function (payload, from) {
  //TODO: Buffer ICE ?
  console.log('WILL ADD ICE CANDIDATE!!!');
  peer.signal(payload.candidate)
}

jsFlowTracker.prototype._sendAnnounce = function (params) {
  var self = this
  jsFlow.messageUser(params.trackerid, params, 'announce')
}
<commit_msg>Minor fix<commit_after>module.exports = jsFlowTracker

var debug = require('debug')('bittorrent-tracker:websocket-tracker')
var EventEmitter = require('events').EventEmitter
var hat = require('hat')
var inherits = require('inherits')
var jsFlow = require('./jsFlow')
var Peer = require('simple-peer')
//var Peer = require('jsflow-peer') // No changes yet.. :)

function jsFlowTracker (client, announceUrl, opts) {
  console.log('jsFlowTracker constructor is now running')
	var self=this
	EventEmitter.call(self)

  self.client=client
  self._opts = opts
  self._announceUrl = announceUrl
  self._peers = {} // peers (peer id -> peer)
  self._intervalMs = self.client._intervalMs // use client interval initially
  self._interval = null

  console.log(self);

  jsFlow.onRecievedUserId = function(userId) {
    console.log('userId', userId);
    self._peerID = userId;
  };

  // Starts jsFlow and handles the user ID
  jsFlow.run("31bc728296d8da7e14e132k",{sessionAuthURL: 'http://corslabs.com/jsflow',
                  debugMsg: true});

  jsFlow.addHandler('list', self._onData.bind(self)) // These messages are only sent by the TRACKER

  //Handlers for peer-2-peer WebRTC signalling using jsFlow
  jsFlow.addHandler('webrtc_offer', self._onWebRtcOffer.bind(self)) // only sent from other PEERS
  jsFlow.addHandler('webrtc_answer', self._onWebRtcAnswer.bind(self)) // only sent from other PEERS
  jsFlow.addHandler('webrtc_ice', self._onWebRtcIce.bind(self)) // only sent from other PEERS
}

jsFlowTracker.prototype.announce = function(opts){
  var self=this
  opts.info_hash = self.client._infoHash.toString('base64')
  opts.peer_id = self._peerId
  opts.trackerid = 'tracker'

  self._sendAnnounce(opts)
}

jsFlowTracker.prototype.setInterval= function (intervalMs) {
  var self = this
  clearInterval(self._interval)

  self._intervalMs = intervalMs
  if (intervalMs) {
    // HACK
    var update = self.announce.bind(self, self.client._defaultAnnounceOpts())
    self._interval = setInterval(update, self._intervalMs)
  }
}

jsFlowTracker.prototype._onData = function (payload, from) {
  console.log('Got Data from Tracker!!', payload, from);

  var self = this
  if (!(typeof payload === 'object' && payload !== null)) {
    return self.client.emit('warning', new Error('Invalid tracker response'))
  }

  if (payload.info_hash !== self.client._infoHash.toString('base64')) {
    return self.client.emit('warning', new Error('Invalid tracker response'))
  }

  var failure = payload['failure reason']
  if (failure) return self.client.emit('warning', new Error(failure))

  var warning = payload['warning message']
  if (warning) self.client.emit('warning', new Error(warning))

  var interval = payload.interval || payload['min interval']
  if (interval && !self._opts.interval && self._intervalMs !== 0) { //TODO: Fix so tracker can set interval (now defaults to 30 min)
  //if(interval) { // ALWAYS use the interval recommended by tracker
    self.setInterval(interval)
  }

  var trackerId = payload['tracker id']
  if (trackerId) {
    // If absent, do not discard previous trackerId value
    self._trackerId = trackerId
  }

  if (payload.complete) {
    self.client.emit('update', {
    announce: self._announceUrl,
    complete: payload.complete,
    incomplete: payload.incomplete
    })
  }

  // Handle received peers
  if (Array.isArray(payload.peers)) {
    payload.peers.forEach(function (peerInfo) { //For all peers we receive - Open a WebRTC peer connection

      console.log('Will handle connection for peer: ', peerInfo.peerId);

      var peer = self._peers[peerId] = new Peer({
        initiator: true,
        trickle: true,
        config: self.client._rtcConfig,
        wrtc: self.client._wrtc
      })
      peer.id = peerInfo.peerId

      peer.on('signal', function (signalObject) {
        console.log('GOT SIGNAL, expecting offer/ice', signalObject);
        if(signalObject.candidate) { // The signalling is for ICE
          var params = {
            info_hash: self.client._infoHash.toString('base64'),
            peer_id: self._peerID,
            candidate: candidate
          }

          jsFlow.messageUser(peerId, params, 'webrtc_ice');
        }
        else { // The signalling is for an OFFER
          offer = signalObject;
          var params = {
            info_hash: self.client._infoHash.toString('base64'),
            peer_id: self._peerID,
            offer: offer
          }

          jsFlow.messageUser(peerId, params, 'webrtc_offer');
        }
      })
    })
  };
}

jsFlowTracker.prototype._onWebRtcOffer = function (payload, from) {
  if(!self._peers[from]) { //Verify we haven't already received an offer from this user
    var peer = self._peers[from] = new Peer({
      trickle: true,
      config: self.client._rtcConfig,
      wrtc: self.client._wrtc
    })
    peer.id = from

    peer.on('signal', function (signalObject) {
        console.log('GOT SIGNAL, expecting offer/ice', signalObject);
      if(signalObject.candidate) { // The signalling is for ICE
        var params = {
          info_hash: self.client._infoHash.toString('base64'),
          peer_id: self._peerID,
          candidate: candidate
        }

        jsFlow.messageUser(from, params, 'webrtc_ice');
      }
      else { // The signalling is for an ANSWER
        answer = signalObject;
        var params = {
          info_hash: self.client._infoHash.toString('base64'),
          peer_id: self._peerID,
          answer: answer
        }

        jsFlow.messageUser(from, params, 'webrtc_answer');
      }
    })

    peer.signal(payload.offer)

    self.client.emit('peer', peer)
  }
  else {
    console.error('Already have peer connection with user: ' + from);
  }
}

jsFlowTracker.prototype._onWebRtcAnswer = function (payload, from) {
  peer = self._peers[from]
  if(peer) {
    peer.id = from
    peer.signal(payload.answer)
    self.client.emit('peer', peer)
  }
  else {
    console.error('Got answer on peer connection that does not exist, from user: ' + from);
  }
}

jsFlowTracker.prototype._onWebRtcIce = function (payload, from) {
  //TODO: Buffer ICE ?
  console.log('WILL ADD ICE CANDIDATE!!!');
  peer.signal(payload.candidate)
}

jsFlowTracker.prototype._sendAnnounce = function (params) {
  var self = this
  jsFlow.messageUser(params.trackerid, params, 'announce')
}
<|endoftext|>


<commit_before>'use strict'

let logger = require('./modules/errorLogger'),
	emails = require('./modules/emails'),
	generalStore = require('./modules/generalStore'),
	tokenManager = require('./modules/tokenManager'),
	Sequelize = require('sequelize'),
	express = require('express'),
	wrap = require('co-express'),
	expressSession = require('express-session'),
	passport = require('passport'),
	redis = require('redis'),
	RedisStore = require('connect-redis')(expressSession),
	http = require('http'),
	bodyParser = require('body-parser'),
	multipart = require('connect-multiparty'),
	cookieParser = require('cookie-parser'),
	requestLogger = require('morgan'),
	path = require('path'),
	pug = require('pug'),
	fs = require('fs'),
	moment = require('moment'),
	pd = require('pretty-data').pd,
	defaultConfig = require('./defaults/config'),
	defaultClientSettings = require('./defaults/clientSettings'),
	defaultApiSettings = require('./defaults/apiSettings'),
	baseDBClass = require('./base/dbClass'),
	baseClientClass = require('./base/clientClass'),
	baseApiClass = require('./base/apiClass')

class Core {
	constructor(cfg) {
		try {
			this.cfg = cfg || defaultConfig
			this.logger = new logger(this.cfg)
			this.mailClient = new emails(this.cfg)
			this.generalStore = new generalStore(this.cfg)
			this.tokenManager = new tokenManager({generalStore: this.generalStore})
			this.modules = {}

			// ####### ------------ LOAD THE DATABASE MODULE ---------- ####### \\
			let moduleDir = fs.readdirSync(this.cfg.db.modulePath),
				sequelize = new Sequelize(this.cfg.postgres.database, this.cfg.postgres.user, this.cfg.postgres.pass, {
					host: this.cfg.postgres.host,
					port: this.cfg.postgres.port,
					dialect: 'postgres',
					logging: (this.cfg.postgres.logging === true) ?
						(sql) => {
							console.log('================ SQL ==================')
							console.log(pd.sql(sql))
							console.log('================ /SQL ==================')
						} : false
				}),
				CORE = this

			this.modules.db = {
				components: {},
				seedingOrder: this.cfg.db.seedingOrder
			}
			moduleDir.forEach((componentDir, index) => {
				if (componentDir.indexOf('.') === -1) {
					this.modules.db.components[componentDir] = new (require(path.join(this.cfg.db.modulePath, componentDir)))(sequelize, Sequelize, {
						mailClient: this.mailClient,
						cfg: this.cfg,
						logger: this.logger
					})
				}
			})

			// ----- create the database associations and update the modules -------- \\
			for (let componentName in this.modules.db.components) {
				let component = this.modules.db.components[componentName],
					relKey = component.associate(this.modules.db.components)
			}
			this.modules.db.sequelize = sequelize
			this.modules.db.Sequelize = Sequelize
			for (let componentName in this.modules.db.components) {
				let component = this.modules.db.components[componentName]
				component.setDb(this.modules.db)
			}

			this.modules.db.sequelize.sync()

			// ####### ------------ LOAD THE CLIENT SERVER MODULES ---------- ####### \\
			this.modules.clients = {}

			let modulesDirPath = this.cfg.clientModulesPath,
				modulesDirData = fs.readdirSync(modulesDirPath),
				settings = {passport}
			modulesDirData.forEach((moduleDir, index) => {
				if (moduleDir.indexOf('.') === -1) {
					let moduleDirPath = path.join(modulesDirPath, moduleDir),
						moduleDirData = fs.readdirSync(moduleDirPath),
						moduleData = {},
						moduleSettings = {}

					try{
						moduleSettings = require(path.join(moduleDirPath, 'settings'))
					} catch (e) {
						console.log(`Could not load the settings for client module ${moduleDir}. Using defaults.`)
						moduleSettings = defaultClientSettings
					}

					moduleDirData.forEach((componentDir, index) => {
						if (componentDir.indexOf('.') === -1) {
							moduleData[componentDir] = new (require(path.join(moduleDirPath, componentDir)))(settings)
						}
					})

					for (let key in moduleSettings){
						settings[key] = moduleSettings[key]
					}

					this.modules.clients[moduleDir] = {moduleData, settings}
				}
			})

			// ####### ------------ LOAD THE API SERVER MODULES ---------- ####### \\
			this.modules.apis = {}

			modulesDirPath = this.cfg.apiModulesPath
			modulesDirData = fs.readdirSync(modulesDirPath)
			settings = {}
			modulesDirData.forEach((moduleDir, index) => {
				if (moduleDir.indexOf('.') === -1) {
					let moduleDirPath = path.join(modulesDirPath, moduleDir),
						moduleDirData = fs.readdirSync(moduleDirPath),
						moduleData = {},
						moduleSettings = {}

					try{
						moduleSettings = require(path.join(moduleDirPath, 'settings'))
					} catch (e) {
						console.log(`Could not load the settings for API module ${moduleDir}. Using defaults.`)
						moduleSettings = defaultApiSettings
					}

					moduleDirData.forEach((componentDir, index) => {
						if (componentDir.indexOf('.') === -1) {
							moduleData[componentDir] = new (require(path.join(moduleDirPath, componentDir)))(settings)
						}
					})

					for (let key in moduleSettings){
						settings[key] = moduleSettings[key]
					}

					this.modules.apis[moduleDir] = {moduleData, settings}
				}
			})
		} catch (e) {
			console.log(e)
		}
	}

	listen() {
		try {
			let CORE = this

			// ------------ LOAD THE CLIENTS' ROUTES ---------- \\
			let redisClient = redis.createClient(this.cfg.redis.port, this.cfg.redis.host, {}),
				sessionStore = new RedisStore({
					host: this.cfg.redis.host,
					port: this.cfg.redis.port,
					client: redisClient
				})

			for (let moduleName in this.modules.clients) {
				// build the layout.html file
				let publicSourcesPath = path.join(this.cfg.clientModulesPublicSourcesPath, moduleName),
					layoutFile = (pug.compileFile(path.join(publicSourcesPath, 'layout_' + this.cfg.name + '.pug'), {}))(),
					layoutFilePath = path.join(this.cfg[moduleName].publicPath, 'layout.html'),
					clientModule = this.modules.clients[moduleName]

				fs.openSync(layoutFilePath, 'w')
				fs.writeFileSync(layoutFilePath, layoutFile)

				clientModule.app = express()
				clientModule.router = express.Router()
				clientModule.paths = []

				//set up request logging and request body parsing
				clientModule.app.use(requestLogger(`[${moduleName} client] :method request to :url; result: :status; completed in: :response-time; :date`))
				clientModule.app.use(bodyParser.json())  // for 'application/json' request bodies
				clientModule.app.use(bodyParser.urlencoded({extended: false})) // 'x-www-form-urlencoded' request bodies
				clientModule.app.use(multipart({uploadDir: this.cfg.globalUploadPath})) // for multipart bodies - file uploads etc.
				clientModule.app.use(cookieParser())

				//set up the passport session
				clientModule.app.use(expressSession({
					secret: this.cfg[moduleName].session.secret,
					key: this.cfg[moduleName].session.key,
					resave: true,
					saveUninitialized: true,
					cookie: {
						httpOnly: true
					},
					store: sessionStore,
					passport: {}
				}))
				clientModule.app.use(clientModule.settings.passport.initialize())
				clientModule.app.use(clientModule.settings.passport.session())

				clientModule.app.use(express.static(this.cfg[moduleName].publicPath)) //serve static files

				//load all route paths
				for (let i in clientModule.moduleData) {
					let component = clientModule.moduleData[i],
						routes = component.getRoutes()
					routes.forEach((routeData, index) => {
						if (routeData.path instanceof Array) {
							routeData.path.forEach((path, pIndex) => {
								clientModule.paths.push(path)
							})
						} else {
							clientModule.paths.push(routeData.path)
						}
					})
				}

				//before every route - set up post params logging, redirects and locals
				clientModule.app.use(clientModule.paths, wrap(function* (req, res, next) {
					let originalUrl = req.originalUrl.split('?')[0]
					console.log(`[${moduleName} client]`, originalUrl, 'POST Params: ', JSON.stringify(req.body || {}))

					if (clientModule.settings.unathorizedRedirectRoute && !req.isAuthenticated() && (clientModule.settings.anonymousAccessRoutes.indexOf(originalUrl) === -1)) {
						res.redirect(302, clientModule.settings.unathorizedRedirectRoute)
						return;
					}

					req.locals = {
						moduleName,
						cfg: CORE.cfg,
						settings: clientModule.settings,
						logger: CORE.logger,
						mailClient: CORE.mailClient,
						generalStore: CORE.generalStore,
						tokenManager: CORE.tokenManager,
						db: CORE.modules.db,
						passport: clientModule.settings.passport,
						error: null,
						errorStatus: 500,
						originalUrl
					}
					next()
				}))

				//mount all routes
				for (let i in clientModule.moduleData) {
					let component = clientModule.moduleData[i],
						routes = component.getRoutes()
					routes.forEach((routeData, index) => {
						clientModule.router[routeData.method](routeData.path, wrap(component[routeData.func]()))
					})
				}
				clientModule.app.use('/', clientModule.router)

				//after every route - return handled errors and set up redirects
				clientModule.app.use('*', function (req, res) {
					if (req.locals.error == null) {
						if (req.isAuthenticated()) {
							res.redirect(302, clientModule.settings.notFoundRedirectRoutes.authenticated)
							return;
						}
						res.redirect(302, clientModule.settings.notFoundRedirectRoutes.default)
						return;
					}
					CORE.logger.error(req.locals.error)
					res.status(req.locals.errorStatus).json({error: req.locals.error.customMessage || 'An internal server error has occurred. Please try again.'})
				})

				clientModule.server = http.createServer(clientModule.app)
				clientModule.server.listen(this.cfg[moduleName].serverPort, () => {
					console.log(`[${moduleName} client] Server started.`)
					console.log(`[${moduleName} client] Port:`, this.cfg[moduleName].serverPort)
					console.log(`[${moduleName} client] Configuration profile:`, this.cfg.name)
				})
			}

			// ------------ LOAD THE APIS' ROUTES ---------- \\
			for (let moduleName in this.modules.apis) {
				// build the initial index.html file
				let apiModule = this.modules.apis[moduleName]

				apiModule.app = express()
				apiModule.router = express.Router()
				apiModule.paths = []

				//set up request logging and request body parsing
				apiModule.app.use(requestLogger(`[${moduleName} API] :method request to :url; result: :status; completed in: :response-time; :date`))
				apiModule.app.use(bodyParser.json())  // for 'application/json' request bodies

				//load all route paths
				for (let i in apiModule.moduleData) {
					let component = apiModule.moduleData[i],
						routes = component.getRoutes()
					routes.forEach((routeData, index) => {
						if (routeData.path instanceof Array) {
							routeData.path.forEach((path, pIndex) => {
								apiModule.paths.push(path)
							})
						} else {
							apiModule.paths.push(routeData.path)
						}
					})
				}

				//before every route - set up post params logging, redirects and locals
				apiModule.app.use(apiModule.paths, wrap(function* (req, res, next) {
					let originalUrl = req.originalUrl.split('?')[0]
					console.log(`[${moduleName} API]`, originalUrl, 'POST Params: ', JSON.stringify(req.body || {}))

					req.locals = {
						moduleName,
						cfg: CORE.cfg,
						settings: apiModule.settings,
						logger: CORE.logger,
						mailClient: CORE.mailClient,
						generalStore: CORE.generalStore,
						tokenManager: CORE.tokenManager,
						db: CORE.modules.db,
						error: null,
						errorStatus: 500,
						originalUrl
					}
					next()
				}))

				//mount all routes
				for (let i in apiModule.moduleData) {
					let component = apiModule.moduleData[i],
						routes = component.getRoutes()
					routes.forEach((routeData, index) => {
						if(apiModule.settings.anonymousAccessRoutes.indexOf(routeData.path) === -1) {
							apiModule.router[routeData.method](routeData.path, this.tokenManager.validate({secret: this.cfg[moduleName].jwt.secret, moduleName}), wrap(component[routeData.func]()))
							return;
						}
						apiModule.router[routeData.method](routeData.path, wrap(component[routeData.func]()))
					})
				}
				apiModule.app.use('/', apiModule.router)

				//after every route - return handled errors and set up redirects
				apiModule.app.use('*', function (err, req, res, next) {
					if (req.locals.error == null) {
						res.status(404).json({error: 'Not found.'})
						return;
					}
					CORE.logger.error(req.locals.error)
					res.status(req.locals.errorStatus).json({error: req.locals.error.customMessage || 'An internal server error has occurred. Please try again.'})
				})

				apiModule.server = http.createServer(apiModule.app)
				apiModule.server.listen(this.cfg[moduleName].serverPort, () => {
					console.log(`[${moduleName} API] Server started.`)
					console.log(`[${moduleName} API] Port:`, this.cfg[moduleName].serverPort)
					console.log(`[${moduleName} API] Configuration profile:`, this.cfg.name)
				})
			}
		} catch (e) {
			this.logger.error(e)
		}
	}
}

module.exports = {
	Core,
	baseDBClass,
	baseClientClass,
	baseApiClass
}
<commit_msg>added the csvPromise module to exports<commit_after>'use strict'

let csvPromise = require('./modules/csvPromise'),
	logger = require('./modules/errorLogger'),
	emails = require('./modules/emails'),
	generalStore = require('./modules/generalStore'),
	tokenManager = require('./modules/tokenManager'),
	Sequelize = require('sequelize'),
	express = require('express'),
	wrap = require('co-express'),
	expressSession = require('express-session'),
	passport = require('passport'),
	redis = require('redis'),
	RedisStore = require('connect-redis')(expressSession),
	http = require('http'),
	bodyParser = require('body-parser'),
	multipart = require('connect-multiparty'),
	cookieParser = require('cookie-parser'),
	requestLogger = require('morgan'),
	path = require('path'),
	pug = require('pug'),
	fs = require('fs'),
	moment = require('moment'),
	pd = require('pretty-data').pd,
	defaultConfig = require('./defaults/config'),
	defaultClientSettings = require('./defaults/clientSettings'),
	defaultApiSettings = require('./defaults/apiSettings'),
	baseDBClass = require('./base/dbClass'),
	baseClientClass = require('./base/clientClass'),
	baseApiClass = require('./base/apiClass')

class Core {
	constructor(cfg) {
		try {
			this.cfg = cfg || defaultConfig
			this.logger = new logger(this.cfg)
			this.mailClient = new emails(this.cfg)
			this.generalStore = new generalStore(this.cfg)
			this.tokenManager = new tokenManager({generalStore: this.generalStore})
			this.modules = {}

			// ####### ------------ LOAD THE DATABASE MODULE ---------- ####### \\
			let moduleDir = fs.readdirSync(this.cfg.db.modulePath),
				sequelize = new Sequelize(this.cfg.postgres.database, this.cfg.postgres.user, this.cfg.postgres.pass, {
					host: this.cfg.postgres.host,
					port: this.cfg.postgres.port,
					dialect: 'postgres',
					logging: (this.cfg.postgres.logging === true) ?
						(sql) => {
							console.log('================ SQL ==================')
							console.log(pd.sql(sql))
							console.log('================ /SQL ==================')
						} : false
				}),
				CORE = this

			this.modules.db = {
				components: {},
				seedingOrder: this.cfg.db.seedingOrder
			}
			moduleDir.forEach((componentDir, index) => {
				if (componentDir.indexOf('.') === -1) {
					this.modules.db.components[componentDir] = new (require(path.join(this.cfg.db.modulePath, componentDir)))(sequelize, Sequelize, {
						mailClient: this.mailClient,
						cfg: this.cfg,
						logger: this.logger
					})
				}
			})

			// ----- create the database associations and update the modules -------- \\
			for (let componentName in this.modules.db.components) {
				let component = this.modules.db.components[componentName],
					relKey = component.associate(this.modules.db.components)
			}
			this.modules.db.sequelize = sequelize
			this.modules.db.Sequelize = Sequelize
			for (let componentName in this.modules.db.components) {
				let component = this.modules.db.components[componentName]
				component.setDb(this.modules.db)
			}

			this.modules.db.sequelize.sync()

			// ####### ------------ LOAD THE CLIENT SERVER MODULES ---------- ####### \\
			this.modules.clients = {}

			let modulesDirPath = this.cfg.clientModulesPath,
				modulesDirData = fs.readdirSync(modulesDirPath),
				settings = {passport}
			modulesDirData.forEach((moduleDir, index) => {
				if (moduleDir.indexOf('.') === -1) {
					let moduleDirPath = path.join(modulesDirPath, moduleDir),
						moduleDirData = fs.readdirSync(moduleDirPath),
						moduleData = {},
						moduleSettings = {}

					try{
						moduleSettings = require(path.join(moduleDirPath, 'settings'))
					} catch (e) {
						console.log(`Could not load the settings for client module ${moduleDir}. Using defaults.`)
						moduleSettings = defaultClientSettings
					}

					moduleDirData.forEach((componentDir, index) => {
						if (componentDir.indexOf('.') === -1) {
							moduleData[componentDir] = new (require(path.join(moduleDirPath, componentDir)))(settings)
						}
					})

					for (let key in moduleSettings){
						settings[key] = moduleSettings[key]
					}

					this.modules.clients[moduleDir] = {moduleData, settings}
				}
			})

			// ####### ------------ LOAD THE API SERVER MODULES ---------- ####### \\
			this.modules.apis = {}

			modulesDirPath = this.cfg.apiModulesPath
			modulesDirData = fs.readdirSync(modulesDirPath)
			settings = {}
			modulesDirData.forEach((moduleDir, index) => {
				if (moduleDir.indexOf('.') === -1) {
					let moduleDirPath = path.join(modulesDirPath, moduleDir),
						moduleDirData = fs.readdirSync(moduleDirPath),
						moduleData = {},
						moduleSettings = {}

					try{
						moduleSettings = require(path.join(moduleDirPath, 'settings'))
					} catch (e) {
						console.log(`Could not load the settings for API module ${moduleDir}. Using defaults.`)
						moduleSettings = defaultApiSettings
					}

					moduleDirData.forEach((componentDir, index) => {
						if (componentDir.indexOf('.') === -1) {
							moduleData[componentDir] = new (require(path.join(moduleDirPath, componentDir)))(settings)
						}
					})

					for (let key in moduleSettings){
						settings[key] = moduleSettings[key]
					}

					this.modules.apis[moduleDir] = {moduleData, settings}
				}
			})
		} catch (e) {
			console.log(e)
		}
	}

	listen() {
		try {
			let CORE = this

			// ------------ LOAD THE CLIENTS' ROUTES ---------- \\
			let redisClient = redis.createClient(this.cfg.redis.port, this.cfg.redis.host, {}),
				sessionStore = new RedisStore({
					host: this.cfg.redis.host,
					port: this.cfg.redis.port,
					client: redisClient
				})

			for (let moduleName in this.modules.clients) {
				// build the layout.html file
				let publicSourcesPath = path.join(this.cfg.clientModulesPublicSourcesPath, moduleName),
					layoutFile = (pug.compileFile(path.join(publicSourcesPath, 'layout_' + this.cfg.name + '.pug'), {}))(),
					layoutFilePath = path.join(this.cfg[moduleName].publicPath, 'layout.html'),
					clientModule = this.modules.clients[moduleName]

				fs.openSync(layoutFilePath, 'w')
				fs.writeFileSync(layoutFilePath, layoutFile)

				clientModule.app = express()
				clientModule.router = express.Router()
				clientModule.paths = []

				//set up request logging and request body parsing
				clientModule.app.use(requestLogger(`[${moduleName} client] :method request to :url; result: :status; completed in: :response-time; :date`))
				clientModule.app.use(bodyParser.json())  // for 'application/json' request bodies
				clientModule.app.use(bodyParser.urlencoded({extended: false})) // 'x-www-form-urlencoded' request bodies
				clientModule.app.use(multipart({uploadDir: this.cfg.globalUploadPath})) // for multipart bodies - file uploads etc.
				clientModule.app.use(cookieParser())

				//set up the passport session
				clientModule.app.use(expressSession({
					secret: this.cfg[moduleName].session.secret,
					key: this.cfg[moduleName].session.key,
					resave: true,
					saveUninitialized: true,
					cookie: {
						httpOnly: true
					},
					store: sessionStore,
					passport: {}
				}))
				clientModule.app.use(clientModule.settings.passport.initialize())
				clientModule.app.use(clientModule.settings.passport.session())

				clientModule.app.use(express.static(this.cfg[moduleName].publicPath)) //serve static files

				//load all route paths
				for (let i in clientModule.moduleData) {
					let component = clientModule.moduleData[i],
						routes = component.getRoutes()
					routes.forEach((routeData, index) => {
						if (routeData.path instanceof Array) {
							routeData.path.forEach((path, pIndex) => {
								clientModule.paths.push(path)
							})
						} else {
							clientModule.paths.push(routeData.path)
						}
					})
				}

				//before every route - set up post params logging, redirects and locals
				clientModule.app.use(clientModule.paths, wrap(function* (req, res, next) {
					let originalUrl = req.originalUrl.split('?')[0]
					console.log(`[${moduleName} client]`, originalUrl, 'POST Params: ', JSON.stringify(req.body || {}))

					if (clientModule.settings.unathorizedRedirectRoute && !req.isAuthenticated() && (clientModule.settings.anonymousAccessRoutes.indexOf(originalUrl) === -1)) {
						res.redirect(302, clientModule.settings.unathorizedRedirectRoute)
						return;
					}

					req.locals = {
						moduleName,
						cfg: CORE.cfg,
						settings: clientModule.settings,
						logger: CORE.logger,
						mailClient: CORE.mailClient,
						generalStore: CORE.generalStore,
						tokenManager: CORE.tokenManager,
						db: CORE.modules.db,
						passport: clientModule.settings.passport,
						error: null,
						errorStatus: 500,
						originalUrl
					}
					next()
				}))

				//mount all routes
				for (let i in clientModule.moduleData) {
					let component = clientModule.moduleData[i],
						routes = component.getRoutes()
					routes.forEach((routeData, index) => {
						clientModule.router[routeData.method](routeData.path, wrap(component[routeData.func]()))
					})
				}
				clientModule.app.use('/', clientModule.router)

				//after every route - return handled errors and set up redirects
				clientModule.app.use('*', function (req, res) {
					if (req.locals.error == null) {
						if (req.isAuthenticated()) {
							res.redirect(302, clientModule.settings.notFoundRedirectRoutes.authenticated)
							return;
						}
						res.redirect(302, clientModule.settings.notFoundRedirectRoutes.default)
						return;
					}
					CORE.logger.error(req.locals.error)
					res.status(req.locals.errorStatus).json({error: req.locals.error.customMessage || 'An internal server error has occurred. Please try again.'})
				})

				clientModule.server = http.createServer(clientModule.app)
				clientModule.server.listen(this.cfg[moduleName].serverPort, () => {
					console.log(`[${moduleName} client] Server started.`)
					console.log(`[${moduleName} client] Port:`, this.cfg[moduleName].serverPort)
					console.log(`[${moduleName} client] Configuration profile:`, this.cfg.name)
				})
			}

			// ------------ LOAD THE APIS' ROUTES ---------- \\
			for (let moduleName in this.modules.apis) {
				// build the initial index.html file
				let apiModule = this.modules.apis[moduleName]

				apiModule.app = express()
				apiModule.router = express.Router()
				apiModule.paths = []

				//set up request logging and request body parsing
				apiModule.app.use(requestLogger(`[${moduleName} API] :method request to :url; result: :status; completed in: :response-time; :date`))
				apiModule.app.use(bodyParser.json())  // for 'application/json' request bodies

				//load all route paths
				for (let i in apiModule.moduleData) {
					let component = apiModule.moduleData[i],
						routes = component.getRoutes()
					routes.forEach((routeData, index) => {
						if (routeData.path instanceof Array) {
							routeData.path.forEach((path, pIndex) => {
								apiModule.paths.push(path)
							})
						} else {
							apiModule.paths.push(routeData.path)
						}
					})
				}

				//before every route - set up post params logging, redirects and locals
				apiModule.app.use(apiModule.paths, wrap(function* (req, res, next) {
					let originalUrl = req.originalUrl.split('?')[0]
					console.log(`[${moduleName} API]`, originalUrl, 'POST Params: ', JSON.stringify(req.body || {}))

					req.locals = {
						moduleName,
						cfg: CORE.cfg,
						settings: apiModule.settings,
						logger: CORE.logger,
						mailClient: CORE.mailClient,
						generalStore: CORE.generalStore,
						tokenManager: CORE.tokenManager,
						db: CORE.modules.db,
						error: null,
						errorStatus: 500,
						originalUrl
					}
					next()
				}))

				//mount all routes
				for (let i in apiModule.moduleData) {
					let component = apiModule.moduleData[i],
						routes = component.getRoutes()
					routes.forEach((routeData, index) => {
						if(apiModule.settings.anonymousAccessRoutes.indexOf(routeData.path) === -1) {
							apiModule.router[routeData.method](routeData.path, this.tokenManager.validate({secret: this.cfg[moduleName].jwt.secret, moduleName}), wrap(component[routeData.func]()))
							return;
						}
						apiModule.router[routeData.method](routeData.path, wrap(component[routeData.func]()))
					})
				}
				apiModule.app.use('/', apiModule.router)

				//after every route - return handled errors and set up redirects
				apiModule.app.use('*', function (err, req, res, next) {
					if (req.locals.error == null) {
						res.status(404).json({error: 'Not found.'})
						return;
					}
					CORE.logger.error(req.locals.error)
					res.status(req.locals.errorStatus).json({error: req.locals.error.customMessage || 'An internal server error has occurred. Please try again.'})
				})

				apiModule.server = http.createServer(apiModule.app)
				apiModule.server.listen(this.cfg[moduleName].serverPort, () => {
					console.log(`[${moduleName} API] Server started.`)
					console.log(`[${moduleName} API] Port:`, this.cfg[moduleName].serverPort)
					console.log(`[${moduleName} API] Configuration profile:`, this.cfg.name)
				})
			}
		} catch (e) {
			this.logger.error(e)
		}
	}
}

module.exports = {
	Core,
	baseDBClass,
	baseClientClass,
	baseApiClass,
	csvPromise: new csvPromise()
}
<|endoftext|>