<commit_before>var fs = require('fs');
var util = require('util');
var bower = require('bower');
var chalk = require('bower/lib/node_modules/chalk');
var Q = require('q');
var mout = require('bower/lib/node_modules/mout');
var common = require('./common');
var Logger = require('./logger');

var packages = JSON.parse(fs.readFileSync(process.argv[2], 'utf-8'));
var dependencies = packages.dependencies;
var resolutions = packages.resolutions;
var options = packages.options;
var parallelize = process.argv[3] === 'true';
var logLevel = parseInt(process.argv[4]);

var log = new Logger(logLevel, 'Bower');

if (parallelize) {
  common.handleExit();
  common.install(installParallel);
} else {
  common.handleExit(validateInstalledDependencies);
  common.installSequentially(dependencies, bowerInstallDependency);
}

function bowerInstallDependency(item, cb) {
  var cacheName = item.name;
  if (item.hasOwnProperty('cacheName')) {
    cacheName = item.cacheName;
  }
  Q.fcall(function() { return [item.name, item.version, cacheName]; })
  .then(checkCache)
  .then(install)
  .catch(function(error) {
    if (error) {
      log.e('Install failed: ' + cacheName + ': ' + error.stack);
    }
    common.setExitCode(1);
  })
  .done(function() {
    if (!common.hasError() && !fs.existsSync('bower_components/' + cacheName)) {
      log.e('Install failed: module does not exist: ' + cacheName);
      common.setExitCode(1);
    }
    if (cb) {
      cb();
    }
  });
}

function checkCache(data) {
  var name, version, cacheName;
  if (data) {
    name = data.shift();
    version = data.shift();
    cacheName = data.shift();
  }
  var deferred = Q.defer();
  bower.commands.cache.list([cacheName], {}, {})
  .on('error', function(err) {
    log.e('Checking cache failed: ' + err);
    deferred.reject();
  })
  .on('end', function (r) {
    var offline = false;
    for (var i = 0; i < r.length; i++) {
      if (r[i].pkgMeta.version == version) {
        offline = true;
        break;
      }
    }
    deferred.resolve([name, version, cacheName, offline]);
  });
  return deferred.promise;
}

function installParallel(dummy, cb) {
  Q.fcall(function() { return undefined; })
  .then(install)
  .catch(function(error) {
    if (error) {
      log.e('Install failed: ' + error.stack);
    }
    common.setExitCode(1);
  })
  .done(function() {
    if (cb) {
      cb();
    }
  });
}

function install(data) {
  var name, version, cacheName, offline;
  var isSerialInstall = data !== undefined;
  if (isSerialInstall) {
    name = data.shift();
    version = data.shift();
    cacheName = data.shift();
    offline = data.shift();
  }
  var deferred = Q.defer();

  if (isSerialInstall) {
    var installedVersion = getInstalledVersion(name);
    if (installedVersion !== '') {
      // already installed
      if (version !== installedVersion) {
        deferred.reject(new Error(util.format('Update required for %s: please remove bower_components/%s and execute again.', name, name)));
      } else {
        deferred.resolve();
      }
      return deferred.promise;
    }
    saveCurrentDependencyToJson(cacheName, version);
  } else {
    saveBowerJson();
  }

  var cached = false;
  var validate = false;
  var validCacheName = name;
  var installOptions = {};
  Object.keys(options).forEach(function(k) {
    installOptions[mout.string.camelCase(k)] = options[k];
  });
  // If 1st arg is specified, they are marked as unresolvable, and resolutions have no effect.
  bower.commands.install([], installOptions, { 'offline': offline })
  .on('log', function (l) {
    if (l.id === 'cached') {
      cached = true;
    } else if (l.id === 'validate') {
      log.d('Validating: ' + l.data.resolver.name);
      validCacheName = l.data.pkgMeta.name;
      validate = true;
    } else if (l.id === 'resolve') {
      log.i(util.format("Resolving: %s", l.data.resolver.name));
    } else if (l.id === 'download') {
      log.i(util.format("Downloading: %s", l.data.resolver.name));
    } else if (l.id === 'progress') {
      log.i(util.format("Downloading: %s#%s: %s", name, version, l.message));
    } else if (l.id === 'extract') {
      log.i(util.format("Extracting: %s", l.data.resolver.name));
    } else if (l.id === 'install') {
      log.d(util.format("Installing: %s", l.message));
    }
  })
  .on('error', function (err) {
    if (err) {
      if (err.code === 'ECONFLICT') {
        log.e('Install failed: Unable to find a suitable version for ' + err.name + (data ? ' while installing ' + name + '#' + version : '') + '.');
        log.w('To resolve this conflict, please define resolution to your build.gradle.');
        log.w('Example:');
        log.w('    bower {');
        log.w('        dependencies {');
        log.w("            resolve name: '" + err.name + "', version: '" + err.picks[0].pkgMeta.version + "'");
        log.w('        }');
        log.w('    }');

        log.w('Candidate versions:');
        for (var i = 1; i <= err.picks.length; i++) {
          var pick = err.picks[i - 1];
          var dependants = pick.dependants.map(function(dependant) {
            var result = dependant.pkgMeta.name + '#' + dependant.pkgMeta.version;
            if (result === 'webResource#undefined') {
              result = 'this project'
            }
            return result;
          });
          log.w('    ' + chalk.magenta(i + ') ') + chalk.cyan(pick.endpoint.name + '#' + pick.endpoint.target) + ' which resolved to ' + chalk.green(pick.pkgMeta.version) + ' and is required by ' + chalk.green(dependants.join(', ')));
        }
        if (isSerialInstall) {
          log.w('Some candidates might not be shown above because they are not installed yet.');
          log.w('This is a limitation of this plugin.');
        }
      } else {
        log.e('Install failed: ' + err.code + ': ' + err.stack);
      }
    }
    deferred.reject();
  })
  .on('end', function (installed) {
    if (isSerialInstall) {
      log.i('Installed: ' + name + '#' + version + (offline ? ' (offline)' : ''));
      var validatedDueToDependencies = false;
      if (installed[cacheName] && installed[cacheName].dependencies) {
        validatedDueToDependencies = installed[cacheName].dependencies.hasOwnProperty(validCacheName);
      }
      if (cached && validate && !validatedDueToDependencies) {// offline === false) {
        // Installed with cache, but validation occurred
        log.w(util.format('  Note: cache key does not match to the package name.'));
        log.w(util.format('  It means, the package "%s" is cached ', name));
        log.w(util.format('  but still needed a network connection to validate the package '));
        log.w(util.format('  because the cache could not be found by the name "%s".', name));
        log.w(util.format('  To execute installation without any network connections, add cacheName: "%s"', validCacheName));
        log.w(util.format('  to "install" definition in your build.gradle. Example:'));
        log.w(util.format('      bower {'));
        log.w(util.format('          dependencies {'));
        log.w(util.format('              install name: "%s", version: "%s", cacheName: "%s"', name, version, validCacheName));
        log.w(util.format('          }'));
        log.w(util.format('      }'));
      } else if (installed[name] !== undefined && cacheName != installed[name].pkgMeta.name) {
        // Installed without cache but the name doesn't match to the cache key.
        validCacheName = installed[name].pkgMeta.name;
        log.w(util.format('  Note: cache key does not match to the package name.'));
        log.w(util.format('  It means, the package "%s" was cached ', name));
        log.w(util.format('  but you cannot use this cache in the next installation '));
        log.w(util.format('  because the cache will not be found by the name "%s".', name));
        log.w(util.format('  To use this cache in the next installation, add cacheName: "%s"', validCacheName));
        log.w(util.format('  to "install" definition in your build.gradle. Example:'));
        log.w(util.format('      bower {'));
        log.w(util.format('          dependencies {'));
        log.w(util.format('              install name: "%s", version: "%s", cacheName: "%s"', name, version, validCacheName));
        log.w(util.format('          }'));
        log.w(util.format('      }'));
      }
    } else {
      Object.keys(installed).forEach(function(k) {
        var i = installed[k];
        log.i('Installed: ' + i.pkgMeta.name + '#' + i.pkgMeta.version);
      });
    }
    deferred.resolve();
  });
  return deferred.promise;
}

function validateInstalledDependencies() {
  dependencies.forEach(function(e) {
    var cacheName = e.name;
    if (e.hasOwnProperty('cacheName')) {
      cacheName = e.cacheName;
    }
    if (!fs.existsSync('bower_components/' + cacheName)) {
      common.setExitCode(1);
      log.w('Not installed: ' + cacheName);
    }
  });
  if (common.hasError()) {
    log.e('Some dependencies are not installed.');
  }
}

function getInstalledVersion(name) {
  // Some bower.json files don't have "version" attribute.
  // Try .bower.json first, then check bower.json.
  var bowerJson = 'bower_components/' + name + '/.bower.json';
  if (fs.existsSync(bowerJson)) {
    var pkg = JSON.parse(fs.readFileSync(bowerJson, 'utf8'));
    if (pkg.version) {
      return pkg.version;
    }
  }
  bowerJson = 'bower_components/' + name + '/bower.json';
  if (fs.existsSync(bowerJson)) {
    var pkg = JSON.parse(fs.readFileSync(bowerJson, 'utf8'));
    if (pkg.version) {
      return pkg.version;
    }
  }
  return '';
}

function saveCurrentDependencyToJson(name, version) {
  var json = {
    name: "webResource",
    dependencies: {},
    resolutions: {}
  };
  json.dependencies[name] = version;
  json.resolutions = resolutions;
  var jsonStr = JSON.stringify(json, null, '  ');
  fs.writeFileSync('bower.json', jsonStr);
}

function saveBowerJson() {
  var json = {
    name: "webResource",
    dependencies: {},
    resolutions: resolutions
  };
  dependencies.forEach(function(dependency) {
    json.dependencies[dependency.name] = dependency.version;
  });
  var jsonStr = JSON.stringify(json, null, '  ');
  fs.writeFileSync('bower.json', jsonStr);
}
<commit_msg>Fix that cacheName warning log is incorrect<commit_after>var fs = require('fs');
var util = require('util');
var bower = require('bower');
var chalk = require('bower/lib/node_modules/chalk');
var Q = require('q');
var mout = require('bower/lib/node_modules/mout');
var common = require('./common');
var Logger = require('./logger');

var packages = JSON.parse(fs.readFileSync(process.argv[2], 'utf-8'));
var dependencies = packages.dependencies;
var resolutions = packages.resolutions;
var options = packages.options;
var parallelize = process.argv[3] === 'true';
var logLevel = parseInt(process.argv[4]);

var log = new Logger(logLevel, 'Bower');

if (parallelize) {
  common.handleExit();
  common.install(installParallel);
} else {
  common.handleExit(validateInstalledDependencies);
  common.installSequentially(dependencies, bowerInstallDependency);
}

function bowerInstallDependency(item, cb) {
  var cacheName = item.name;
  if (item.hasOwnProperty('cacheName')) {
    cacheName = item.cacheName;
  }
  Q.fcall(function() { return [item.name, item.version, cacheName]; })
  .then(checkCache)
  .then(install)
  .catch(function(error) {
    if (error) {
      log.e('Install failed: ' + cacheName + ': ' + error.stack);
    }
    common.setExitCode(1);
  })
  .done(function() {
    if (!common.hasError() && !fs.existsSync('bower_components/' + cacheName)) {
      log.e('Install failed: module does not exist: ' + cacheName);
      common.setExitCode(1);
    }
    if (cb) {
      cb();
    }
  });
}

function checkCache(data) {
  var name, version, cacheName;
  if (data) {
    name = data.shift();
    version = data.shift();
    cacheName = data.shift();
  }
  var deferred = Q.defer();
  bower.commands.cache.list([cacheName], {}, {})
  .on('error', function(err) {
    log.e('Checking cache failed: ' + err);
    deferred.reject();
  })
  .on('end', function (r) {
    var offline = false;
    for (var i = 0; i < r.length; i++) {
      if (r[i].pkgMeta.version == version) {
        offline = true;
        break;
      }
    }
    deferred.resolve([name, version, cacheName, offline]);
  });
  return deferred.promise;
}

function installParallel(dummy, cb) {
  Q.fcall(function() { return undefined; })
  .then(install)
  .catch(function(error) {
    if (error) {
      log.e('Install failed: ' + error.stack);
    }
    common.setExitCode(1);
  })
  .done(function() {
    if (cb) {
      cb();
    }
  });
}

function install(data) {
  var name, version, cacheName, offline;
  var isSerialInstall = data !== undefined;
  if (isSerialInstall) {
    name = data.shift();
    version = data.shift();
    cacheName = data.shift();
    offline = data.shift();
  }
  var deferred = Q.defer();

  if (isSerialInstall) {
    var installedVersion = getInstalledVersion(name);
    if (installedVersion !== '') {
      // already installed
      if (version !== installedVersion) {
        deferred.reject(new Error(util.format('Update required for %s: please remove bower_components/%s and execute again.', name, name)));
      } else {
        deferred.resolve();
      }
      return deferred.promise;
    }
    saveCurrentDependencyToJson(cacheName, version);
  } else {
    saveBowerJson();
  }

  var cached = false;
  var validate = false;
  var validCacheName = name;
  var installOptions = {};
  Object.keys(options).forEach(function(k) {
    installOptions[mout.string.camelCase(k)] = options[k];
  });
  // If 1st arg is specified, they are marked as unresolvable, and resolutions have no effect.
  bower.commands.install([], installOptions, { 'offline': offline })
  .on('log', function (l) {
    if (l.id === 'cached') {
      cached = true;
    } else if (l.id === 'validate') {
      log.d('Validating: ' + l.data.resolver.name);
      validCacheName = l.data.pkgMeta.name;
      validate = true;
    } else if (l.id === 'resolve') {
      log.i(util.format("Resolving: %s", l.data.resolver.name));
    } else if (l.id === 'download') {
      log.i(util.format("Downloading: %s", l.data.resolver.name));
    } else if (l.id === 'progress') {
      log.i(util.format("Downloading: %s#%s: %s", name, version, l.message));
    } else if (l.id === 'extract') {
      log.i(util.format("Extracting: %s", l.data.resolver.name));
    } else if (l.id === 'install') {
      log.d(util.format("Installing: %s", l.message));
    }
  })
  .on('error', function (err) {
    if (err) {
      if (err.code === 'ECONFLICT') {
        log.e('Install failed: Unable to find a suitable version for ' + err.name + (data ? ' while installing ' + name + '#' + version : '') + '.');
        log.w('To resolve this conflict, please define resolution to your build.gradle.');
        log.w('Example:');
        log.w('    bower {');
        log.w('        dependencies {');
        log.w("            resolve name: '" + err.name + "', version: '" + err.picks[0].pkgMeta.version + "'");
        log.w('        }');
        log.w('    }');

        log.w('Candidate versions:');
        for (var i = 1; i <= err.picks.length; i++) {
          var pick = err.picks[i - 1];
          var dependants = pick.dependants.map(function(dependant) {
            var result = dependant.pkgMeta.name + '#' + dependant.pkgMeta.version;
            if (result === 'webResource#undefined') {
              result = 'this project'
            }
            return result;
          });
          log.w('    ' + chalk.magenta(i + ') ') + chalk.cyan(pick.endpoint.name + '#' + pick.endpoint.target) + ' which resolved to ' + chalk.green(pick.pkgMeta.version) + ' and is required by ' + chalk.green(dependants.join(', ')));
        }
        if (isSerialInstall) {
          log.w('Some candidates might not be shown above because they are not installed yet.');
          log.w('This is a limitation of this plugin.');
        }
      } else {
        log.e('Install failed: ' + err.code + ': ' + err.stack);
      }
    }
    deferred.reject();
  })
  .on('end', function (installed) {
    if (isSerialInstall) {
      log.i('Installed: ' + name + '#' + version + (offline ? ' (offline)' : ''));
      var hasDependencies = Object.keys(installed).length > 1;
      if (cached && validate && !hasDependencies) {// offline === false) {
        // Installed with cache, but validation occurred
        log.w(util.format('  Note: cache key does not match to the package name.'));
        log.w(util.format('  It means, the package "%s" is cached ', name));
        log.w(util.format('  but still needed a network connection to validate the package '));
        log.w(util.format('  because the cache could not be found by the name "%s".', name));
        log.w(util.format('  To execute installation without any network connections, add cacheName: "%s"', validCacheName));
        log.w(util.format('  to "install" definition in your build.gradle. Example:'));
        log.w(util.format('      bower {'));
        log.w(util.format('          dependencies {'));
        log.w(util.format('              install name: "%s", version: "%s", cacheName: "%s"', name, version, validCacheName));
        log.w(util.format('          }'));
        log.w(util.format('      }'));
      } else if (installed[name] !== undefined && cacheName != installed[name].pkgMeta.name) {
        // Installed without cache but the name doesn't match to the cache key.
        validCacheName = installed[name].pkgMeta.name;
        log.w(util.format('  Note: cache key does not match to the package name.'));
        log.w(util.format('  It means, the package "%s" was cached ', name));
        log.w(util.format('  but you cannot use this cache in the next installation '));
        log.w(util.format('  because the cache will not be found by the name "%s".', name));
        log.w(util.format('  To use this cache in the next installation, add cacheName: "%s"', validCacheName));
        log.w(util.format('  to "install" definition in your build.gradle. Example:'));
        log.w(util.format('      bower {'));
        log.w(util.format('          dependencies {'));
        log.w(util.format('              install name: "%s", version: "%s", cacheName: "%s"', name, version, validCacheName));
        log.w(util.format('          }'));
        log.w(util.format('      }'));
      }
    } else {
      Object.keys(installed).forEach(function(k) {
        var i = installed[k];
        log.i('Installed: ' + i.pkgMeta.name + '#' + i.pkgMeta.version);
      });
    }
    deferred.resolve();
  });
  return deferred.promise;
}

function validateInstalledDependencies() {
  dependencies.forEach(function(e) {
    var cacheName = e.name;
    if (e.hasOwnProperty('cacheName')) {
      cacheName = e.cacheName;
    }
    if (!fs.existsSync('bower_components/' + cacheName)) {
      common.setExitCode(1);
      log.w('Not installed: ' + cacheName);
    }
  });
  if (common.hasError()) {
    log.e('Some dependencies are not installed.');
  }
}

function getInstalledVersion(name) {
  // Some bower.json files don't have "version" attribute.
  // Try .bower.json first, then check bower.json.
  var bowerJson = 'bower_components/' + name + '/.bower.json';
  if (fs.existsSync(bowerJson)) {
    var pkg = JSON.parse(fs.readFileSync(bowerJson, 'utf8'));
    if (pkg.version) {
      return pkg.version;
    }
  }
  bowerJson = 'bower_components/' + name + '/bower.json';
  if (fs.existsSync(bowerJson)) {
    var pkg = JSON.parse(fs.readFileSync(bowerJson, 'utf8'));
    if (pkg.version) {
      return pkg.version;
    }
  }
  return '';
}

function saveCurrentDependencyToJson(name, version) {
  var json = {
    name: "webResource",
    dependencies: {},
    resolutions: {}
  };
  json.dependencies[name] = version;
  json.resolutions = resolutions;
  var jsonStr = JSON.stringify(json, null, '  ');
  fs.writeFileSync('bower.json', jsonStr);
}

function saveBowerJson() {
  var json = {
    name: "webResource",
    dependencies: {},
    resolutions: resolutions
  };
  dependencies.forEach(function(dependency) {
    json.dependencies[dependency.name] = dependency.version;
  });
  var jsonStr = JSON.stringify(json, null, '  ');
  fs.writeFileSync('bower.json', jsonStr);
}
<|endoftext|>


<commit_before>
/**
 * Node style callback.
 * @callback callback
 * @param {Error} error
 * @param {...*} results
 */

/**
 * Server side related documentation.
 *
 * @example
npm package usage

 *   let ChatService = require('chat-service')
 *
 * @namespace chat-service
 */

const ArgumentsValidator = require('./ArgumentsValidator')
const ChatServiceError = require('./ChatServiceError')
const MemoryState = require('./MemoryState')
const Promise = require('bluebird')
const RecoveryAPI = require('./RecoveryAPI')
const RedisState = require('./RedisState')
const ServiceAPI = require('./ServiceAPI')
const SocketIOClusterBus = require('./SocketIOClusterBus')
const SocketIOTransport = require('./SocketIOTransport')
const User = require('./User')
const _ = require('lodash')
const uid = require('uid-safe')
const { EventEmitter } = require('events')
const { checkNameSymbols, execHook } = require('./utils')
const { mixin } = require('es6-mixin')

const rpcRequestsNames = [
  'directAddToList',
  'directGetAccessList',
  'directGetWhitelistMode',
  'directMessage',
  'directRemoveFromList',
  'directSetWhitelistMode',
  'listOwnSockets',
  'roomAddToList',
  'roomCreate',
  'roomDelete',
  'roomGetAccessList',
  'roomGetOwner',
  'roomGetWhitelistMode',
  'roomHistoryGet',
  'roomHistoryInfo',
  'roomJoin',
  'roomLeave',
  'roomMessage',
  'roomRecentHistory',
  'roomRemoveFromList',
  'roomSetWhitelistMode',
  'roomUserSeen',
  'systemMessage'
]

/**
 * Service class, is the package exported object.
 *
 * @extends EventEmitter
 *
 * @mixes chat-service.ServiceAPI
 * @mixes chat-service.RecoveryAPI
 *
 * @fires chat-service.ready
 * @fires chat-service.closed
 * @fires chat-service.storeConsistencyFailure
 * @fires chat-service.transportConsistencyFailure
 * @fires chat-service.lockTimeExceeded
 *
 * @example
starting a server

 *   let ChatService = require('chat-service')
 *   let service = new ChatService(options, hooks)
 *
 * @example
server-side: adding a room

 *   let owner = 'admin'
 *   let whitelistOnly = true
 *   let whitelist = [ 'user' ]
 *   let state = { owner, whitelistOnly, whitelist }
 *   chatService.addRoom('roomName', state).then(fn)
 *
 * @example
server-side: sending a room message

 *   let msg = { textMessage: 'some message' }
 *   let context = {
 *     userName: 'system',
 *     bypassPermissions: true
 *   }
 *   chatService.execUserCommand(context, 'roomMessage', 'roomName', msg)
 *     .then(fn)
 *
 * @memberof chat-service
 *
 */
class ChatService extends EventEmitter {

  /**
   * Crates an object and starts a new service instance. The {@link
   * chat-service.ChatService#close} method __MUST__ be called before
   * the node process exit.
   *
   * @param {chat-service.config.options} [options] Service
   * configuration options.
   *
   * @param {chat-service.hooks.HooksInterface} [hooks] Service
   * customisation hooks.
   */
  constructor (options = {}, hooks = {}) {
    super()
    this.options = options
    this.hooks = hooks
    this.initVariables()
    this.setOptions()
    this.setIntegraionOptions()
    this.setComponents()
    this.attachBusListeners()
    mixin(this, ServiceAPI, this.state,
          () => new User(this), this.clusterBus)
    mixin(this, RecoveryAPI, this.state, this.transport,
          this.execUserCommand.bind(this), this.instanceUID)
    this.startServer()
  }

  /**
   * @name ChatServiceError
   * @type Class
   * @static
   * @readonly
   *
   * @memberof chat-service.ChatService
   */

  /**
   * @name SocketIOClusterBus
   * @type Class
   * @static
   * @readonly
   *
   * @memberof chat-service.ChatService
   */

  /**
   * @name chat-service.ChatService#instanceUID
   * @type string
   * @readonly
   */

  /**
   * @name chat-service.ChatService#redis
   * @type Object|undefined
   * @readonly
   */

  /**
   * @name chat-service.ChatService#io
   * @type Object|undefined
   * @readonly
   */

  /**
   * @name chat-service.ChatService#nsp
   * @type Object|undefined
   * @readonly
   */

  /**
   * @name chat-service.ChatService#clusterBus
   * @type EventEmitter
   * @readonly
   */

  /**
   * @name chat-service.ChatService#transport
   * @type chat-service.TransportInterface
   * @readonly
   */

  /**
   * Service is ready, state and transport are up.
   * @event ready
   *
   * @memberof chat-service
   */

  /**
   * Service is closed, state and transport are closed.
   * @event closed
   * @param {Error} [error] If was closed due to an error.
   *
   * @memberof chat-service
   */

  /**
   * State store failed to be updated to reflect the current user
   * connections or presence state
   * @event storeConsistencyFailure
   * @param {Error} error Error.
   * @param {Object} operationInfo Operation details.
   * @property {string} operationInfo.userName User name.
   * @property {string} operationInfo.opType Operation type.
   * @property {string} [operationInfo.roomName] Room name.
   * @property {string} [operationInfo.id] Socket id.
   *
   * @memberof chat-service
   */

  /**
   * Failed to teardown a transport connection.
   * @event transportConsistencyFailure
   *
   * @param {Error} error Error.
   * @param {Object} operationInfo Operation details.
   * @property {string} operationInfo.userName User name.
   * @property {string} operationInfo.opType Operation type.
   * @property {string} [operationInfo.roomName] Room name.
   * @property {string} [operationInfo.id] Socket id.
   *
   * @memberof chat-service
   */

  /**
   * Lock was hold longer than a lock ttl.
   * @event lockTimeExceeded
   *
   * @param {string} id Lock id.
   * @param {Object} lockInfo Lock resource details.
   * @property {string} [lockInfo.userName] User name.
   * @property {string} [lockInfo.roomName] Room name.
   *
   * @memberof chat-service
   */

  /**
   * Exposes an internal arguments validation method, it is run
   * automatically by all client request handlers.
   *
   * @method chat-service.ChatService#checkArguments
   *
   * @param {string} name Command name.
   * @param {...*} args Command arguments.
   * @param {callback} [cb] Optional callback.
   *
   * @return {Promise<undefined>} Promise that resolves without any
   * data if validation is successful, otherwise a promise is
   * rejected.
   */

  initVariables () {
    this.instanceUID = uid.sync(18)
    this.runningCommands = 0
    this.rpcRequestsNames = rpcRequestsNames
    this.closed = false
  }

  setOptions () {
    this.closeTimeout = this.options.closeTimeout || 15000
    this.busAckTimeout = this.options.busAckTimeout || 5000
    this.heartbeatRate = this.options.heartbeatRate || 10000
    this.heartbeatTimeout = this.options.heartbeatTimeout || 30000
    this.enableAccessListsUpdates =
      this.options.enableAccessListsUpdates || false
    this.enableDirectMessages = this.options.enableDirectMessages || false
    this.enableRoomsManagement = this.options.enableRoomsManagement || false
    this.enableUserlistUpdates = this.options.enableUserlistUpdates || false
    this.historyMaxGetMessages = this.options.historyMaxGetMessages
    if (!_.isNumber(this.historyMaxGetMessages) ||
        this.historyMaxGetMessages < 0) {
      this.historyMaxGetMessages = 100
    }
    this.defaultHistoryLimit = this.options.defaultHistoryLimit
    if (!_.isNumber(this.defaultHistoryLimit) ||
        this.defaultHistoryLimit < 0) {
      this.defaultHistoryLimit = 10000
    }
    this.port = this.options.port || 8000
    this.directMessagesChecker = this.hooks.directMessagesChecker
    this.roomMessagesChecker = this.hooks.roomMessagesChecker
    this.useRawErrorObjects = this.options.useRawErrorObjects || false
  }

  setIntegraionOptions () {
    this.adapterConstructor = this.options.adapter || 'memory'
    this.adapterOptions = _.castArray(this.options.adapterOptions)

    this.stateConstructor = this.options.state || 'memory'
    this.stateOptions = this.options.stateOptions || {}

    this.transportConstructor = this.options.transport || 'socket.io'
    this.transportOptions = this.options.transportOptions || {}
  }

  setComponents () {
    let State = (() => {
      switch (true) {
        case this.stateConstructor === 'memory':
          return MemoryState
        case this.stateConstructor === 'redis':
          return RedisState
        case _.isFunction(this.stateConstructor):
          return this.stateConstructor
        default:
          throw new Error(`Invalid state: ${this.stateConstructor}`)
      }
    })()
    let Transport = (() => {
      switch (true) {
        case this.transportConstructor === 'socket.io':
          return SocketIOTransport
        case _.isFunction(this.transportConstructor):
          return this.transportConstructor
        default:
          throw new Error(`Invalid transport: ${this.transportConstructor}`)
      }
    })()
    this.validator = new ArgumentsValidator(this)
    this.checkArguments = this.validator.checkArguments.bind(this.validator)
    this.state = new State(this, this.stateOptions)
    this.transport = new Transport(
      this, this.transportOptions,
      this.adapterConstructor, this.adapterOptions)
    this.clusterBus = this.transport.clusterBus
  }

  attachBusListeners () {
    this.clusterBus.on('roomLeaveSocket', (id, roomName) => {
      return this.transport.leaveChannel(id, roomName)
        .then(() => this.clusterBus.emit('socketRoomLeft', id, roomName))
        .catchReturn()
    })
    this.clusterBus.on('disconnectUserSockets', userName => {
      return this.state.getUser(userName)
        .then(user => user.disconnectInstanceSockets())
        .catchReturn()
    })
  }

  onConnect (id) {
    if (this.hooks.onConnect) {
      return Promise.try(() => {
        return execHook(this.hooks.onConnect, this, id)
      }).then(loginData => {
        loginData = _.castArray(loginData)
        return Promise.resolve(loginData)
      })
    } else {
      return Promise.resolve([])
    }
  }

  registerClient (userName, id) {
    return checkNameSymbols(userName)
      .then(() => this.state.getOrAddUser(userName))
      .then(user => user.registerSocket(id))
  }

  waitCommands () {
    if (this.runningCommands > 0) {
      return Promise.fromCallback(cb => {
        return this.once('commandsFinished', cb)
      })
    } else {
      return Promise.resolve()
    }
  }

  closeTransport () {
    return this.transport.close()
      .then(() => this.waitCommands())
      .timeout(this.closeTimeout)
  }

  startServer () {
    return Promise.try(() => {
      if (this.hooks.onStart) {
        return this.clusterBus.listen()
          .then(() => execHook(this.hooks.onStart, this))
          .then(() => this.transport.setEvents())
      } else {
        // tests spec compatibility
        return this.transport.setEvents().then(() => this.clusterBus.listen())
      }
    }).then(() => {
      this.state.updateHeartbeat()
      let hbupdater = this.state.updateHeartbeat.bind(this.state)
      this.hbtimer = setInterval(hbupdater, this.heartbeatRate)
      return this.emit('ready')
    }).catch(error => {
      this.closed = true
      return this.closeTransport()
        .then(() => this.state.close())
        .finally(() => this.emit('closed', error))
    })
  }

  /**
   * Closes server.
   * @note __MUST__ be called before node process shutdown to correctly
   *   update the state.
   * @param {callback} [cb] Optional callback.
   * @return {Promise<undefined>} Promise that resolves without any data.
   */
  close (cb) {
    if (this.closed) { return Promise.resolve() }
    this.closed = true
    clearInterval(this.hbtimer)
    let closeError = null
    return this.closeTransport().then(
      () => execHook(this.hooks.onClose, this, null),
      error => {
        if (this.hooks.onClose) {
          return execHook(this.hooks.onClose, this, error)
        } else {
          return Promise.reject(error)
        }
      }).catch(error => {
        closeError = error
        return Promise.reject(error)
      }).finally(() => {
        return this.state.close()
          .finally(() => this.emit('closed', closeError))
      }).asCallback(cb)
  }
}

ChatService.ChatServiceError = ChatServiceError
ChatService.SocketIOClusterBus = SocketIOClusterBus

module.exports = ChatService
<commit_msg>docs: add members description<commit_after>
/**
 * Node style callback.
 * @callback callback
 * @param {Error} error
 * @param {...*} results
 */

/**
 * Server side related documentation.
 *
 * @example
npm package usage

 *   let ChatService = require('chat-service')
 *
 * @namespace chat-service
 */

const ArgumentsValidator = require('./ArgumentsValidator')
const ChatServiceError = require('./ChatServiceError')
const MemoryState = require('./MemoryState')
const Promise = require('bluebird')
const RecoveryAPI = require('./RecoveryAPI')
const RedisState = require('./RedisState')
const ServiceAPI = require('./ServiceAPI')
const SocketIOClusterBus = require('./SocketIOClusterBus')
const SocketIOTransport = require('./SocketIOTransport')
const User = require('./User')
const _ = require('lodash')
const uid = require('uid-safe')
const { EventEmitter } = require('events')
const { checkNameSymbols, execHook } = require('./utils')
const { mixin } = require('es6-mixin')

const rpcRequestsNames = [
  'directAddToList',
  'directGetAccessList',
  'directGetWhitelistMode',
  'directMessage',
  'directRemoveFromList',
  'directSetWhitelistMode',
  'listOwnSockets',
  'roomAddToList',
  'roomCreate',
  'roomDelete',
  'roomGetAccessList',
  'roomGetOwner',
  'roomGetWhitelistMode',
  'roomHistoryGet',
  'roomHistoryInfo',
  'roomJoin',
  'roomLeave',
  'roomMessage',
  'roomRecentHistory',
  'roomRemoveFromList',
  'roomSetWhitelistMode',
  'roomUserSeen',
  'systemMessage'
]

/**
 * Service class, is the package exported object.
 *
 * @extends EventEmitter
 *
 * @mixes chat-service.ServiceAPI
 * @mixes chat-service.RecoveryAPI
 *
 * @fires chat-service.ready
 * @fires chat-service.closed
 * @fires chat-service.storeConsistencyFailure
 * @fires chat-service.transportConsistencyFailure
 * @fires chat-service.lockTimeExceeded
 *
 * @example
starting a server

 *   let ChatService = require('chat-service')
 *   let service = new ChatService(options, hooks)
 *
 * @example
server-side: adding a room

 *   let owner = 'admin'
 *   let whitelistOnly = true
 *   let whitelist = [ 'user' ]
 *   let state = { owner, whitelistOnly, whitelist }
 *   chatService.addRoom('roomName', state).then(fn)
 *
 * @example
server-side: sending a room message

 *   let msg = { textMessage: 'some message' }
 *   let context = {
 *     userName: 'system',
 *     bypassPermissions: true
 *   }
 *   chatService.execUserCommand(context, 'roomMessage', 'roomName', msg)
 *     .then(fn)
 *
 * @memberof chat-service
 *
 */
class ChatService extends EventEmitter {

  /**
   * Crates an object and starts a new service instance. The {@link
   * chat-service.ChatService#close} method __MUST__ be called before
   * the node process exit.
   *
   * @param {chat-service.config.options} [options] Service
   * configuration options.
   *
   * @param {chat-service.hooks.HooksInterface} [hooks] Service
   * customisation hooks.
   */
  constructor (options = {}, hooks = {}) {
    super()
    this.options = options
    this.hooks = hooks
    this.initVariables()
    this.setOptions()
    this.setIntegraionOptions()
    this.setComponents()
    this.attachBusListeners()
    mixin(this, ServiceAPI, this.state,
          () => new User(this), this.clusterBus)
    mixin(this, RecoveryAPI, this.state, this.transport,
          this.execUserCommand.bind(this), this.instanceUID)
    this.startServer()
  }

  /**
   * ChatService errors constructor. This errors are intended to be
   * returned to clients as a part of a normal service functioning
   * (something like 403 errors). Can be also used to create custom
   * errors subclasses.
   *
   * @name ChatServiceError
   * @type Class
   * @static
   * @readonly
   *
   * @memberof chat-service.ChatService
   */

  /**
   * @name SocketIOClusterBus
   * @type Class
   * @static
   * @readonly
   *
   * @memberof chat-service.ChatService
   */

  /**
   * Service instance UID.
   *
   * @name chat-service.ChatService#instanceUID
   * @type string
   * @readonly
   */

  /**
   * `ioredis` instance if `redis` state is used.
   *
   * @name chat-service.ChatService#redis
   * @type Object|undefined
   * @readonly
   */

  /**
   * Socket.io server, if `socket.io` transport is used.
   *
   * @name chat-service.ChatService#io
   * @type Object|undefined
   * @readonly
   */

  /**
   * Socket.io server namespace, if `socket.io` transport is used.
   *
   * @name chat-service.ChatService#nsp
   * @type Object|undefined
   * @readonly
   */

  /**
   * Cluster communication via an adapter. Emits messages to all
   * services nodes, including the sender node.
   *
   * @name chat-service.ChatService#clusterBus
   * @type EventEmitter
   * @readonly
   */

  /**
   * Transport wrapper.
   *
   * @name chat-service.ChatService#transport
   * @type chat-service.TransportInterface
   * @readonly
   */

  /**
   * Service is ready, state and transport are up.
   * @event ready
   *
   * @memberof chat-service
   */

  /**
   * Service is closed, state and transport are closed.
   * @event closed
   * @param {Error} [error] If was closed due to an error.
   *
   * @memberof chat-service
   */

  /**
   * State store failed to be updated to reflect the current user
   * connections or presence state
   * @event storeConsistencyFailure
   * @param {Error} error Error.
   * @param {Object} operationInfo Operation details.
   * @property {string} operationInfo.userName User name.
   * @property {string} operationInfo.opType Operation type.
   * @property {string} [operationInfo.roomName] Room name.
   * @property {string} [operationInfo.id] Socket id.
   *
   * @memberof chat-service
   */

  /**
   * Failed to teardown a transport connection.
   * @event transportConsistencyFailure
   *
   * @param {Error} error Error.
   * @param {Object} operationInfo Operation details.
   * @property {string} operationInfo.userName User name.
   * @property {string} operationInfo.opType Operation type.
   * @property {string} [operationInfo.roomName] Room name.
   * @property {string} [operationInfo.id] Socket id.
   *
   * @memberof chat-service
   */

  /**
   * Lock was hold longer than a lock ttl.
   * @event lockTimeExceeded
   *
   * @param {string} id Lock id.
   * @param {Object} lockInfo Lock resource details.
   * @property {string} [lockInfo.userName] User name.
   * @property {string} [lockInfo.roomName] Room name.
   *
   * @memberof chat-service
   */

  /**
   * Exposes an internal arguments validation method, it is run
   * automatically by all client request handlers.
   *
   * @method chat-service.ChatService#checkArguments
   *
   * @param {string} name Command name.
   * @param {...*} args Command arguments.
   * @param {callback} [cb] Optional callback.
   *
   * @return {Promise<undefined>} Promise that resolves without any
   * data if validation is successful, otherwise a promise is
   * rejected.
   */

  initVariables () {
    this.instanceUID = uid.sync(18)
    this.runningCommands = 0
    this.rpcRequestsNames = rpcRequestsNames
    this.closed = false
  }

  setOptions () {
    this.closeTimeout = this.options.closeTimeout || 15000
    this.busAckTimeout = this.options.busAckTimeout || 5000
    this.heartbeatRate = this.options.heartbeatRate || 10000
    this.heartbeatTimeout = this.options.heartbeatTimeout || 30000
    this.enableAccessListsUpdates =
      this.options.enableAccessListsUpdates || false
    this.enableDirectMessages = this.options.enableDirectMessages || false
    this.enableRoomsManagement = this.options.enableRoomsManagement || false
    this.enableUserlistUpdates = this.options.enableUserlistUpdates || false
    this.historyMaxGetMessages = this.options.historyMaxGetMessages
    if (!_.isNumber(this.historyMaxGetMessages) ||
        this.historyMaxGetMessages < 0) {
      this.historyMaxGetMessages = 100
    }
    this.defaultHistoryLimit = this.options.defaultHistoryLimit
    if (!_.isNumber(this.defaultHistoryLimit) ||
        this.defaultHistoryLimit < 0) {
      this.defaultHistoryLimit = 10000
    }
    this.port = this.options.port || 8000
    this.directMessagesChecker = this.hooks.directMessagesChecker
    this.roomMessagesChecker = this.hooks.roomMessagesChecker
    this.useRawErrorObjects = this.options.useRawErrorObjects || false
  }

  setIntegraionOptions () {
    this.adapterConstructor = this.options.adapter || 'memory'
    this.adapterOptions = _.castArray(this.options.adapterOptions)

    this.stateConstructor = this.options.state || 'memory'
    this.stateOptions = this.options.stateOptions || {}

    this.transportConstructor = this.options.transport || 'socket.io'
    this.transportOptions = this.options.transportOptions || {}
  }

  setComponents () {
    let State = (() => {
      switch (true) {
        case this.stateConstructor === 'memory':
          return MemoryState
        case this.stateConstructor === 'redis':
          return RedisState
        case _.isFunction(this.stateConstructor):
          return this.stateConstructor
        default:
          throw new Error(`Invalid state: ${this.stateConstructor}`)
      }
    })()
    let Transport = (() => {
      switch (true) {
        case this.transportConstructor === 'socket.io':
          return SocketIOTransport
        case _.isFunction(this.transportConstructor):
          return this.transportConstructor
        default:
          throw new Error(`Invalid transport: ${this.transportConstructor}`)
      }
    })()
    this.validator = new ArgumentsValidator(this)
    this.checkArguments = this.validator.checkArguments.bind(this.validator)
    this.state = new State(this, this.stateOptions)
    this.transport = new Transport(
      this, this.transportOptions,
      this.adapterConstructor, this.adapterOptions)
    this.clusterBus = this.transport.clusterBus
  }

  attachBusListeners () {
    this.clusterBus.on('roomLeaveSocket', (id, roomName) => {
      return this.transport.leaveChannel(id, roomName)
        .then(() => this.clusterBus.emit('socketRoomLeft', id, roomName))
        .catchReturn()
    })
    this.clusterBus.on('disconnectUserSockets', userName => {
      return this.state.getUser(userName)
        .then(user => user.disconnectInstanceSockets())
        .catchReturn()
    })
  }

  onConnect (id) {
    if (this.hooks.onConnect) {
      return Promise.try(() => {
        return execHook(this.hooks.onConnect, this, id)
      }).then(loginData => {
        loginData = _.castArray(loginData)
        return Promise.resolve(loginData)
      })
    } else {
      return Promise.resolve([])
    }
  }

  registerClient (userName, id) {
    return checkNameSymbols(userName)
      .then(() => this.state.getOrAddUser(userName))
      .then(user => user.registerSocket(id))
  }

  waitCommands () {
    if (this.runningCommands > 0) {
      return Promise.fromCallback(cb => {
        return this.once('commandsFinished', cb)
      })
    } else {
      return Promise.resolve()
    }
  }

  closeTransport () {
    return this.transport.close()
      .then(() => this.waitCommands())
      .timeout(this.closeTimeout)
  }

  startServer () {
    return Promise.try(() => {
      if (this.hooks.onStart) {
        return this.clusterBus.listen()
          .then(() => execHook(this.hooks.onStart, this))
          .then(() => this.transport.setEvents())
      } else {
        // tests spec compatibility
        return this.transport.setEvents().then(() => this.clusterBus.listen())
      }
    }).then(() => {
      this.state.updateHeartbeat()
      let hbupdater = this.state.updateHeartbeat.bind(this.state)
      this.hbtimer = setInterval(hbupdater, this.heartbeatRate)
      return this.emit('ready')
    }).catch(error => {
      this.closed = true
      return this.closeTransport()
        .then(() => this.state.close())
        .finally(() => this.emit('closed', error))
    })
  }

  /**
   * Closes server.
   * @note __MUST__ be called before node process shutdown to correctly
   *   update the state.
   * @param {callback} [cb] Optional callback.
   * @return {Promise<undefined>} Promise that resolves without any data.
   */
  close (cb) {
    if (this.closed) { return Promise.resolve() }
    this.closed = true
    clearInterval(this.hbtimer)
    let closeError = null
    return this.closeTransport().then(
      () => execHook(this.hooks.onClose, this, null),
      error => {
        if (this.hooks.onClose) {
          return execHook(this.hooks.onClose, this, error)
        } else {
          return Promise.reject(error)
        }
      }).catch(error => {
        closeError = error
        return Promise.reject(error)
      }).finally(() => {
        return this.state.close()
          .finally(() => this.emit('closed', closeError))
      }).asCallback(cb)
  }
}

ChatService.ChatServiceError = ChatServiceError
ChatService.SocketIOClusterBus = SocketIOClusterBus

module.exports = ChatService
<|endoftext|>


<commit_before>/* @flow */

"use strict";

const _ = require("underscore"),
    classNames = require("classNames"),
    TopicTreeHelper = require("../data/topic-tree-helper"),
    React = require("react"),
    component = require("omniscient");

/**
 * Represents a single root, domain, subject, topic, or tutorial
 * item in the topic list.
 * This is represented as a single list item, and when clicked, the
 * list view will be replaced with a bunch of different TopicListItem
 * which are the children of the clicked item.
 */
const TopicListItem = component(({topicTreeNode, domainTopicTreeNode, options}, {onClickTopic}) => {
    var topicClassObj = {
        "topic-item": true,
        faded: options.get("showDownloadsOnly") &&
            TopicTreeHelper.getDownloadCount(topicTreeNode),
    };
    topicClassObj[TopicTreeHelper.getId(domainTopicTreeNode)] = true;
    var topicClass = classNames(topicClassObj);
    return

        { TopicTreeHelper.getKey(topicTreeNode) === TopicTreeHelper.getKey(domainTopicTreeNode) &&

 }

{TopicTreeHelper.getTitle(topicTreeNode)}

;
}).jsx;

/**
 * Represents a single video item in the topic list.
 * This renders the list item and not the actual video.
 * When clicked, it will render the video corresponding to this list item.
 */
const ContentListItem = component(({topicTreeNode, domainTopicTreeNode, options}, {onClick}) => {
    var contentNodeClass = classNames({
      "article-node": TopicTreeHelper.isArticle(topicTreeNode),
      "video-node": TopicTreeHelper.isVideo(topicTreeNode),
      "exercise-node": TopicTreeHelper.isExercise(topicTreeNode),
      completed: TopicTreeHelper.isCompleted(topicTreeNode),
      "in-progress": TopicTreeHelper.isStarted(topicTreeNode),
    });
    var pipeClassObj = {
        pipe: true,
        completed: TopicTreeHelper.isCompleted(topicTreeNode),
        "in-progress": TopicTreeHelper.isStarted(topicTreeNode),
    };
    var subwayIconClassObj = {
        "subway-icon": true,
    };
    var contentClassObj = {
        "video-item": TopicTreeHelper.isVideo(topicTreeNode),
        "article-item": TopicTreeHelper.isArticle(topicTreeNode),
        "exercise-item": TopicTreeHelper.isExercise(topicTreeNode),
        faded: options.get("showDownloadsOnly") &&
            !TopicTreeHelper.isDownloaded(topicTreeNode)
    };
    if (domainTopicTreeNode) {
        subwayIconClassObj[TopicTreeHelper.getId(domainTopicTreeNode)] = true;
        contentClassObj[TopicTreeHelper.getId(domainTopicTreeNode)] = true;
        pipeClassObj[TopicTreeHelper.getId(domainTopicTreeNode)] = true;
    }
    var subwayIconClass = classNames(subwayIconClassObj);
    var pipeClass = classNames(pipeClassObj);
    var contentClass = classNames(contentClassObj);
    return

{TopicTreeHelper.getTitle(topicTreeNode)}

;
}).jsx;

/**
 * Represents a single topic and it displays a list of all of its children.
 * Each child of the list is a ContentListItem
 */
const TopicViewer = component(({topicTreeNode, domainTopicTreeNode, options}, {onClickTopic, onClickContentItem}) =>

                {
                    // Output the child topics
                    TopicTreeHelper.mapChildTopicNodes(topicTreeNode, (childTopicNode) =>
                        <TopicListItem
                            statics={{
                                onClickTopic: onClickTopic
                            }}
                            topicTreeNode={childTopicNode}
                            options={options}
                            domainTopicTreeNode={domainTopicTreeNode || childTopicNode}
                            key={TopicTreeHelper.getKey(childTopicNode)} />
                    )
                }

                {
                    // Output the child content items
                    TopicTreeHelper.mapChildContentNodes(topicTreeNode, (topicTreeNode) =>
                        <ContentListItem
                            statics={{
                                onClick: onClickContentItem
                            }}
                            topicTreeNode={topicTreeNode}
                            options={options}
                            domainTopicTreeNode={domainTopicTreeNode}
                            key={TopicTreeHelper.getKey(topicTreeNode)} />
                    )
                }

).jsx;

/**
 * Represents a list of content items.
 * This is used for displaying search results and download lists.
 * This always contains only a list of VideoListItems, or ARticleListItems.
 */
const ContentListViewer = component(({topicTreeNodes, options}, {onClickContentItem}) =>

                {
                    topicTreeNodes.map((topicTreeNode) => <ContentListItem statics={{
                            onClick: onClickContentItem
                        }}
                        topicTreeNode={topicTreeNode}
                        options={options}
                        key={TopicTreeHelper.getKey(topicTreeNode)} />
                    )
                }

).jsx;

module.exports = {
    ContentListItem,
    TopicViewer,
    ContentListViewer,
};
<commit_msg>Get rid of classNames vs classnames warning on webpack compile<commit_after>/* @flow */

"use strict";

const _ = require("underscore"),
    classNames = require("classnames"),
    TopicTreeHelper = require("../data/topic-tree-helper"),
    React = require("react"),
    component = require("omniscient");

/**
 * Represents a single root, domain, subject, topic, or tutorial
 * item in the topic list.
 * This is represented as a single list item, and when clicked, the
 * list view will be replaced with a bunch of different TopicListItem
 * which are the children of the clicked item.
 */
const TopicListItem = component(({topicTreeNode, domainTopicTreeNode, options}, {onClickTopic}) => {
    var topicClassObj = {
        "topic-item": true,
        faded: options.get("showDownloadsOnly") &&
            TopicTreeHelper.getDownloadCount(topicTreeNode),
    };
    topicClassObj[TopicTreeHelper.getId(domainTopicTreeNode)] = true;
    var topicClass = classNames(topicClassObj);
    return

        { TopicTreeHelper.getKey(topicTreeNode) === TopicTreeHelper.getKey(domainTopicTreeNode) &&

 }

{TopicTreeHelper.getTitle(topicTreeNode)}

;
}).jsx;

/**
 * Represents a single video item in the topic list.
 * This renders the list item and not the actual video.
 * When clicked, it will render the video corresponding to this list item.
 */
const ContentListItem = component(({topicTreeNode, domainTopicTreeNode, options}, {onClick}) => {
    var contentNodeClass = classNames({
      "article-node": TopicTreeHelper.isArticle(topicTreeNode),
      "video-node": TopicTreeHelper.isVideo(topicTreeNode),
      "exercise-node": TopicTreeHelper.isExercise(topicTreeNode),
      completed: TopicTreeHelper.isCompleted(topicTreeNode),
      "in-progress": TopicTreeHelper.isStarted(topicTreeNode),
    });
    var pipeClassObj = {
        pipe: true,
        completed: TopicTreeHelper.isCompleted(topicTreeNode),
        "in-progress": TopicTreeHelper.isStarted(topicTreeNode),
    };
    var subwayIconClassObj = {
        "subway-icon": true,
    };
    var contentClassObj = {
        "video-item": TopicTreeHelper.isVideo(topicTreeNode),
        "article-item": TopicTreeHelper.isArticle(topicTreeNode),
        "exercise-item": TopicTreeHelper.isExercise(topicTreeNode),
        faded: options.get("showDownloadsOnly") &&
            !TopicTreeHelper.isDownloaded(topicTreeNode)
    };
    if (domainTopicTreeNode) {
        subwayIconClassObj[TopicTreeHelper.getId(domainTopicTreeNode)] = true;
        contentClassObj[TopicTreeHelper.getId(domainTopicTreeNode)] = true;
        pipeClassObj[TopicTreeHelper.getId(domainTopicTreeNode)] = true;
    }
    var subwayIconClass = classNames(subwayIconClassObj);
    var pipeClass = classNames(pipeClassObj);
    var contentClass = classNames(contentClassObj);
    return

{TopicTreeHelper.getTitle(topicTreeNode)}

;
}).jsx;

/**
 * Represents a single topic and it displays a list of all of its children.
 * Each child of the list is a ContentListItem
 */
const TopicViewer = component(({topicTreeNode, domainTopicTreeNode, options}, {onClickTopic, onClickContentItem}) =>

                {
                    // Output the child topics
                    TopicTreeHelper.mapChildTopicNodes(topicTreeNode, (childTopicNode) =>
                        <TopicListItem
                            statics={{
                                onClickTopic: onClickTopic
                            }}
                            topicTreeNode={childTopicNode}
                            options={options}
                            domainTopicTreeNode={domainTopicTreeNode || childTopicNode}
                            key={TopicTreeHelper.getKey(childTopicNode)} />
                    )
                }

                {
                    // Output the child content items
                    TopicTreeHelper.mapChildContentNodes(topicTreeNode, (topicTreeNode) =>
                        <ContentListItem
                            statics={{
                                onClick: onClickContentItem
                            }}
                            topicTreeNode={topicTreeNode}
                            options={options}
                            domainTopicTreeNode={domainTopicTreeNode}
                            key={TopicTreeHelper.getKey(topicTreeNode)} />
                    )
                }

).jsx;

/**
 * Represents a list of content items.
 * This is used for displaying search results and download lists.
 * This always contains only a list of VideoListItems, or ARticleListItems.
 */
const ContentListViewer = component(({topicTreeNodes, options}, {onClickContentItem}) =>

                {
                    topicTreeNodes.map((topicTreeNode) => <ContentListItem statics={{
                            onClick: onClickContentItem
                        }}
                        topicTreeNode={topicTreeNode}
                        options={options}
                        key={TopicTreeHelper.getKey(topicTreeNode)} />
                    )
                }

).jsx;

module.exports = {
    ContentListItem,
    TopicViewer,
    ContentListViewer,
};
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// function revealLogin() {
//     console.log("fetching login status");
//     //fetches login staus
//     // document.getElementById("username").style.visibility = "hidden";

//     fetch('/login').then(response => response.json()).then((person) => {
//       console.log("is user logged in? " + person.status);
//       if(person.status == true){
//         var a = document.createElement('a');
//         var link = document.createTextNode("Log out Here");
//         a.appendChild(link);
//         a.title = "Log out Here";
//         a.href = person.url;
//         document.body.appendChild(a);

//         //after they logout, they are directed to the home page
//         // window.open("/_ah/logout?continue\u003d%2Flogin");

//       }
//       else if (person.status == false){
//         // var a = document.createElement('a');
//         // var link = document.createTextNode("Log in Here");
//         // a.appendChild(link);
//         // a.title = "Log in Here";
//         // a.href = person.url;
//         // document.body.appendChild(a);

//         window.open("/_ah/login?continue\u003d%2Flogin");

//         window.open("/nickname.html");

//         //after they login, they create their username
//         // document.getElementById("username").style.visibility = "visible";
//       }
//     });
//   }

function setNickname(){
  fetch('/nickname').then(response => response.json()).then((status) => {
    if(person.status == true){
      document.getElementById("name").value = status.name;

      window.open("/index.html");
    }
    else{
      var a = document.createElement('a');
      var link = document.createTextNode("Log in Here");
      a.appendChild(link);
      a.title = "Log in Here";
      a.href = person.url;
      document.body.appendChild(a);
      window.open("/login.html");
    }
  });
}

function revealLogin() {
  fetch('/login').then(response => response.json()).then((person) => {
    console.log("is user logged in? " + person.status);
    if(person.status == true){
      var a = document.createElement('a');
      var link = document.createTextNode("Log out Here");
      a.appendChild(link);
      a.title = "Log out Here";
      a.href = person.url;
      document.body.appendChild(a);
    }
    else if (person.status == false){
      var a = document.createElement('a');
      var link = document.createTextNode("Log in Here");
      a.appendChild(link);
      a.title = "Log in Here";
      a.href = person.url;
      document.body.appendChild(a);
    }
  });
}

function backHome(){
  var a = document.createElement('a');
  var link = document.createTextNode("Home");
  a.appendChild(link);
  a.title = "Home";
  a.href = index.html;
  // a.onclick = window.open("/index.html");
  document.body.appendChild(a);
}
<commit_msg>remove useless comments<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

function setNickname(){
  fetch('/nickname').then(response => response.json()).then((status) => {
    if(person.status == true){
      document.getElementById("name").value = status.name;

      window.open("/index.html");
    }
    else{
      var a = document.createElement('a');
      var link = document.createTextNode("Log in Here");
      a.appendChild(link);
      a.title = "Log in Here";
      a.href = person.url;
      document.body.appendChild(a);
      window.open("/login.html");
    }
  });
}

function revealLogin() {
  fetch('/login').then(response => response.json()).then((person) => {
    console.log("is user logged in? " + person.status);
    if(person.status == true){
      var a = document.createElement('a');
      var link = document.createTextNode("Log out Here");
      a.appendChild(link);
      a.title = "Log out Here";
      a.href = person.url;
      document.body.appendChild(a);
    }
    else if (person.status == false){
      var a = document.createElement('a');
      var link = document.createTextNode("Log in Here");
      a.appendChild(link);
      a.title = "Log in Here";
      a.href = person.url;
      document.body.appendChild(a);
    }
  });
}

function backHome(){
  var a = document.createElement('a');
  var link = document.createTextNode("Home");
  a.appendChild(link);
  a.title = "Home";
  a.href = index.html;
  // a.onclick = window.open("/index.html");
  document.body.appendChild(a);
}
<|endoftext|>


<commit_before>var Recorder = require('./recorder')
var Monotonic = require('monotonic').asString

function Acceptor (paxos) {
    this.register = paxos._writer.register || {
        body: paxos.log.head.body,
        previous: null
    }
    this.promise = paxos.log.head.body.promise
    this._paxos = paxos
}

Acceptor.prototype.request = function (now, message) {
    switch (message.method) {
    case 'prepare':
        if (Monotonic.compare(this.promise, message.promise) < 0) {
            this.promise = message.promise
            return {
                method: 'promise',
                promise: this.promise,
                register: this.register
            }
        }
        break
    case 'accept':
        if (Monotonic.compare(this.promise, message.body.promise) == 0) {
            var register = {
                body: message.body,
                previous: message.previous
            }
            this.register = register
            this.promise = register.body.promise
            return { method: 'accepted', promise: this.promise }
        }
        break
    }
    return { method: 'reject', promise: this.promise }
}

Acceptor.prototype.createRecorder = function (promise) {
    var entries = [], register = this.register
    while (register) {
        entries.push(register.body)
        register = register.previous
    }

    entries.reverse()

    var found = false
    if (Monotonic.compare(entries[0].promise, promise) < 0) {
        for (var i = 1, I = entries.length - 1; !found && i < I; i++) {
            found = entries[i].promise == promise
        }
    }

    // TODO Does it matter if the promise is off? Or only register contents?
    if (!found) {
        return new Recorder(this._paxos)
    }

    return this
}

Acceptor.prototype.inspect = function () {
    return { type: 'Acceptor', register: this.register }
}

module.exports = Acceptor
<commit_msg>Remove pointless condition.<commit_after>var Recorder = require('./recorder')
var Monotonic = require('monotonic').asString

function Acceptor (paxos) {
    this.register = paxos._writer.register || {
        body: paxos.log.head.body,
        previous: null
    }
    this.promise = paxos.log.head.body.promise
    this._paxos = paxos
}

Acceptor.prototype.request = function (now, message) {
    switch (message.method) {
    case 'prepare':
        if (Monotonic.compare(this.promise, message.promise) < 0) {
            this.promise = message.promise
            return {
                method: 'promise',
                promise: this.promise,
                register: this.register
            }
        }
        break
    case 'accept':
        if (Monotonic.compare(this.promise, message.body.promise) == 0) {
            var register = {
                body: message.body,
                previous: message.previous
            }
            this.register = register
            this.promise = register.body.promise
            return { method: 'accepted', promise: this.promise }
        }
        break
    }
    return { method: 'reject', promise: this.promise }
}

Acceptor.prototype.createRecorder = function (promise) {
    var entries = [], register = this.register
    while (register) {
        entries.push(register.body)
        register = register.previous
    }

    entries.reverse()

    var found = false
    for (var i = 1, I = entries.length - 1; !found && i < I; i++) {
        found = entries[i].promise == promise
    }

    // TODO Does it matter if the promise is off? Or only register contents?
    if (!found) {
        return new Recorder(this._paxos)
    }

    return this
}

Acceptor.prototype.inspect = function () {
    return { type: 'Acceptor', register: this.register }
}

module.exports = Acceptor
<|endoftext|>


<commit_before>'use strict';

const userRouter = require('../routes/user_router');
const chai = require('chai');
const chaiHttp = require('chai-http');
const expect = chai.expect;
const request = chai.request;
const User = require('../models/user');
const baseUrl = 'localhost:5000/api'
chai.use(chaiHttp);

describe('User CRUD tests', function() {
  it('Should create a new user', function(done) {
    request(baseUrl)
      .post('/user/')
      .send({name: 'testUser', overdue: true, amountDue: 50, contact: {phone: '555', email: 'test@test.com'}, role: 'basic'})
      .end(function(err, res) {
        expect(err).to.eql(null);
        expect(res.body).to.have.property('_id');
        expect(res.status).to.eql(200);
        done();
      });
  });

  describe('adding user to db and testing', function() {
    let user;
    before(function(done) {
      user = User({name: 'User1', overdue: true, amountDue: 500, contact: {phone: '5551', email: 'test1@test.com'}, role: 'basic'});
      user.save().then((userData) => {
        this.user = userData;
        done();
      }, (err) => {throw err;
      });
    });

    it('Should GET User1', function(done) {
      request(baseUrl)
        .get('/user/' + user.name)
        .end((err, res) => {
          expect(err).to.eql(null);
          expect(res.body).to.have.property('_id');
          done();
        });
    });

    it('Should GET all users', function(done) {
      request(baseUrl)
        .get('/user/')
        .end((err, res) => {
          expect(err).to.eql(null);
          expect(res.status).to.eql(200);
          done();
        });
    });

    it('Should update User1', function(done) {
      user.overdue = false;
      request(baseUrl)
        .put('/user/' + user.name)
        .send(user)
        .end((err, res) => {
          expect(err).to.eql(null);
          expect(res.status).to.eql(200);
          expect(res.body.message).to.eql('Success');
          done();
        });
    });
    it('should DELETE a user', function(done) {
      request(baseUrl)
        .delete('/user/' + user.name)
        .end((err, res) => {
          expect(err).to.eql(null);
          expect(res.status).to.eql(200);
          expect(res.body.message).to.eql('Success');
          done();
        });
    });
  });
});
<commit_msg>last minor<commit_after>'use strict';

const userRouter = require('../routes/user_router');
const chai = require('chai');
const chaiHttp = require('chai-http');
const expect = chai.expect;
const request = chai.request;
const User = require('../models/user');
const baseUrl = 'localhost:5000/api';
chai.use(chaiHttp);

describe('User CRUD tests', function() {
  it('Should create a new user', function(done) {
    request(baseUrl)
      .post('/user/')
      .send({name: 'testUser', overdue: true, amountDue: 50, contact: {phone: '555', email: 'test@test.com'}, role: 'basic'})
      .end(function(err, res) {
        expect(err).to.eql(null);
        expect(res.body).to.have.property('_id');
        expect(res.status).to.eql(200);
        done();
      });
  });

  describe('adding user to db and testing', function() {
    let user;
    before(function(done) {
      user = User({name: 'User1', overdue: true, amountDue: 500, contact: {phone: '5551', email: 'test1@test.com'}, role: 'basic'});
      user.save().then((userData) => {
        this.user = userData;
        done();
      }, (err) => {throw err;
      });
    });

    it('Should GET User1', function(done) {
      request(baseUrl)
        .get('/user/' + user.name)
        .end((err, res) => {
          expect(err).to.eql(null);
          expect(res.body).to.have.property('_id');
          done();
        });
    });

    it('Should GET all users', function(done) {
      request(baseUrl)
        .get('/user/')
        .end((err, res) => {
          expect(err).to.eql(null);
          expect(res.status).to.eql(200);
          done();
        });
    });

    it('Should update User1', function(done) {
      user.overdue = false;
      request(baseUrl)
        .put('/user/' + user.name)
        .send(user)
        .end((err, res) => {
          expect(err).to.eql(null);
          expect(res.status).to.eql(200);
          expect(res.body.message).to.eql('Success');
          done();
        });
    });
    it('should DELETE a user', function(done) {
      request(baseUrl)
        .delete('/user/' + user.name)
        .end((err, res) => {
          expect(err).to.eql(null);
          expect(res.status).to.eql(200);
          expect(res.body.message).to.eql('Success');
          done();
        });
    });
  });
});
<|endoftext|>


<commit_before>// @flow

import semver from 'semver';
import inquirer from 'inquirer';
import { mainStory, chalk } from 'storyboard';
import { readAllSpecs, ROOT_PACKAGE } from './utils/readSpecs';
import writeSpecs from './utils/writeSpecs';
import { exec } from './utils/shell';
import {
  gitLastTag,
  gitCurBranch,
  gitUncommittedChanges,
  gitUnpulledChanges,
  gitDiffSinceIn,
  gitCommitChanges,
  gitAddTag,
  gitPushWithTags,
} from './utils/git';
import { addVersionLine } from './utils/changelog';
import { masterOrMainBranch } from './utils/helpers';
import { calcGraphAndReturnAsAllSpecs } from './utils/calcGraph';

const DEBUG_SKIP_CHECKS = false;
const RELEASE_INCREMENTS = ['major', 'minor', 'patch'];
const PRERELEASE_INCREMENTS = ['rc', 'beta', 'alpha'];
const INCREMENTS = [...RELEASE_INCREMENTS, ...PRERELEASE_INCREMENTS];

type Options = {
  src: string,
  ignoreSrc?: string,
  incrementVersionBy?: string,
  master: boolean,
  checkUncommitted: boolean,
  checkUnpulled: boolean,
  checks: boolean,
  confirm: boolean,
  bump: boolean,
  gitCommit: boolean,
  newVersion?: string,
  npmPublish: boolean,
  publishTag?: string,
  otp?: string,
  access?: string,
  changelog: boolean,
  changelogPath: string,
  single: boolean,
  // For unit tests
  _date?: ?Object, // overrides the current date
  _masterVersion?: string, // overrides the current master version
};

const run = async ({
  src,
  ignoreSrc,
  master,
  checkUncommitted,
  checkUnpulled,
  checks,
  confirm,
  bump,
  gitCommit,
  newVersion,
  npmPublish,
  publishTag,
  incrementVersionBy,
  changelog,
  changelogPath,
  single,
  otp,
  access,
  _date,
  _masterVersion,
}: Options) => {
  const allSpecs = calcGraphAndReturnAsAllSpecs(
    await readAllSpecs(src, ignoreSrc)
  );

  // Confirm that we have run build and run prepublish checks
  if (confirm && !(await confirmBuild())) return;
  await prepublishChecks({ checks, master, checkUncommitted, checkUnpulled });

  // Get list of packages to be updated. This is NOT the list of packages to
  // be published, since some of them might be private. But all of them will
  // be version-bumped
  const pkgList = [];
  let numPublic = 0;
  Object.keys(allSpecs).forEach(pkgName => {
    if (pkgName === ROOT_PACKAGE && !single) return;
    pkgList.push(pkgName);
    const { specs } = allSpecs[pkgName];
    if (!specs.private) numPublic += 1;
  });
  if (!pkgList.length) {
    mainStory.info('No packages found!');
    return;
  }

  if (bump) {
    // Determine a suitable new version number
    const lastTag = await gitLastTag();
    const masterVersion =
      _masterVersion || (await getMasterVersion(allSpecs, lastTag));
    if (masterVersion == null) return;
    if (incrementVersionBy) validateVersionIncrement(incrementVersionBy);
    const nextVersion =
      newVersion ||
      calcNextVersion(masterVersion, incrementVersionBy) ||
      (await promptNextVersion(masterVersion));

    // Confirm before proceeding
    if (confirm && !(await confirmPublish({ pkgList, numPublic, nextVersion })))
      return;

    // Update package.json's for pkgList packages AND THE ROOT PACKAGE
    const pkgListPlusRoot = single ? pkgList : pkgList.concat(ROOT_PACKAGE);
    pkgListPlusRoot.forEach(pkgName => {
      const { specPath, specs } = allSpecs[pkgName];
      specs.version = nextVersion;
      writeSpecs(specPath, specs);
    });

    // Update changelog
    if (changelog) {
      addVersionLine({ changelogPath, version: nextVersion, _date });
    }

    // Commit, tag and push
    if (gitCommit) {
      await gitCommitChanges(`v${nextVersion}`);
      await gitAddTag(`v${nextVersion}`);
      await gitPushWithTags();
    }
  }

  // Publish
  if (npmPublish) {
    for (let i = 0; i < pkgList.length; i++) {
      const pkgName = pkgList[i];
      const { pkgPath, specs } = allSpecs[pkgName];
      if (specs.private) continue; // we don't want npm to complain :)
      let cmd = 'npm publish';
      if (publishTag != null) cmd += ` --tag ${publishTag}`;
      if (otp != null) cmd += ` --otp ${otp}`;
      if (access === 'public' || access === 'restricted')
        cmd += ` --access ${access}`;
      await exec(cmd, { cwd: pkgPath });
    }
  }
};

// ------------------------------------------------
// Helpers
// ------------------------------------------------
const prepublishChecks = async ({
  checks,
  master,
  checkUncommitted,
  checkUnpulled,
}) => {
  if (!checks) return;
  if (DEBUG_SKIP_CHECKS) {
    mainStory.warn('DEBUG_SKIP_CHECKS should be disabled!!');
  }

  // Check current branch
  const branch = await gitCurBranch();
  if (!masterOrMainBranch(branch)) {
    if (master) {
      mainStory.error(
        `Can't publish from current branch: ${chalk.bold(branch)}`
      );
      if (!DEBUG_SKIP_CHECKS) throw new Error('BRANCH_CHECK_FAILED');
    }
    mainStory.warn(
      `Publishing from a non-master or non-main branch: ${chalk.red.bold(
        branch
      )}`
    );
  } else {
    mainStory.info(`Current branch: ${chalk.yellow.bold(branch)}`);
  }

  // Check that the branch is clean
  const uncommitted = await gitUncommittedChanges();
  if (uncommitted !== '') {
    if (checkUncommitted) {
      mainStory.error(
        `Can't publish with uncommitted changes (stash/commit them): \n${chalk.bold(
          uncommitted
        )}`
      );
      if (!DEBUG_SKIP_CHECKS) throw new Error('UNCOMMITTED_CHECK_FAILED');
    }
    mainStory.warn('Publishing with uncommitted changes');
  } else {
    mainStory.info('No uncommitted changes');
  }

  // Check remote history
  const unpulled = await gitUnpulledChanges();
  if (unpulled !== '0') {
    if (checkUnpulled) {
      mainStory.error('Remote history differs. Please pull changes');
      if (!DEBUG_SKIP_CHECKS) throw new Error('UNPULLED_CHECK_FAILED');
    }
    mainStory.warn('Publishing with unpulled changes');
  } else {
    mainStory.info('Remote history matches local history');
  }
};

const confirmBuild = async () => {
  const { confirmBuild: out } = await inquirer.prompt([
    {
      name: 'confirmBuild',
      type: 'confirm',
      message: 'Have you built all your packages for production?',
      default: false,
    },
  ]);
  return out;
};

const confirmPublish = async ({ pkgList, numPublic, nextVersion }) => {
  const { confirmPublish: out } = await inquirer.prompt([
    {
      name: 'confirmPublish',
      type: 'confirm',
      message: `Confirm release (${chalk.yellow.bold(
        pkgList.length
      )} package/s, ${chalk.yellow.bold(numPublic)} public, v${chalk.cyan.bold(
        nextVersion
      )})?`,
      default: false,
    },
  ]);
  return out;
};

const validateVersionIncrement = incrementVersionBy => {
  if (INCREMENTS.indexOf(incrementVersionBy) < 0) {
    mainStory.error(
      `Value specified for --increment-version-by: ${chalk.bold(
        incrementVersionBy
      )} is invalid.`
    );
    mainStory.error(
      `It should be one of (${INCREMENTS.join(', ')}), or not specified.`
    );
    if (!DEBUG_SKIP_CHECKS) throw new Error('INVALID_INCREMENT_BY_VALUE');
  }
};

const getMasterVersion = async (allSpecs, lastTag) => {
  let masterVersion = allSpecs[ROOT_PACKAGE].specs.version;
  if (lastTag != null) {
    const tagVersion = semver.clean(lastTag);
    mainStory.info(`Last tag found: ${chalk.yellow.bold(lastTag)}`);
    if (tagVersion !== masterVersion) {
      mainStory.warn(
        `Last tagged version ${chalk.cyan.bold(
          tagVersion
        )} does not match package.json version ${chalk.cyan.bold(
          masterVersion
        )}`
      );
      const { confirm } = await inquirer.prompt([
        {
          name: 'confirm',
          type: 'confirm',
          message: 'Continue?',
          default: false,
        },
      ]);
      if (!confirm) return null;
      if (semver.valid(tagVersion) && semver.gt(tagVersion, masterVersion)) {
        masterVersion = tagVersion;
      }
      mainStory.warn(
        `Using ${chalk.cyan.bold(
          masterVersion
        )} as reference (the highest one of both)`
      );
    }
  } else {
    mainStory.warn('Repo has no tags yet');
  }
  if (!semver.valid(masterVersion)) {
    mainStory.error(
      `Master version ${chalk.cyan.bold(
        masterVersion
      )} is invalid. Please correct it manually`
    );
    throw new Error('INVALID_VERSION');
  }
  return masterVersion;
};

const calcNextVersion = (prevVersion: string, incrementBy = ''): ?string => {
  if (!incrementBy) return null;
  const isPreRelease = PRERELEASE_INCREMENTS.indexOf(incrementBy) >= 0;
  const increment = isPreRelease ? 'prerelease' : incrementBy;
  const isNewPreRelease = isPreRelease && prevVersion.indexOf(incrementBy) < 0;
  return isNewPreRelease
    ? `${semver.inc(prevVersion, 'major')}-${incrementBy}.0`
    : semver.inc(prevVersion, increment);
};

const promptNextVersion = async (prevVersion: string): Promise<string> => {
  const major = semver.inc(prevVersion, 'major');
  const minor = semver.inc(prevVersion, 'minor');
  const patch = semver.inc(prevVersion, 'patch');
  const prerelease = semver.inc(prevVersion, 'prerelease');
  const rc = prevVersion.indexOf('rc') < 0 ? `${major}-rc.0` : prerelease;
  const beta = prevVersion.indexOf('beta') < 0 ? `${major}-beta.0` : prerelease;
  const alpha =
    prevVersion.indexOf('alpha') < 0 ? `${major}-alpha.0` : prerelease;
  const { nextVersion } = await inquirer.prompt([
    {
      name: 'nextVersion',
      type: 'list',
      message: `Current version is ${chalk.cyan.bold(prevVersion)}. Next one?`,
      choices: [
        { name: `Major (${chalk.cyan.bold(major)})`, value: major },
        { name: `Minor (${chalk.cyan.bold(minor)})`, value: minor },
        { name: `Patch (${chalk.cyan.bold(patch)})`, value: patch },
        { name: `Release candidate (${chalk.cyan.bold(rc)})`, value: rc },
        { name: `Beta (${chalk.cyan.bold(beta)})`, value: beta },
        { name: `Alpha (${chalk.cyan.bold(alpha)})`, value: alpha },
      ],
      defaultValue: 2,
    },
  ]);
  return nextVersion;
};

// ------------------------------------------------
// Public
// ------------------------------------------------
export default run;
<commit_msg>Bump dependent requirements before publishing (default version: range), see #100<commit_after>// @flow

import semver from 'semver';
import inquirer from 'inquirer';
import { mainStory, chalk } from 'storyboard';
import { readAllSpecs, ROOT_PACKAGE } from './utils/readSpecs';
import writeSpecs from './utils/writeSpecs';
import { exec } from './utils/shell';
import {
  gitLastTag,
  gitCurBranch,
  gitUncommittedChanges,
  gitUnpulledChanges,
  gitDiffSinceIn,
  gitCommitChanges,
  gitAddTag,
  gitPushWithTags,
} from './utils/git';
import { addVersionLine } from './utils/changelog';
import { masterOrMainBranch } from './utils/helpers';
import { calcGraphAndReturnAsAllSpecs } from './utils/calcGraph';
import bumpDeps from './bump';

const DEBUG_SKIP_CHECKS = false;
const RELEASE_INCREMENTS = ['major', 'minor', 'patch'];
const PRERELEASE_INCREMENTS = ['rc', 'beta', 'alpha'];
const INCREMENTS = [...RELEASE_INCREMENTS, ...PRERELEASE_INCREMENTS];

type Options = {
  src: string,
  ignoreSrc?: string,
  link: ?string,
  incrementVersionBy?: string,
  master: boolean,
  checkUncommitted: boolean,
  checkUnpulled: boolean,
  checks: boolean,
  confirm: boolean,
  bump: boolean,
  gitCommit: boolean,
  newVersion?: string,
  npmPublish: boolean,
  publishTag?: string,
  otp?: string,
  access?: string,
  changelog: boolean,
  changelogPath: string,
  single: boolean,
  // For unit tests
  _date?: ?Object, // overrides the current date
  _masterVersion?: string, // overrides the current master version
};

const run = async ({
  src,
  ignoreSrc,
  link,
  master,
  checkUncommitted,
  checkUnpulled,
  checks,
  confirm,
  bump,
  gitCommit,
  newVersion,
  npmPublish,
  publishTag,
  incrementVersionBy,
  changelog,
  changelogPath,
  single,
  otp,
  access,
  _date,
  _masterVersion,
}: Options) => {
  const allSpecs = calcGraphAndReturnAsAllSpecs(
    await readAllSpecs(src, ignoreSrc)
  );

  // Confirm that we have run build and run prepublish checks
  if (confirm && !(await confirmBuild())) return;
  await prepublishChecks({ checks, master, checkUncommitted, checkUnpulled });

  // Get list of packages to be updated. This is NOT the list of packages to
  // be published, since some of them might be private. But all of them will
  // be version-bumped
  const pkgList = [];
  let numPublic = 0;
  Object.keys(allSpecs).forEach(pkgName => {
    if (pkgName === ROOT_PACKAGE && !single) return;
    pkgList.push(pkgName);
    const { specs } = allSpecs[pkgName];
    if (!specs.private) numPublic += 1;
  });
  if (!pkgList.length) {
    mainStory.info('No packages found!');
    return;
  }

  if (bump) {
    // Determine a suitable new version number
    const lastTag = await gitLastTag();
    const masterVersion =
      _masterVersion || (await getMasterVersion(allSpecs, lastTag));
    if (masterVersion == null) return;
    if (incrementVersionBy) validateVersionIncrement(incrementVersionBy);
    const nextVersion =
      newVersion ||
      calcNextVersion(masterVersion, incrementVersionBy) ||
      (await promptNextVersion(masterVersion));

    // Confirm before proceeding
    if (confirm && !(await confirmPublish({ pkgList, numPublic, nextVersion })))
      return;

    // Update package.json's for pkgList packages AND THE ROOT PACKAGE
    const pkgListPlusRoot = single ? pkgList : pkgList.concat(ROOT_PACKAGE);
    pkgListPlusRoot.forEach(pkgName => {
      const { specPath, specs } = allSpecs[pkgName];
      specs.version = nextVersion;
      writeSpecs(specPath, specs);
    });

    // Bump dependent requirements
    if (!single) {
      const bumpList = pkgList.map(pkgName => `${pkgName}@^${nextVersion}`);
      await bumpDeps(bumpList, { src, ignoreSrc, link });
    }

    // Update changelog
    if (changelog) {
      addVersionLine({ changelogPath, version: nextVersion, _date });
    }

    // Commit, tag and push
    if (gitCommit) {
      await gitCommitChanges(`v${nextVersion}`);
      await gitAddTag(`v${nextVersion}`);
      await gitPushWithTags();
    }
  }

  // Publish
  if (npmPublish) {
    for (let i = 0; i < pkgList.length; i++) {
      const pkgName = pkgList[i];
      const { pkgPath, specs } = allSpecs[pkgName];
      if (specs.private) continue; // we don't want npm to complain :)
      let cmd = 'npm publish';
      if (publishTag != null) cmd += ` --tag ${publishTag}`;
      if (otp != null) cmd += ` --otp ${otp}`;
      if (access === 'public' || access === 'restricted')
        cmd += ` --access ${access}`;
      await exec(cmd, { cwd: pkgPath });
    }
  }
};

// ------------------------------------------------
// Helpers
// ------------------------------------------------
const prepublishChecks = async ({
  checks,
  master,
  checkUncommitted,
  checkUnpulled,
}) => {
  if (!checks) return;
  if (DEBUG_SKIP_CHECKS) {
    mainStory.warn('DEBUG_SKIP_CHECKS should be disabled!!');
  }

  // Check current branch
  const branch = await gitCurBranch();
  if (!masterOrMainBranch(branch)) {
    if (master) {
      mainStory.error(
        `Can't publish from current branch: ${chalk.bold(branch)}`
      );
      if (!DEBUG_SKIP_CHECKS) throw new Error('BRANCH_CHECK_FAILED');
    }
    mainStory.warn(
      `Publishing from a non-master or non-main branch: ${chalk.red.bold(
        branch
      )}`
    );
  } else {
    mainStory.info(`Current branch: ${chalk.yellow.bold(branch)}`);
  }

  // Check that the branch is clean
  const uncommitted = await gitUncommittedChanges();
  if (uncommitted !== '') {
    if (checkUncommitted) {
      mainStory.error(
        `Can't publish with uncommitted changes (stash/commit them): \n${chalk.bold(
          uncommitted
        )}`
      );
      if (!DEBUG_SKIP_CHECKS) throw new Error('UNCOMMITTED_CHECK_FAILED');
    }
    mainStory.warn('Publishing with uncommitted changes');
  } else {
    mainStory.info('No uncommitted changes');
  }

  // Check remote history
  const unpulled = await gitUnpulledChanges();
  if (unpulled !== '0') {
    if (checkUnpulled) {
      mainStory.error('Remote history differs. Please pull changes');
      if (!DEBUG_SKIP_CHECKS) throw new Error('UNPULLED_CHECK_FAILED');
    }
    mainStory.warn('Publishing with unpulled changes');
  } else {
    mainStory.info('Remote history matches local history');
  }
};

const confirmBuild = async () => {
  const { confirmBuild: out } = await inquirer.prompt([
    {
      name: 'confirmBuild',
      type: 'confirm',
      message: 'Have you built all your packages for production?',
      default: false,
    },
  ]);
  return out;
};

const confirmPublish = async ({ pkgList, numPublic, nextVersion }) => {
  const { confirmPublish: out } = await inquirer.prompt([
    {
      name: 'confirmPublish',
      type: 'confirm',
      message: `Confirm release (${chalk.yellow.bold(
        pkgList.length
      )} package/s, ${chalk.yellow.bold(numPublic)} public, v${chalk.cyan.bold(
        nextVersion
      )})?`,
      default: false,
    },
  ]);
  return out;
};

const validateVersionIncrement = incrementVersionBy => {
  if (INCREMENTS.indexOf(incrementVersionBy) < 0) {
    mainStory.error(
      `Value specified for --increment-version-by: ${chalk.bold(
        incrementVersionBy
      )} is invalid.`
    );
    mainStory.error(
      `It should be one of (${INCREMENTS.join(', ')}), or not specified.`
    );
    if (!DEBUG_SKIP_CHECKS) throw new Error('INVALID_INCREMENT_BY_VALUE');
  }
};

const getMasterVersion = async (allSpecs, lastTag) => {
  let masterVersion = allSpecs[ROOT_PACKAGE].specs.version;
  if (lastTag != null) {
    const tagVersion = semver.clean(lastTag);
    mainStory.info(`Last tag found: ${chalk.yellow.bold(lastTag)}`);
    if (tagVersion !== masterVersion) {
      mainStory.warn(
        `Last tagged version ${chalk.cyan.bold(
          tagVersion
        )} does not match package.json version ${chalk.cyan.bold(
          masterVersion
        )}`
      );
      const { confirm } = await inquirer.prompt([
        {
          name: 'confirm',
          type: 'confirm',
          message: 'Continue?',
          default: false,
        },
      ]);
      if (!confirm) return null;
      if (semver.valid(tagVersion) && semver.gt(tagVersion, masterVersion)) {
        masterVersion = tagVersion;
      }
      mainStory.warn(
        `Using ${chalk.cyan.bold(
          masterVersion
        )} as reference (the highest one of both)`
      );
    }
  } else {
    mainStory.warn('Repo has no tags yet');
  }
  if (!semver.valid(masterVersion)) {
    mainStory.error(
      `Master version ${chalk.cyan.bold(
        masterVersion
      )} is invalid. Please correct it manually`
    );
    throw new Error('INVALID_VERSION');
  }
  return masterVersion;
};

const calcNextVersion = (prevVersion: string, incrementBy = ''): ?string => {
  if (!incrementBy) return null;
  const isPreRelease = PRERELEASE_INCREMENTS.indexOf(incrementBy) >= 0;
  const increment = isPreRelease ? 'prerelease' : incrementBy;
  const isNewPreRelease = isPreRelease && prevVersion.indexOf(incrementBy) < 0;
  return isNewPreRelease
    ? `${semver.inc(prevVersion, 'major')}-${incrementBy}.0`
    : semver.inc(prevVersion, increment);
};

const promptNextVersion = async (prevVersion: string): Promise<string> => {
  const major = semver.inc(prevVersion, 'major');
  const minor = semver.inc(prevVersion, 'minor');
  const patch = semver.inc(prevVersion, 'patch');
  const prerelease = semver.inc(prevVersion, 'prerelease');
  const rc = prevVersion.indexOf('rc') < 0 ? `${major}-rc.0` : prerelease;
  const beta = prevVersion.indexOf('beta') < 0 ? `${major}-beta.0` : prerelease;
  const alpha =
    prevVersion.indexOf('alpha') < 0 ? `${major}-alpha.0` : prerelease;
  const { nextVersion } = await inquirer.prompt([
    {
      name: 'nextVersion',
      type: 'list',
      message: `Current version is ${chalk.cyan.bold(prevVersion)}. Next one?`,
      choices: [
        { name: `Major (${chalk.cyan.bold(major)})`, value: major },
        { name: `Minor (${chalk.cyan.bold(minor)})`, value: minor },
        { name: `Patch (${chalk.cyan.bold(patch)})`, value: patch },
        { name: `Release candidate (${chalk.cyan.bold(rc)})`, value: rc },
        { name: `Beta (${chalk.cyan.bold(beta)})`, value: beta },
        { name: `Alpha (${chalk.cyan.bold(alpha)})`, value: alpha },
      ],
      defaultValue: 2,
    },
  ]);
  return nextVersion;
};

// ------------------------------------------------
// Public
// ------------------------------------------------
export default run;
<|endoftext|>


<commit_before>
assert(ProcessingInstruction);
assert(DocumentType);
assert(Document);

var doctype = document.implementation.createDocumentType("foo", "bar", "baz");

assert(doctype.name === "foo", doctype.name);
assert(doctype.publicId === "bar", doctype.publicId);
assert(doctype.systemId === "baz", doctype.systemId);

var doc = document.implementation.createDocument(
    "http://example.com/namespace", "qual", doctype);

assert(doc.isDefaultNamespace('http://example.com/namespace'));

var proc = doc.createProcessingInstruction("target", "proc");

assert(proc.data === "proc", proc.data);

var cloned = proc.cloneNode();

cloned.data = "clone";

assert(proc.data === "proc", proc.data);
assert(cloned.data === "clone", cloned.data);

assert(proc.target === "target");
assert(cloned.target === "target");

<commit_msg>More coverage for DOMImplementation.<commit_after>
assert(ProcessingInstruction);
assert(DocumentType);
assert(Document);

var doctype = document.implementation.createDocumentType("foo", "bar", "baz");

assert(doctype.name === "foo", doctype.name);
assert(doctype.publicId === "bar", doctype.publicId);
assert(doctype.systemId === "baz", doctype.systemId);

var doc = document.implementation.createDocument(
    "http://example.com/namespace", "qual", doctype);

assert(doc.isDefaultNamespace('http://example.com/namespace'));

var proc = doc.createProcessingInstruction("target", "proc");

assert(proc.data === "proc", proc.data);

var cloned = proc.cloneNode();

cloned.data = "clone";

assert(proc.data === "proc", proc.data);
assert(cloned.data === "clone", cloned.data);

assert(proc.target === "target");
assert(cloned.target === "target");

document.implementation.createDocument("", "");

assertThrows(function() {
    document.implementation.createDocument("foo", "bar", doctype);
});

assertThrows(function() {
    document.implementation.createDocumentType("", "");
});

<|endoftext|>


<commit_before>import Ember from 'ember';
import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';
const { Application } = Ember;

Ember.MODEL_FACTORY_INJECTIONS = true;

const app = Application.extend({
  modulePrefix: config.modulePrefix,
  podModulePrefix: config.podModulePrefix,
  Resolver
});

loadInitializers(app, config.modulePrefix);

export default app;
<commit_msg>use shim<commit_after>import Ember from 'ember';
import Application from 'ember-application';
import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers';
import config from './config/environment';

Ember.MODEL_FACTORY_INJECTIONS = true;

const app = Application.extend({
  modulePrefix: config.modulePrefix,
  podModulePrefix: config.podModulePrefix,
  Resolver
});

loadInitializers(app, config.modulePrefix);

export default app;
<|endoftext|>