<commit_before>/* global XLSX*/
'use strict';

angular.module('metadatamanagementApp').service('VariableBuilderService',
function(Variable, CleanJSObjectService, JobLoggingService) {
  var getVariables = function(data, dataAcquisitionProjectId) {
    var jsonContent = {};
    var variablesObjArray = [];
    try {
      var excelFile = data.files['variables.xlsx'];
      var content = XLSX.read(excelFile.asBinary(), {type: 'binary'});
      var sheetList = content.SheetNames;
      var worksheet = content.Sheets[sheetList[0]];
      // jscs:disable
      jsonContent = XLSX.utils.sheet_to_json(worksheet);
      // jscs:enable
      for (var i = 0; i < jsonContent.length; i++) {
        var variableObj = {
        id: jsonContent[i].id,
        atomicQuestionId: jsonContent[i].atomicQuestionId,
        accessWays: CleanJSObjectService.
        removeWhiteSpace(jsonContent[i].accessWays),
        dataAcquisitionProjectId: dataAcquisitionProjectId,
        dataType: {
          en: jsonContent[i]['dataType.en'],
          de: jsonContent[i]['dataType.de']
        },
        label: {
          en: jsonContent[i]['label.en'],
          de: jsonContent[i]['label.de']
        },
        description: {
          en: jsonContent[i]['description.en'],
          de: jsonContent[i]['description.de']
        },
        filterDetails: {
          filterExpression:
          jsonContent[i]['filterDetails.filterExpression'],
          filterDescription: {
            en: jsonContent[i]['filterDetails.filterDescription.de'],
            de: jsonContent[i]['filterDetails.filterDescription.en']
          },
          filterExpressionLanguage:
          jsonContent[i]['filterDetails.filterExpressionLanguage']
        },
        generationDetails: {
          rule: jsonContent[i]['generationDetails.rule'],
          ruleExpressionLanguage: jsonContent[i]
          ['generationDetails.ruleExpressionLanguage'],
          description: {
            en: jsonContent[i]['generationDetails.description.en'],
            de: jsonContent[i]['generationDetails.description.de']
          }
        },
        sameVariablesInPanel: CleanJSObjectService.
        removeWhiteSpace(jsonContent[i].sameVariablesInPanel),
        name: jsonContent[i].name,
        scaleLevel: {
          en: jsonContent[i]['scaleLevel.en'],
          de: jsonContent[i]['scaleLevel.de']
        },
        statistics: {
          firstQuartile: jsonContent[i]['statistics.firstQuartile'],
          highWhisker: jsonContent[i]['statistics.highWhisker'],
          kurtosis: jsonContent[i]['statistics.kurtosis'],
          lowWhisker: jsonContent[i]['statistics.lowWhisker'],
          maximum: jsonContent[i]['statistics.maximum'],
          meanValue: jsonContent[i]['statistics.meanValue'],
          median: jsonContent[i]['statistics.median'],
          minimum: jsonContent[i]['statistics.minimum'],
          skewness: jsonContent[i]['statistics.skewness'],
          standardDeviation: jsonContent[i]
          ['statistics.standardDeviation'],
          thirdQuartile: jsonContent[i]['statistics.thirdQuartile']
        },
        values: data.files['values/' + jsonContent[i].id + '.json'] ?
          JSON.parse(data.files['values/' + jsonContent[i].id + '.json']
          .asBinary()).values : undefined,
        surveyIds: CleanJSObjectService.
        removeWhiteSpace(jsonContent[i].surveyIds),
        conceptId: jsonContent[i].conceptId,
        dataSetIds: CleanJSObjectService.
        removeWhiteSpace(jsonContent[i].dataSetIds),
        valueSummary: {
          totalAbsoluteFrequency:
          jsonContent[i]['valueSummary.totalAbsoluteFrequency'],
          totalValidAbsoluteFrequency:
          jsonContent[i]['valueSummary.totalValidAbsoluteFrequency'],
          totalValidRelativeFrequency:
          jsonContent[i]['valueSummary.totalValidRelativeFrequency']
        }
      };
        CleanJSObjectService.removeEmptyJsonObjects(variableObj);
        variablesObjArray.push(new Variable(variableObj));
      }
    }catch (e) {
      console.log(e);
      JobLoggingService.cancel('' + e, {});
    }
    return variablesObjArray;
  };
  return {
      getVariables: getVariables
    };
});
<commit_msg>#393 changed fields names for variable detail filter<commit_after>/* global XLSX*/
'use strict';

angular.module('metadatamanagementApp').service('VariableBuilderService',
function(Variable, CleanJSObjectService, JobLoggingService) {
  var getVariables = function(data, dataAcquisitionProjectId) {
    var jsonContent = {};
    var variablesObjArray = [];
    try {
      var excelFile = data.files['variables.xlsx'];
      var content = XLSX.read(excelFile.asBinary(), {type: 'binary'});
      var sheetList = content.SheetNames;
      var worksheet = content.Sheets[sheetList[0]];
      // jscs:disable
      jsonContent = XLSX.utils.sheet_to_json(worksheet);
      // jscs:enable
      for (var i = 0; i < jsonContent.length; i++) {
        var variableObj = {
        id: jsonContent[i].id,
        atomicQuestionId: jsonContent[i].atomicQuestionId,
        accessWays: CleanJSObjectService.
        removeWhiteSpace(jsonContent[i].accessWays),
        dataAcquisitionProjectId: dataAcquisitionProjectId,
        dataType: {
          en: jsonContent[i]['dataType.en'],
          de: jsonContent[i]['dataType.de']
        },
        label: {
          en: jsonContent[i]['label.en'],
          de: jsonContent[i]['label.de']
        },
        description: {
          en: jsonContent[i]['description.en'],
          de: jsonContent[i]['description.de']
        },
        filterDetails: {
          expression:
          jsonContent[i]['filterDetails.expression'],
          description: {
            en: jsonContent[i]['filterDetails.description.de'],
            de: jsonContent[i]['filterDetails.description.en']
          },
          filterExpressionLanguage:
          jsonContent[i]['filterDetails.filterExpressionLanguage']
        },
        generationDetails: {
          rule: jsonContent[i]['generationDetails.rule'],
          ruleExpressionLanguage: jsonContent[i]
          ['generationDetails.ruleExpressionLanguage'],
          description: {
            en: jsonContent[i]['generationDetails.description.en'],
            de: jsonContent[i]['generationDetails.description.de']
          }
        },
        sameVariablesInPanel: CleanJSObjectService.
        removeWhiteSpace(jsonContent[i].sameVariablesInPanel),
        name: jsonContent[i].name,
        scaleLevel: {
          en: jsonContent[i]['scaleLevel.en'],
          de: jsonContent[i]['scaleLevel.de']
        },
        statistics: {
          firstQuartile: jsonContent[i]['statistics.firstQuartile'],
          highWhisker: jsonContent[i]['statistics.highWhisker'],
          kurtosis: jsonContent[i]['statistics.kurtosis'],
          lowWhisker: jsonContent[i]['statistics.lowWhisker'],
          maximum: jsonContent[i]['statistics.maximum'],
          meanValue: jsonContent[i]['statistics.meanValue'],
          median: jsonContent[i]['statistics.median'],
          minimum: jsonContent[i]['statistics.minimum'],
          skewness: jsonContent[i]['statistics.skewness'],
          standardDeviation: jsonContent[i]
          ['statistics.standardDeviation'],
          thirdQuartile: jsonContent[i]['statistics.thirdQuartile']
        },
        values: data.files['values/' + jsonContent[i].id + '.json'] ?
          JSON.parse(data.files['values/' + jsonContent[i].id + '.json']
          .asBinary()).values : undefined,
        surveyIds: CleanJSObjectService.
        removeWhiteSpace(jsonContent[i].surveyIds),
        conceptId: jsonContent[i].conceptId,
        dataSetIds: CleanJSObjectService.
        removeWhiteSpace(jsonContent[i].dataSetIds),
        valueSummary: {
          totalAbsoluteFrequency:
          jsonContent[i]['valueSummary.totalAbsoluteFrequency'],
          totalValidAbsoluteFrequency:
          jsonContent[i]['valueSummary.totalValidAbsoluteFrequency'],
          totalValidRelativeFrequency:
          jsonContent[i]['valueSummary.totalValidRelativeFrequency']
        }
      };
        CleanJSObjectService.removeEmptyJsonObjects(variableObj);
        variablesObjArray.push(new Variable(variableObj));
      }
    }catch (e) {
      console.log(e);
      JobLoggingService.cancel('' + e, {});
    }
    return variablesObjArray;
  };
  return {
      getVariables: getVariables
    };
});
<|endoftext|>


<commit_before>var semver = require('semver'),
    versions = require('../versions'),
    logger = require('../logger'),
    utils = require('../utils'),
    packages = require('../packages'),
    repository = require('../repository'),
    kansorc = require('../kansorc'),
    settings = require('../settings'),
    argParse = require('../args').parse,
    tar = require('../tar'),
    tree = require('../tree'),
    async = require('async'),
    path = require('path'),
    fs = require('fs');

/**
 * TODO: before installing from file, be sure to manually add an entry to the
 * version tree for that file otherwise when building the initial tree it might
 * complain if the file is not in the repositories.
 *
 * Can test this by packing vertest/packages/testpkg1, removing and trying to
 * install from the .tar.gz file
 *
 * TODO: review comments in tree module since the apis might have changed
 * slightly
 *
 * TODO: refactor this module now because it won't get done otherwise
 */

exports.summary = 'Installs a package and its dependencies';

exports.usage = '' +
'kanso install [PACKAGE]\n' +
'\n' +
'The PACKAGE argument can be one of the following: \n' +
'  kanso install (with no args in a package or project dir)\n' +
'  kanso install <tarball file>\n' +
'  kanso install <tarball url>\n' +
'  kanso install <folder>\n' +
'  kanso install <name>\n' +
//'  kanso install <name>@<tag>\n' +
'  kanso install <name>@<version>\n' +
'  kanso install <name>@<version range>\n' +
'\n' +
'Parameters:\n' +
'  PACKAGE    Package to install (defaults to ".")\n' +
'\n' +
'Options:\n' +
'  --force, -f    Overwrite existing packages in target directory\n' +
'  --repository   Source repository URL (otherwise uses settings in kansorc)\n' +
'  --package-dir  Output directory (defaults to "./packages")\n' +
'  --no-deps      Don\'t fetch dependencies for the package';

/**
 * Run function called when "kanso install" command is used
 *
 * @param {Object} settings - the values from .kansorc files
 * @param {Array} args - command-line arguments
 */

exports.run = function (settings, args) {
    var a = argParse(args, {
        'repository': {match: '--repository', value: true},
        'force': {match: ['-f', '--force']},
        'target_dir': {match: '--package-dir', value: true},
        'no_deps': {match: '--no-deps'}
    });

    var opt = a.options;
    var pkg = a.positional[0] || '.';

    opt.repositories = settings.repositories;
    if (a.options.repository) {
        opt.repositories = [a.options.repository];
        // don't allow package dir .kansorc file to overwrite repositories
        opt.fixed_repositories = true;
    }
    exports.install(pkg, opt, function (err) {
        if (err) {
            return logger.error(err);
        }
        logger.end();
    });
};

/**
 * Install a package from repository, file, directory or URL.
 *
 * @param {String} pkg - the package name, filename, directory or URL
 * @param {Object} opt - options such as target_dir and repositories
 * @param {Function} callback
 */

exports.install = function (pkg, opt, callback) {
    if (/^https?:\/\//.test(pkg)) {
        opt.target_dir = opt.target_dir || utils.abspath('packages');
        logger.info('installing from URL', pkg);
        return exports.installURL(pkg, opt, callback);
    }
    fs.stat(pkg, function (err, stats) {
        if (err) {
            // may not be a file
            opt.target_dir = opt.target_dir || utils.abspath('packages');
            logger.info('installing from repositories', pkg);
            return exports.installName(pkg, opt, callback);
        }
        if (stats.isDirectory()) {
            opt.target_dir = opt.target_dir || utils.abspath('packages', pkg);
            logger.info('installing from directory', pkg);
            return exports.installDir(pkg, opt, callback);
        }
        else if (stats.isFile()) {
            opt.target_dir = opt.target_dir || utils.abspath('packages');
            logger.info('installing from local file', pkg);
            return exports.installFile(pkg, opt, callback);
        }
        else {
            return callback(new Error('Unknown install target: ' + pkg));
        }
    });
};

// check packages already in local target_dir
exports.dirSource = function (target_dir) {
    return function (name, callback) {
        // TODO: also check package_paths (not just target_dir) for available
        // versions?
        packages.availableVersions([path.join(target_dir, name)], callback);
    };
};

exports.repoSource = function (repositories) {
    return function (name, callback) {
        logger.info('checking', name);
        repository.availableVersions(name, repositories, callback);
    };
};

/**
 * Install a dependencies for a package directory. Reads the .kansorc and
 * kanso.json files for that project and checks it's dependencies.
 *
 * @param {String} dir - the directory the install dependencies for
 * @param {Object} opt - the options object
 * @param {Function} callback
 */

exports.installDir = function (dir, opt, callback) {
    if (opt.no_deps) {
        return callback();
    }
    kansorc.loadFile(dir + '/.kansorc', function (err, _settings) {
        if (err) {
            return logger.error(err);
        }
        if (_settings.repositories && !opt.fixed_repositories) {
            // overwrite repository list with package directory's list
            opt.repositories = _settings.repositories;
        }
        settings.load(dir, function (err, cfg) {
            if (err) {
                return callback(err);
            }
            if (!cfg.dependencies) {
                logger.info('No dependencies specified');
                return callback();
            }
            var sources = [
                exports.dirSource(opt.target_dir),
                exports.repoSource(opt.repositories)
            ];
            var pkg = {config: cfg, source: 'root'}
            logger.info('Building version tree...');
            tree.build(pkg, sources, function (err, packages) {
                if (err) {
                    return callback(err);
                }
                exports.installTree(packages, opt, callback);
            });
        });
    });
};

exports.installTree = function (packages, opt, callback) {
    var names = Object.keys(packages);
    async.forEachLimit(names, 5, function (name, cb) {
        var curr = packages[name].current_version;
        if (packages[name].versions[curr].source === 'repository') {
            exports.installRepo(name, curr, opt, cb);
        }
        else if (packages[name].versions[curr].source === 'tmp') {
            var v = packages[name].versions[curr];
            logger.info('copying files', v.basename);
            exports.cpDir(name, curr, false, v.path, opt, cb);
        }
        else {
            process.nextTick(cb);
        }
    }, callback);
};

exports.installName = function (name, opt, callback) {
    var range = null;
    if (!range && name.indexOf('@') !== -1) {
        var parts = name.split('@');
        name = parts[0];
        range = parts.slice(1).join('@');
    }
    kansorc.loadFile('.kansorc', function (err, _settings) {
        if (err) {
            return logger.error(err);
        }
        if (_settings.repositories && !opt.fixed_repositories) {
            // overwrite repository list with package directory's list
            opt.repositories = _settings.repositories;
        }
        settings.load('.', function (err, cfg) {
            if (err) {
                return callback(err);
            }
            var sources1 = [
                // TODO: should this use other package_paths too?
                exports.dirSource(opt.target_dir),
                exports.repoSource(opt.repositories)
            ];
            var pkg1 = {
                config: cfg,
                source: 'root'
            };
            tree.build(pkg1, sources1, function (err, packages) {
                if (err) {
                    return callback(err);
                }
                var sources2 = [
                    // TODO: should this use other package_paths too?
                    exports.dirSource(opt.target_dir),
                    exports.repoSource(opt.repositories)
                ];
                tree.addDependency(
                    cfg.name, name, range, sources2, packages,
                    function (err, packages) {
                        if (err) {
                            return callback(err);
                        }
                        exports.installTree(packages, opt, callback);
                    }
                );
            });
        });
    });
};

exports.installRepo = function (name, range, opt, callback) {
    repository.fetch(name, range, opt.repositories,
        function (err, tfile, cdir, v, cfg, from_cache) {
            if (err) {
                return callback(err);
            }
            exports.cpDir(name, v, from_cache, cdir, opt, callback);
        }
    );
};

exports.cpDir = function (name, v, from_cache, cdir, opt, callback) {
    var p = opt.target_dir + '/' + name;
    function cp() {
        logger.info(
            'installing',
            name + '@' + v + (from_cache ? ' (cached)': '')
        );
        utils.ensureDir(opt.target_dir, function (err) {
            if (err) {
                return callback(err);
            }
            utils.cp('-r', cdir, p, function (err) {
                return callback(err);
            });
        });
    }
    path.exists(p, function (exists) {
        if (exists) {
            logger.info('removing', name);
            utils.rm('-rf', p, function (err) {
                if (err) {
                    return callback(err);
                }
                process.nextTick(function () {
                    cp();
                });
            });
        }
        else {
            cp();
        }
    });
};

exports.installFile = function (filename, opt, callback) {
    var tmp = repository.TMP_DIR + '/' + path.basename(filename);
    var tmp_extracted = repository.TMP_DIR + '/package';

    // clean up tmp dir after attempted install, even if error
    var _callback = callback;
    var callback = function (err) {
        var args = arguments;
        var that = this;
        utils.rm('-rf', [tmp, tmp_extracted], function (err2) {
            if (err2) {
                logger.error(err2);
            }
            _callback.apply(that, args);
        });
    };

    async.series({
        tmpdir: async.apply(utils.ensureDir, repository.TMP_DIR),
        dir: async.apply(utils.ensureDir, opt.target_dir),
        cp: function (cb) {
            if (filename === tmp) {
                // installing from a file in tmp already
                return cb();
            }
            utils.cp('-r', filename, tmp, cb);
        },
        extract: async.apply(tar.extract, tmp),
        cfg: async.apply(settings.load, tmp_extracted)
    },
    function (err, results) {
        if (err) {
            return callback(err);
        }
        var v = results.cfg.version;
        var name = results.cfg.name;

        kansorc.loadFile('.kansorc', function (err, _settings) {
            if (err) {
                return logger.error(err);
            }
            if (_settings.repositories && !opt.fixed_repositories) {
                // overwrite repository list with package directory's list
                opt.repositories = _settings.repositories;
            }
            settings.load('.', function (err, cfg) {
                if (err) {
                    return callback(err);
                }
                var sources = [
                    exports.dirSource(opt.target_dir),
                    exports.repoSource(opt.repositories)
                ];
                var packages = {};
                packages[name] = tree.createPackage([]);
                packages[name].current_version = results.cfg.version;
                packages[name].versions[results.cfg.version] = {
                    source: 'tmp',
                    path: tmp_extracted,
                    basename: path.basename(filename),
                    config: results.cfg
                };
                var root = {config: cfg, source: 'root'}
                tree.extend(root, sources, packages, function (err, packages) {
                    if (err) {
                        return callback(err);
                    }
                    exports.installTree(packages, opt, callback);
                });
            });
        });
    });
};
<commit_msg>don't pre-select version of new package when installing from file otherwise it's depenency requirements won't be taken into account<commit_after>var semver = require('semver'),
    versions = require('../versions'),
    logger = require('../logger'),
    utils = require('../utils'),
    packages = require('../packages'),
    repository = require('../repository'),
    kansorc = require('../kansorc'),
    settings = require('../settings'),
    argParse = require('../args').parse,
    tar = require('../tar'),
    tree = require('../tree'),
    async = require('async'),
    path = require('path'),
    fs = require('fs');

/**
 * TODO: before installing from file, be sure to manually add an entry to the
 * version tree for that file otherwise when building the initial tree it might
 * complain if the file is not in the repositories.
 *
 * Can test this by packing vertest/packages/testpkg1, removing and trying to
 * install from the .tar.gz file
 *
 * TODO: review comments in tree module since the apis might have changed
 * slightly
 *
 * TODO: refactor this module now because it won't get done otherwise
 */

exports.summary = 'Installs a package and its dependencies';

exports.usage = '' +
'kanso install [PACKAGE]\n' +
'\n' +
'The PACKAGE argument can be one of the following: \n' +
'  kanso install (with no args in a package or project dir)\n' +
'  kanso install <tarball file>\n' +
'  kanso install <tarball url>\n' +
'  kanso install <folder>\n' +
'  kanso install <name>\n' +
//'  kanso install <name>@<tag>\n' +
'  kanso install <name>@<version>\n' +
'  kanso install <name>@<version range>\n' +
'\n' +
'Parameters:\n' +
'  PACKAGE    Package to install (defaults to ".")\n' +
'\n' +
'Options:\n' +
'  --force, -f    Overwrite existing packages in target directory\n' +
'  --repository   Source repository URL (otherwise uses settings in kansorc)\n' +
'  --package-dir  Output directory (defaults to "./packages")\n' +
'  --no-deps      Don\'t fetch dependencies for the package';

/**
 * Run function called when "kanso install" command is used
 *
 * @param {Object} settings - the values from .kansorc files
 * @param {Array} args - command-line arguments
 */

exports.run = function (settings, args) {
    var a = argParse(args, {
        'repository': {match: '--repository', value: true},
        'force': {match: ['-f', '--force']},
        'target_dir': {match: '--package-dir', value: true},
        'no_deps': {match: '--no-deps'}
    });

    var opt = a.options;
    var pkg = a.positional[0] || '.';

    opt.repositories = settings.repositories;
    if (a.options.repository) {
        opt.repositories = [a.options.repository];
        // don't allow package dir .kansorc file to overwrite repositories
        opt.fixed_repositories = true;
    }
    exports.install(pkg, opt, function (err) {
        if (err) {
            return logger.error(err);
        }
        logger.end();
    });
};

/**
 * Install a package from repository, file, directory or URL.
 *
 * @param {String} pkg - the package name, filename, directory or URL
 * @param {Object} opt - options such as target_dir and repositories
 * @param {Function} callback
 */

exports.install = function (pkg, opt, callback) {
    if (/^https?:\/\//.test(pkg)) {
        opt.target_dir = opt.target_dir || utils.abspath('packages');
        logger.info('installing from URL', pkg);
        return exports.installURL(pkg, opt, callback);
    }
    fs.stat(pkg, function (err, stats) {
        if (err) {
            // may not be a file
            opt.target_dir = opt.target_dir || utils.abspath('packages');
            logger.info('installing from repositories', pkg);
            return exports.installName(pkg, opt, callback);
        }
        if (stats.isDirectory()) {
            opt.target_dir = opt.target_dir || utils.abspath('packages', pkg);
            logger.info('installing from directory', pkg);
            return exports.installDir(pkg, opt, callback);
        }
        else if (stats.isFile()) {
            opt.target_dir = opt.target_dir || utils.abspath('packages');
            logger.info('installing from local file', pkg);
            return exports.installFile(pkg, opt, callback);
        }
        else {
            return callback(new Error('Unknown install target: ' + pkg));
        }
    });
};

// check packages already in local target_dir
exports.dirSource = function (target_dir) {
    return function (name, callback) {
        // TODO: also check package_paths (not just target_dir) for available
        // versions?
        packages.availableVersions([path.join(target_dir, name)], callback);
    };
};

exports.repoSource = function (repositories) {
    return function (name, callback) {
        logger.info('checking', name);
        repository.availableVersions(name, repositories, callback);
    };
};

/**
 * Install a dependencies for a package directory. Reads the .kansorc and
 * kanso.json files for that project and checks it's dependencies.
 *
 * @param {String} dir - the directory the install dependencies for
 * @param {Object} opt - the options object
 * @param {Function} callback
 */

exports.installDir = function (dir, opt, callback) {
    if (opt.no_deps) {
        return callback();
    }
    kansorc.loadFile(dir + '/.kansorc', function (err, _settings) {
        if (err) {
            return logger.error(err);
        }
        if (_settings.repositories && !opt.fixed_repositories) {
            // overwrite repository list with package directory's list
            opt.repositories = _settings.repositories;
        }
        settings.load(dir, function (err, cfg) {
            if (err) {
                return callback(err);
            }
            if (!cfg.dependencies) {
                logger.info('No dependencies specified');
                return callback();
            }
            var sources = [
                exports.dirSource(opt.target_dir),
                exports.repoSource(opt.repositories)
            ];
            var pkg = {config: cfg, source: 'root'}
            logger.info('Building version tree...');
            tree.build(pkg, sources, function (err, packages) {
                if (err) {
                    return callback(err);
                }
                exports.installTree(packages, opt, callback);
            });
        });
    });
};

exports.installTree = function (packages, opt, callback) {
    var names = Object.keys(packages);
    async.forEachLimit(names, 5, function (name, cb) {
        var curr = packages[name].current_version;
        if (packages[name].versions[curr].source === 'repository') {
            exports.installRepo(name, curr, opt, cb);
        }
        else if (packages[name].versions[curr].source === 'tmp') {
            var v = packages[name].versions[curr];
            logger.info('copying files', v.basename);
            exports.cpDir(name, curr, false, v.path, opt, cb);
        }
        else {
            process.nextTick(cb);
        }
    }, callback);
};

exports.installName = function (name, opt, callback) {
    var range = null;
    if (!range && name.indexOf('@') !== -1) {
        var parts = name.split('@');
        name = parts[0];
        range = parts.slice(1).join('@');
    }
    kansorc.loadFile('.kansorc', function (err, _settings) {
        if (err) {
            return logger.error(err);
        }
        if (_settings.repositories && !opt.fixed_repositories) {
            // overwrite repository list with package directory's list
            opt.repositories = _settings.repositories;
        }
        settings.load('.', function (err, cfg) {
            if (err) {
                return callback(err);
            }
            var sources1 = [
                // TODO: should this use other package_paths too?
                exports.dirSource(opt.target_dir),
                exports.repoSource(opt.repositories)
            ];
            var pkg1 = {
                config: cfg,
                source: 'root'
            };
            logger.info('Building version tree...');
            tree.build(pkg1, sources1, function (err, packages) {
                if (err) {
                    return callback(err);
                }
                var sources2 = [
                    // TODO: should this use other package_paths too?
                    exports.dirSource(opt.target_dir),
                    exports.repoSource(opt.repositories)
                ];
                tree.addDependency(
                    cfg.name, name, range, sources2, packages,
                    function (err, packages) {
                        if (err) {
                            return callback(err);
                        }
                        exports.installTree(packages, opt, callback);
                    }
                );
            });
        });
    });
};

exports.installRepo = function (name, range, opt, callback) {
    repository.fetch(name, range, opt.repositories,
        function (err, tfile, cdir, v, cfg, from_cache) {
            if (err) {
                return callback(err);
            }
            exports.cpDir(name, v, from_cache, cdir, opt, callback);
        }
    );
};

exports.cpDir = function (name, v, from_cache, cdir, opt, callback) {
    var p = opt.target_dir + '/' + name;
    function cp() {
        logger.info(
            'installing',
            name + '@' + v + (from_cache ? ' (cached)': '')
        );
        utils.ensureDir(opt.target_dir, function (err) {
            if (err) {
                return callback(err);
            }
            utils.cp('-r', cdir, p, function (err) {
                return callback(err);
            });
        });
    }
    path.exists(p, function (exists) {
        if (exists) {
            logger.info('removing', name);
            utils.rm('-rf', p, function (err) {
                if (err) {
                    return callback(err);
                }
                process.nextTick(function () {
                    cp();
                });
            });
        }
        else {
            cp();
        }
    });
};

exports.installFile = function (filename, opt, callback) {
    var tmp = repository.TMP_DIR + '/' + path.basename(filename);
    var tmp_extracted = repository.TMP_DIR + '/package';

    // clean up tmp dir after attempted install, even if error
    var _callback = callback;
    var callback = function (err) {
        var args = arguments;
        var that = this;
        utils.rm('-rf', [tmp, tmp_extracted], function (err2) {
            if (err2) {
                logger.error(err2);
            }
            _callback.apply(that, args);
        });
    };

    async.series({
        tmpdir: async.apply(utils.ensureDir, repository.TMP_DIR),
        dir: async.apply(utils.ensureDir, opt.target_dir),
        cp: function (cb) {
            if (filename === tmp) {
                // installing from a file in tmp already
                return cb();
            }
            utils.cp('-r', filename, tmp, cb);
        },
        extract: async.apply(tar.extract, tmp),
        cfg: async.apply(settings.load, tmp_extracted)
    },
    function (err, results) {
        if (err) {
            return callback(err);
        }
        var v = results.cfg.version;
        var name = results.cfg.name;

        kansorc.loadFile('.kansorc', function (err, _settings) {
            if (err) {
                return logger.error(err);
            }
            if (_settings.repositories && !opt.fixed_repositories) {
                // overwrite repository list with package directory's list
                opt.repositories = _settings.repositories;
            }
            settings.load('.', function (err, cfg) {
                if (err) {
                    return callback(err);
                }
                var sources = [
                    exports.dirSource(opt.target_dir),
                    exports.repoSource(opt.repositories)
                ];
                var packages = {};
                packages[name] = tree.createPackage([]);
                packages[name].versions[results.cfg.version] = {
                    source: 'tmp',
                    path: tmp_extracted,
                    basename: path.basename(filename),
                    config: results.cfg
                };
                var root = {config: cfg, source: 'root'}
                logger.info('Building version tree...');
                tree.extend(root, sources, packages, function (err, packages) {
                    if (err) {
                        return callback(err);
                    }
                    exports.installTree(packages, opt, callback);
                });
            });
        });
    });
};
<|endoftext|>


<commit_before>import React from 'react';
import { createRoot } from 'react-dom';
import { createStore, applyMiddleware, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { parse as parseQS } from 'querystring';
import thunk from 'redux-thunk';
import Translator from '@u-wave/translate';
import webApiRequest from '../redux/request';
import readApplicationConfig from '../utils/readApplicationConfig';
import * as reducers from './reducers';
import { setResetKey } from './actions';
import PasswordResetApp from './containers/PasswordResetApp';
import english from '../../locale/en.yaml';
import './app.css';

const config = readApplicationConfig();
const key = document.querySelector('#reset-data').textContent;

const store = createStore(
  combineReducers(reducers),
  { config },
  applyMiddleware(
    thunk,
    webApiRequest(),
  ),
);

const qs = parseQS(window.location.search.slice(1));
store.dispatch(setResetKey(key || qs.key));

const translator = new Translator(english.uwave);

const root = createRoot(document.querySelector('#app'));
root.render((
  <Provider store={store}>
    <PasswordResetApp translator={translator} />
  </Provider>
));
<commit_msg>Use URLSearchParams<commit_after>import React from 'react';
import { createRoot } from 'react-dom';
import { createStore, applyMiddleware, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import Translator from '@u-wave/translate';
import webApiRequest from '../redux/request';
import readApplicationConfig from '../utils/readApplicationConfig';
import * as reducers from './reducers';
import { setResetKey } from './actions';
import PasswordResetApp from './containers/PasswordResetApp';
import english from '../../locale/en.yaml';
import './app.css';

const config = readApplicationConfig();
const key = document.querySelector('#reset-data').textContent;

const store = createStore(
  combineReducers(reducers),
  { config },
  applyMiddleware(
    thunk,
    webApiRequest(),
  ),
);

const qs = new URL(window.location.href).searchParams;
store.dispatch(setResetKey(key || qs.get('key')));

const translator = new Translator(english.uwave);

const root = createRoot(document.querySelector('#app'));
root.render((
  <Provider store={store}>
    <PasswordResetApp translator={translator} />
  </Provider>
));
<|endoftext|>


<commit_before>var request = require('request');
var moment = require('moment');

var debug = require('debug')('cli:reindex');
var config = require('../../config.json');
var talks = require('libtlks').talk;
var rank = require('librank').rank;

/**
 * Resets full-text search index
 * @param callback  function    function to execute after finished
 */
function resetIndex(callback) {
    // Delete index
    request({
        url: config.elasticsearch + "/tlksio",
        method: 'DELETE'
    }, function(err, response, body) {
        if (err) {
            throw new Error(err);
        }
        debug('Index deleted');
        // Create index
        request({
            url: config.elasticsearch + "/tlksio",
            method: 'PUT',
        }, function(err, response, body) {
            if (err) {
                throw new Error(err);
            }
            debug('Index created');
            callback();
        });
    });
}

/**
 * Index talk to elasticsearch
 * @param talk  object  talk object
 */
function indexTalk(talk) {
    var obj = {
        id: talk.id,
        slug: talk.slug,
        title: talk.title,
        description: talk.description,
        tags: talk.tags.join()
    };
    var url = config.elasticsearch + "/tlksio/talk/" + talk.id;
    request({
        url: url,
        method: 'PUT',
        json: obj
    }, function(err, response, body) {
        if (err) {
            throw new Error(err);
        }
        debug("Indexed:" + talk.title);
    });
}

exports.reindex = function() {
    // Reset index
    resetIndex(function(err) {
        if (err) {
            throw new Error(err);
        }
        // Get all talks
        talks.all(config.mongodb, function(err, docs) {
            if (err) {
                throw new Error(err);
            }
            // Index each talk
            docs.forEach(indexTalk);
        });
    });
};
<commit_msg>Fixed #1<commit_after>var request = require('request');
var moment = require('moment');

var debug = require('debug')('cli:reindex');
var config = require('../../config.json');
var talks = require('libtlks').talk;
var rank = require('librank').rank;

/**
 * Resets full-text search index
 * @param callback  function    function to execute after finished
 */
function resetIndex(callback) {
    // Delete index
    request({
        url: config.elasticsearch + "/tlksio",
        method: 'DELETE'
    }, function(err, response, body) {
        if (err) {
            throw new Error(err);
        }
        debug('Index deleted');
        // Create index
        request({
            url: config.elasticsearch + "/tlksio",
            method: 'PUT',
        }, function(err, response, body) {
            if (err) {
                throw new Error(err);
            }
            debug('Index created');
            callback();
        });
    });
}

/**
 * Index talk to elasticsearch
 * @param talk  object  talk object
 */
function indexTalk(talk) {
    talk.tags = talk.tags || [];
    var obj = {
        id: talk.id,
        slug: talk.slug,
        title: talk.title,
        description: talk.description,
        tags: talk.tags.join()
    };
    var url = config.elasticsearch + "/tlksio/talk/" + talk.id;
    request({
        url: url,
        method: 'PUT',
        json: obj
    }, function(err, response, body) {
        if (err) {
            throw new Error(err);
        }
        debug("Indexed:" + talk.title);
    });
}

exports.reindex = function() {
    // Reset index
    resetIndex(function(err) {
        if (err) {
            throw new Error(err);
        }
        // Get all talks
        talks.all(config.mongodb, function(err, docs) {
            if (err) {
                throw new Error(err);
            }
            // Index each talk
            docs.forEach(indexTalk);
        });
    });
};
<|endoftext|>


<commit_before>const Path = require('three-pathfinding');

const pathfinder = new Path();
const ZONE = 'level';

/**
 * nav
 *
 * Pathfinding system, using PatrolJS.
 */
module.exports = AFRAME.registerSystem('nav', {
  init: function () {
    this.navMesh = null;
    this.agents = new Set();
  },

  /**
   * @param {THREE.Mesh} mesh
   */
  setNavMesh: function (mesh) {
    const geometry = mesh.geometry.isBufferGeometry
      ? new THREE.Geometry().fromBufferGeometry(mesh.geometry)
      : mesh.geometry;
    this.navMesh = new THREE.Mesh(geometry);
    pathfinder.setZoneData(ZONE, Path.createZone(this.navMesh.geometry));
  },

  /**
   * @return {THREE.Mesh}
   */
  getNavMesh: function () {
    return this.navMesh;
  },

  /**
   * @param {NavAgent} ctrl
   */
  addAgent: function (ctrl) {
    this.agents.add(ctrl);
  },

  /**
   * @param {NavAgent} ctrl
   */
  removeAgent: function (ctrl) {
    this.agents.remove(ctrl);
  },

  /**
   * @param  {THREE.Vector3} start
   * @param  {THREE.Vector3} end
   * @param  {number} groupID
   * @return {Array<THREE.Vector3>}
   */
  getPath: function (start, end, groupID) {
    return pathfinder.findPath(start, end, ZONE, groupID);
  },

  /**
   * @param {THREE.Vector3} position
   * @return {number}
   */
  getGroup: function (position) {
    return pathfinder.getGroup(ZONE, position);
  },

  /**
   * @param  {THREE.Vector3} position
   * @param  {number} groupID
   * @return {Node}
   */
  getNode: function (position, groupID) {
    return pathfinder.getClosestNode(position, ZONE, groupID, true);
  },

  /**
   * @param  {THREE.Vector3} start Starting position.
   * @param  {THREE.Vector3} end Desired ending position.
   * @param  {number} groupID
   * @param  {Node} node
   * @param  {THREE.Vector3} endTarget (Output) Adjusted step end position.
   * @return {Node} Current node, after step is taken.
   */
  clampStep: function (start, end, groupID, node, endTarget) {
    if (!this.navMesh || !node) {
      endTarget.copy(end);
      return this.navMesh ? this.getNode(end, groupID) : null;
    }
    return pathfinder.clampStep(start, end, node, ZONE, groupID, endTarget);
  }
});
<commit_msg>[pathfinding] Fix typo in removeAgent().<commit_after>const Path = require('three-pathfinding');

const pathfinder = new Path();
const ZONE = 'level';

/**
 * nav
 *
 * Pathfinding system, using PatrolJS.
 */
module.exports = AFRAME.registerSystem('nav', {
  init: function () {
    this.navMesh = null;
    this.agents = new Set();
  },

  /**
   * @param {THREE.Mesh} mesh
   */
  setNavMesh: function (mesh) {
    const geometry = mesh.geometry.isBufferGeometry
      ? new THREE.Geometry().fromBufferGeometry(mesh.geometry)
      : mesh.geometry;
    this.navMesh = new THREE.Mesh(geometry);
    pathfinder.setZoneData(ZONE, Path.createZone(this.navMesh.geometry));
  },

  /**
   * @return {THREE.Mesh}
   */
  getNavMesh: function () {
    return this.navMesh;
  },

  /**
   * @param {NavAgent} ctrl
   */
  addAgent: function (ctrl) {
    this.agents.add(ctrl);
  },

  /**
   * @param {NavAgent} ctrl
   */
  removeAgent: function (ctrl) {
    this.agents.delete(ctrl);
  },

  /**
   * @param  {THREE.Vector3} start
   * @param  {THREE.Vector3} end
   * @param  {number} groupID
   * @return {Array<THREE.Vector3>}
   */
  getPath: function (start, end, groupID) {
    return pathfinder.findPath(start, end, ZONE, groupID);
  },

  /**
   * @param {THREE.Vector3} position
   * @return {number}
   */
  getGroup: function (position) {
    return pathfinder.getGroup(ZONE, position);
  },

  /**
   * @param  {THREE.Vector3} position
   * @param  {number} groupID
   * @return {Node}
   */
  getNode: function (position, groupID) {
    return pathfinder.getClosestNode(position, ZONE, groupID, true);
  },

  /**
   * @param  {THREE.Vector3} start Starting position.
   * @param  {THREE.Vector3} end Desired ending position.
   * @param  {number} groupID
   * @param  {Node} node
   * @param  {THREE.Vector3} endTarget (Output) Adjusted step end position.
   * @return {Node} Current node, after step is taken.
   */
  clampStep: function (start, end, groupID, node, endTarget) {
    if (!this.navMesh || !node) {
      endTarget.copy(end);
      return this.navMesh ? this.getNode(end, groupID) : null;
    }
    return pathfinder.clampStep(start, end, node, ZONE, groupID, endTarget);
  }
});
<|endoftext|>


<commit_before>// Copyright 2015, EMC, Inc.

'use strict';

module.exports = messengerFactory;

messengerFactory.$provide = 'Messenger';
messengerFactory.$inject = [
    'Constants',
    'Promise',
    'Assert',
    'Connection',
    'Message',
    'Subscription',
    '_',
    'Errors',
    'ErrorEvent',
    'Serializable',
    'shortid',
    'Timer',
    'Services.StatsD',
    '$injector'
];

function messengerFactory(
    Constants,
    Promise,
    assert,
    Connection,
    Message,
    Subscription,
    _,
    Errors,
    ErrorEvent,
    Serializable,
    shortid,
    Timer,
    statsd,
    injector
) {
    var queueOptions = {
        exclusive: true
    };

    var subscribeOptions = {
        exclusive: true
    };

   /**
     * validates data based on whether it is a serializable or not
     * @param  {Object|Serializable} data
     * @return {Promise}
     */
    function validate(data) {
        if (data instanceof Serializable) {
            return data.validate();
        } else {
            return Promise.resolve();
        }
    }

    /**
     * Generates a random queue name based on the name/routingKey that
     * the queue is going to be bound to.
     */
    function queueName(name, routingKey) {
        return '%s:%s:%s'.format(name, routingKey, shortid.generate());
    }

    function Messenger () {
        this.startupPriority = 1;
        this.initialConnection = false;
        this.subscriptions = {};
        this.timeout = 1000;
    }

    /**
     * Initializes an AMQP connection.
     *
     * @returns {Promise}
     */
    Messenger.prototype.start = function () {
        var self = this,
            configuration = injector.get('Services.Configuration'),
            uri = configuration.get('amqp', 'amqp://localhost');

        assert.ok(uri, 'uri');

        var options;

        if (typeof uri === 'string') {
            options = {
                url: uri
            };
        } else if (Array.isArray(uri)) {
            options = uri;
        } else {
            console.log('Setting AMQP URL to localhost');
            options = {
                url: 'amqp://localhost'
            };
        }

        var clientOptions = {
            reconnect: true,
            reconnectBackoffStrategy: 'linear',
            reconnectExponentialLimit: 120000,
            reconnectBackoffTime: 1000
        };

        this.transmit = new Connection (options, clientOptions, 'transmit');
        this.receive = new Connection(options, clientOptions, 'receive');

        return Promise.all([
            self.transmit.start(),
            self.receive.start()
        ]).then(function () {
            _.mapValues(Constants.Protocol.Exchanges, function (exchange) {
                self.receive.exchange(exchange.Name, exchange.Options);
                self.transmit.exchange(exchange.Name, exchange.Options);
            });
        })
        .then(function() {
            self.transmit.initialConnection = true;
            self.receive.initialConnection = true;
        })
        .catch(function(err) {
            // Console log this since the logger may fail without the messenger,
            // which itself is a seperate issue.
            // TODO: remove console.log when the above ^^ comment is fixed.
            console.log(err);
            throw err;
        });
    };

    /**
     * Stops and tears down an AMQP connection.
     */
    Messenger.prototype.stop = function () {
        var self = this;

        if (self.transmit && self.receive) {
            return Promise.all([
                self.transmit.stop(),
                self.receive.stop()
            ]);
        } else {
            return Promise.resolve();
        }
    };

    /**
     * Publishes the JSON serialized from 'data' into AMQP based on exchange and routingKey.
     *
     * @param {string} name
     * @param {string} routingKey
     * @param {Object} data
     * @param {Object} options TODO: Frey to say what options are valid here
     * @returns {Promise}
     */
    Messenger.prototype.publish = function (name, routingKey, data, options) {
        assert.string(name, 'name');
        assert.string(routingKey, 'routingKey');
        assert.object(data, 'data');

        if (_.isUndefined(this.transmit)) {
            return Promise.reject(new Error('Connection Not Established.'));
        }

        if (!_.isEmpty(name) && !_.has(this.transmit.exchanges, name)) {
            return Promise.reject(new Error(
                'Invalid Exchange Specified for Publish (%s:%s).'.format(name, routingKey)
            ));
        }

        var self = this;

        options = options || {};

        // This handles setup of the default publishing options.
        _.merge(options, {
            type: data.constructor.provides || 'Object'
        });

        // Validate, get the exchange, then publish.
        return validate(data).then(function () {
            return self.transmit.exchange(name).then(function (exchange) {
                // Publish is async, even with exchange confirm on the callback for it
                // doesn't seem to fire as documented so there isn't necessarily a reason
                // to use confirm mode.
                exchange.publish(routingKey, data, options);
            });
        });
    };

    /**
     * Attaches a subscription callback to a given exchange and routingKey
     * @param {string} exchange
     * @param {string} routingKey
     * @param {function({Message})} callback
     * @param {Object} type TODO: Frey to say how to use type
     * @returns {Promise}
     */
    Messenger.prototype.subscribe = function (name, routingKey, callback, type) {
        assert.string(name, 'name');
        assert.string(routingKey, 'routingKey');
        assert.func(callback, 'callback');

        var self = this;

        return new Promise(function (resolve, reject) {
            if (_.has(self.receive.exchanges, name)) {
                // Create an anonymous queue for the subscription.
                self.receive.queue(queueName(name, routingKey), queueOptions, function (q) {
                    // Bind the queue to the exchange and routing key as provided.
                    q.bind(name, routingKey, function () {
                        // Subscribe to the queue.
                        q.subscribe(subscribeOptions, function (data, headers, deliveryInfo) {
                            var message = new Message(data, headers, deliveryInfo);

                            // Validate the message and reject if it is a request object.
                            validate(message.data).then(function () {
                                // Check the configured type for the subscriber.
                                if (_.isFunction (type) && !(message.data instanceof type)) {
                                    throw new Error(
                                        'Invalid Request Type (%s:%s:%s).'.format(
                                            name,
                                            routingKey,
                                            type || 'Object'
                                        )
                                    );
                                }

                                callback(message.data, message);
                            }).catch(function (error) {
                                /* istanbul ignore else */
                                if (message.isRequest()) {
                                    message.reject(error);
                                }
                            });
                        }).addCallback(function (options) {
                            // This let's us know the subscription completed and we're able to
                            // resolve the subscription object.
                            resolve(new Subscription(q, options));
                        });
                    });
                });
            } else {
                reject(
                    new Error(
                        'Invalid Exchange Specified for Subscription (%s:%s:%s).'.format(
                            name,
                            routingKey,
                            type || 'Object'
                        )
                    )
                );
            }
        });
    };

    /**
     * Make a request, using data, over AMQP using exchange and routingKey and return
     * a promise that resolves on a response.
     *
     * @param {string} name
     * @param {string} routingKey
     * @param {Object} data
     * @param {Object} type The constructor of the expected type for the response.
     * @param {number} Override default messenger timeout
     * @returns {Promise}
     */
    Messenger.prototype.request = function (name, routingKey, data, type, timeout) {
        assert.string(name, 'name');
        assert.string(routingKey, 'routingKey');
        assert.object(data, 'data');

        var self = this,
            timer = new Timer();

        var context = {
            subscription: null,
            timeout: null,
            timeoutDuration: timeout,
            name: name,
            routingKey: routingKey,
            type: type,
            data: data,
            timer: timer,
            queue: null,
            resolve: null,
            reject: null,
        };

        return new Promise(function (resolve, reject) {
            context.resolve = resolve;
            context.reject = reject;
            self.receive.queue(
                queueName(name, routingKey + '.request'),
                queueOptions,
                function (q) {
                    context.queue = q;
                    q.subscribe(
                        subscribeOptions,
                        self.subscribeTimeout.bind(self, context)
                    )
                    .addCallback(self.subscribeCallback.bind(self, context));
                }
            );
        });
    };

   /* previously there had been a race condition where subscription.dispose
    *  would be called twice when there was a timeout. This function only
    *  executes when dispose has not already been called.
    */
    Messenger.prototype.safeSubscriptionDispose = function (context) {
        context.subscription && !context.subscription._disposed && context.subscription.dispose();
    };

    Messenger.prototype.subscribeTimeout = function(context, data, headers, deliveryInfo) {
        clearTimeout(context.timeout);

        this.safeSubscriptionDispose(context);

        statsd.timing(
            statsd.sanitize(
                'messenger.%s.%s'.format(
                    context.name,
                    context.routingKey
                )
            ),
            context.timer.stop()
        );

        var message = new Message(data, headers, deliveryInfo);

        if (message.data instanceof ErrorEvent) {
            return context.reject(message.data);
        } else {
            if (_.isFunction(context.type) && !(message.data instanceof context.type)) {
                return context.reject(
                   new Error(
                        'Invalid Response Type (%s:%s:%s).'.format(
                            context.name,
                            context.routingKey,
                            context.type || 'Object'
                        )
                    )
                );
            } else {
                return context.resolve(message.data);
            }
        }
    };

    Messenger.prototype.subscribeCallback = function(context, options) {
        var self = this;
        context.timeout = setTimeout(function () {
            clearTimeout(context.timeout);

            self.safeSubscriptionDispose(context);

            return context.reject (
                new Errors.RequestTimedOutError(
                    'Request Timed Out (%s:%s:%s).'.format(
                        context.name,
                        context.routingKey,
                        context.type || 'Object'
                    )
                )
            );
        }, context.timeoutDuration || self.timeout);

        context.subscription = Subscription.create(context.queue, options);

        context.timer.start();

        self.publish(context.name, context.routingKey, context.data, {
            replyTo: context.queue.name
        });
    };

    return Messenger;
}
<commit_msg>revert Lyne's PR #233<commit_after>// Copyright 2015, EMC, Inc.

'use strict';

module.exports = messengerFactory;

messengerFactory.$provide = 'Messenger';
messengerFactory.$inject = [
    'Constants',
    'Promise',
    'Assert',
    'Connection',
    'Message',
    'Subscription',
    '_',
    'Errors',
    'ErrorEvent',
    'Serializable',
    'shortid',
    'Timer',
    'Services.StatsD',
    '$injector'
];

function messengerFactory(
    Constants,
    Promise,
    assert,
    Connection,
    Message,
    Subscription,
    _,
    Errors,
    ErrorEvent,
    Serializable,
    shortid,
    Timer,
    statsd,
    injector
) {
    var queueOptions = {
        exclusive: true
    };

    var subscribeOptions = {
        exclusive: true
    };

   /**
     * validates data based on whether it is a serializable or not
     * @param  {Object|Serializable} data
     * @return {Promise}
     */
    function validate(data) {
        if (data instanceof Serializable) {
            return data.validate();
        } else {
            return Promise.resolve();
        }
    }

    /**
     * Generates a random queue name based on the name/routingKey that
     * the queue is going to be bound to.
     */
    function queueName(name, routingKey) {
        return '%s:%s:%s'.format(name, routingKey, shortid.generate());
    }

    function Messenger () {
        this.startupPriority = 1;
        this.initialConnection = false;
        this.subscriptions = {};
        this.timeout = 1000;
    }

    /**
     * Initializes an AMQP connection.
     *
     * @returns {Promise}
     */
    Messenger.prototype.start = function () {
        var self = this,
            configuration = injector.get('Services.Configuration'),
            uri = configuration.get('amqp', 'amqp://localhost');

        assert.ok(uri, 'uri');

        var options;

        if (typeof uri === 'string') {
            options = {
                url: uri
            };
        } else if (Array.isArray(uri)) {
            options = uri;
        } else {
            console.log('Setting AMQP URL to localhost');
            options = {
                url: 'amqp://localhost'
            };
        }

        var clientOptions = {
            reconnect: true,
            reconnectBackoffStrategy: 'linear',
            reconnectExponentialLimit: 120000,
            reconnectBackoffTime: 1000
        };

        this.transmit = new Connection (options, clientOptions, 'transmit');
        this.receive = new Connection(options, clientOptions, 'receive');

        return Promise.all([
            self.transmit.start(),
            self.receive.start()
        ]).then(function () {
            _.mapValues(Constants.Protocol.Exchanges, function (exchange) {
                self.receive.exchange(exchange.Name, exchange.Options);
                self.transmit.exchange(exchange.Name, exchange.Options);
            });
        })
        .then(function() {
            self.transmit.initialConnection = true;
            self.receive.initialConnection = true;
        })
        .catch(function(err) {
            // Console log this since the logger may fail without the messenger,
            // which itself is a seperate issue.
            // TODO: remove console.log when the above ^^ comment is fixed.
            console.log(err);
            throw err;
        });
    };

    /**
     * Stops and tears down an AMQP connection.
     */
    Messenger.prototype.stop = function () {
        var self = this;

        if (self.transmit && self.receive) {
            return Promise.all([
                self.transmit.stop(),
                self.receive.stop()
            ]);
        } else {
            return Promise.resolve();
        }
    };

    /**
     * Publishes the JSON serialized from 'data' into AMQP based on exchange and routingKey.
     *
     * @param {string} name
     * @param {string} routingKey
     * @param {Object} data
     * @param {Object} options TODO: Frey to say what options are valid here
     * @returns {Promise}
     */
    Messenger.prototype.publish = function (name, routingKey, data, options) {
        assert.string(name, 'name');
        assert.string(routingKey, 'routingKey');
        assert.object(data, 'data');

        if (_.isUndefined(this.transmit)) {
            return Promise.reject(new Error('Connection Not Established.'));
        }

        if (!_.isEmpty(name) && !_.has(this.transmit.exchanges, name)) {
            return Promise.reject(new Error(
                'Invalid Exchange Specified for Publish (%s:%s).'.format(name, routingKey)
            ));
        }

        var self = this;

        options = options || {};

        // This handles setup of the default publishing options.
        _.merge(options, {
            type: data.constructor.provides || 'Object'
        });

        // Validate, get the exchange, then publish.
        return validate(data).then(function () {
            return self.transmit.exchange(name).then(function (exchange) {
                // Publish is async, even with exchange confirm on the callback for it
                // doesn't seem to fire as documented so there isn't necessarily a reason
                // to use confirm mode.
                exchange.publish(routingKey, data, options);
            });
        });
    };

    /**
     * Attaches a subscription callback to a given exchange and routingKey
     * @param {string} exchange
     * @param {string} routingKey
     * @param {function({Message})} callback
     * @param {Object} type TODO: Frey to say how to use type
     * @returns {Promise}
     */
    Messenger.prototype.subscribe = function (name, routingKey, callback, type) {
        assert.string(name, 'name');
        assert.string(routingKey, 'routingKey');
        assert.func(callback, 'callback');

        var self = this;

        return new Promise(function (resolve, reject) {
            if (_.has(self.receive.exchanges, name)) {
                // Create an anonymous queue for the subscription.
                self.receive.queue(queueName(name, routingKey), queueOptions, function (q) {
                    // Bind the queue to the exchange and routing key as provided.
                    q.bind(name, routingKey, function () {
                        // Subscribe to the queue.
                        q.subscribe(subscribeOptions, function (data, headers, deliveryInfo) {
                            var message = new Message(data, headers, deliveryInfo);

                            // Validate the message and reject if it is a request object.
                            validate(message.data).then(function () {
                                // Check the configured type for the subscriber.
                                if (_.isFunction (type) && !(message.data instanceof type)) {
                                    throw new Error(
                                        'Invalid Request Type (%s:%s:%s).'.format(
                                            name,
                                            routingKey,
                                            type || 'Object'
                                        )
                                    );
                                }

                                callback(message.data, message);
                            }).catch(function (error) {
                                /* istanbul ignore else */
                                if (message.isRequest()) {
                                    message.reject(error);
                                }
                            });
                        }).addCallback(function (options) {
                            // This let's us know the subscription completed and we're able to
                            // resolve the subscription object.
                            resolve(new Subscription(q, options));
                        });
                    });
                });
            } else {
                reject(
                    new Error(
                        'Invalid Exchange Specified for Subscription (%s:%s:%s).'.format(
                            name,
                            routingKey,
                            type || 'Object'
                        )
                    )
                );
            }
        });
    };

    /**
     * Make a request, using data, over AMQP using exchange and routingKey and return
     * a promise that resolves on a response.
     *
     * @param {string} name
     * @param {string} routingKey
     * @param {Object} data
     * @param {Object} type The constructor of the expected type for the response.
     * @param {number} Override default messenger timeout
     * @returns {Promise}
     */
    Messenger.prototype.request = function (name, routingKey, data, type, timeout) {
        assert.string(name, 'name');
        assert.string(routingKey, 'routingKey');
        assert.object(data, 'data');

        var self = this,
            timer = new Timer();

        var context = {
            subscription: null,
            timeout: null,
            timeoutDuration: timeout,
            name: name,
            routingKey: routingKey,
            type: type,
            data: data,
            timer: timer,
            queue: null,
            resolve: null,
            reject: null,
        };

        return new Promise(function (resolve, reject) {
            context.resolve = resolve;
            context.reject = reject;
            self.receive.queue(queueName(name, routingKey), queueOptions, function (q) {
                context.queue = q;
                q.subscribe(
                    subscribeOptions,
                    self.subscribeTimeout.bind(self, context)
                )
               .addCallback(self.subscribeCallback.bind(self, context));
            });
        });
    };

   /* previously there had been a race condition where subscription.dispose
    *  would be called twice when there was a timeout. This function only
    *  executes when dispose has not already been called.
    */
    Messenger.prototype.safeSubscriptionDispose = function (context) {
        context.subscription && !context.subscription._disposed && context.subscription.dispose();
    };

    Messenger.prototype.subscribeTimeout = function(context, data, headers, deliveryInfo) {
        clearTimeout(context.timeout);

        this.safeSubscriptionDispose(context);

        statsd.timing(
            statsd.sanitize(
                'messenger.%s.%s'.format(
                    context.name,
                    context.routingKey
                )
            ),
            context.timer.stop()
        );

        var message = new Message(data, headers, deliveryInfo);

        if (message.data instanceof ErrorEvent) {
            return context.reject(message.data);
        } else {
            if (_.isFunction(context.type) && !(message.data instanceof context.type)) {
                return context.reject(
                   new Error(
                        'Invalid Response Type (%s:%s:%s).'.format(
                            context.name,
                            context.routingKey,
                            context.type || 'Object'
                        )
                    )
                );
            } else {
                return context.resolve(message.data);
            }
        }
    };

    Messenger.prototype.subscribeCallback = function(context, options) {
        var self = this;
        context.timeout = setTimeout(function () {
            clearTimeout(context.timeout);

            self.safeSubscriptionDispose(context);

            return context.reject (
                new Errors.RequestTimedOutError(
                    'Request Timed Out (%s:%s:%s).'.format(
                        context.name,
                        context.routingKey,
                        context.type || 'Object'
                    )
                )
            );
        }, context.timeoutDuration || self.timeout);

        context.subscription = Subscription.create(context.queue, options);

        context.timer.start();

        self.publish(context.name, context.routingKey, context.data, {
            replyTo: context.queue.name
        });
    };

    return Messenger;
}
<|endoftext|>


<commit_before>let { createNanoEvents } = require('nanoevents')
let { CrossTabClient } = require('@logux/client/cross-tab-client')
let { isFirstOlder } = require('@logux/core/is-first-older')
let { createStore } = require('redux')

function hackReducer (reducer) {
  return (state, action) => {
    if (action.type === 'logux/state') {
      return action.state
    } else {
      return reducer(state, action)
    }
  }
}

function createLoguxCreator (config = { }) {
  let cleanEvery = config.cleanEvery || 25
  delete config.cleanEvery
  let reasonlessHistory = config.reasonlessHistory || 1000
  delete config.reasonlessHistory
  let saveStateEvery = config.saveStateEvery || 50
  delete config.saveStateEvery
  let onMissedHistory = config.onMissedHistory
  delete config.onMissedHistory

  let client = new CrossTabClient(config)
  let log = client.log

  return function createLoguxStore (reducer, preloadedState, enhancer) {
    let store = createStore(hackReducer(reducer), preloadedState, enhancer)

    let emitter = createNanoEvents()

    store.client = client
    store.log = log
    let historyCleaned = false
    let stateHistory = { }

    let processing = { }

    let actionCount = 0
    function saveHistory (meta) {
      actionCount += 1
      if (saveStateEvery === 1 || actionCount % saveStateEvery === 1) {
        stateHistory[meta.id] = store.getState()
      }
    }

    let originReplace = store.replaceReducer
    store.replaceReducer = newReducer => {
      reducer = newReducer
      return originReplace(hackReducer(newReducer))
    }

    store.on = emitter.on.bind(emitter)

    let init
    store.initialize = new Promise(resolve => {
      init = resolve
    })

    let prevMeta
    let originDispatch = store.dispatch
    store.dispatch = action => {
      let meta = {
        id: log.generateId(),
        tab: store.client.tabId,
        reasons: ['timeTravelTab' + store.client.tabId],
        dispatch: true
      }
      log.add(action, meta)

      prevMeta = meta
      let prevState = store.getState()
      originDispatch(action)
      emitter.emit('change', store.getState(), prevState, action, meta)
      saveHistory(meta)
    }

    store.dispatch.local = (action, meta = { }) => {
      meta.tab = client.tabId
      if (meta.reasons || meta.keepLast) meta.noAutoReason = true
      return log.add(action, meta)
    }

    store.dispatch.crossTab = (action, meta = { }) => {
      if (meta.reasons || meta.keepLast) meta.noAutoReason = true
      return log.add(action, meta)
    }

    store.dispatch.sync = (action, meta = { }) => {
      if (meta.reasons || meta.keepLast) meta.noAutoReason = true

      meta.sync = true

      if (typeof meta.id === 'undefined') {
        meta.id = log.generateId()
      }

      return new Promise((resolve, reject) => {
        processing[meta.id] = [resolve, reject]
        log.add(action, meta)
      })
    }

    function replaceState (state, actions, pushHistory) {
      let last = actions[actions.length - 1][1]
      let newState = actions.reduceRight((prev, [action, id]) => {
        let changed = reducer(prev, action)
        if (pushHistory && id === last) {
          stateHistory[pushHistory] = changed
        } else if (stateHistory[id]) {
          stateHistory[id] = changed
        }
        return changed
      }, state)
      originDispatch({ type: 'logux/state', state: newState })
      return newState
    }

    let replaying
    function replay (actionId) {
      let ignore = { }
      let actions = []
      let replayed = false
      let newAction
      let collecting = true

      replaying = new Promise(resolve => {
        log.each((action, meta) => {
          if (meta.tab && meta.tab !== client.tabId) return true

          if (collecting || !stateHistory[meta.id]) {
            if (action.type === 'logux/undo') {
              ignore[action.id] = true
              return true
            } else if (action.type.startsWith('logux/')) {
              return true
            }

            if (!ignore[meta.id]) actions.push([action, meta.id])
            if (meta.id === actionId) {
              newAction = action
              collecting = false
            }

            return true
          } else {
            replayed = true
            replaceState(stateHistory[meta.id], actions)
            return false
          }
        }).then(() => {
          if (!replayed) {
            if (historyCleaned) {
              if (onMissedHistory) {
                onMissedHistory(newAction)
              }
              for (let i = actions.length - 1; i >= 0; i--) {
                let id = actions[i][1]
                if (stateHistory[id]) {
                  replayed = true
                  replaceState(
                    stateHistory[id],
                    actions.slice(0, i).concat([[newAction, actionId]]),
                    id
                  )
                  break
                }
              }
            }

            if (!replayed) {
              replaceState(preloadedState, actions.concat([
                [{ type: '@@redux/INIT' }]
              ]))
            }
          }

          replaying = false
          resolve()
        })
      })

      return replaying
    }

    log.on('preadd', (action, meta) => {
      let type = action.type
      let isLogux = type.startsWith('logux/')
      if (type === 'logux/undo') {
        meta.reasons.push('reasonsLoading')
      }
      if (!isLogux && !isFirstOlder(prevMeta, meta)) {
        meta.reasons.push('replay')
      }
      if (!isLogux && !meta.noAutoReason && !meta.dispatch) {
        meta.reasons.push('timeTravel')
      }
    })

    let wait = { }

    async function process (action, meta) {
      if (replaying) {
        wait[meta.id] = true
        await replaying
        if (wait[meta.id]) {
          delete wait[meta.id]
          await process(action, meta)
        }
        return
      }

      if (action.type === 'logux/undo') {
        let [undoAction, undoMeta] = await log.byId(action.id)
        if (undoAction) {
          log.changeMeta(meta.id, {
            reasons: undoMeta.reasons.filter(i => i !== 'syncing')
          })
          delete stateHistory[action.id]
          await replay(action.id)
        } else {
          await log.changeMeta(meta.id, { reasons: [] })
        }
        if (processing[action.id]) {
          let error = new Error(
            'Server undid Logux action because of ' + action.reason
          )
          error.action = action
          processing[action.id][1](error)
          delete processing[action.id]
        }
      } else if (!action.type.startsWith('logux/')) {
        if (isFirstOlder(prevMeta, meta)) {
          prevMeta = meta
          originDispatch(action)
          if (meta.added) saveHistory(meta)
        } else {
          await replay(meta.id)
          if (meta.reasons.includes('replay')) {
            log.changeMeta(meta.id, {
              reasons: meta.reasons.filter(i => i !== 'replay')
            })
          }
        }
      }
    }

    let lastAdded = 0
    let addCalls = 0
    client.on('add', (action, meta) => {
      if (meta.added > lastAdded) lastAdded = meta.added

      if (action.type === 'logux/processed') {
        if (processing[action.id]) {
          processing[action.id][0]()
          delete processing[action.id]
        }
      } else if (!meta.noAutoReason) {
        addCalls += 1
        if (addCalls % cleanEvery === 0 && lastAdded > reasonlessHistory) {
          historyCleaned = true
          log.removeReason('timeTravel', {
            maxAdded: lastAdded - reasonlessHistory
          })
          log.removeReason('timeTravelTab' + store.client.tabId, {
            maxAdded: lastAdded - reasonlessHistory
          })
        }
      }

      if (!meta.dispatch) {
        let prevState = store.getState()
        process(action, meta).then(() => {
          emitter.emit('change', store.getState(), prevState, action, meta)
        })
      }
    })

    client.on('clean', (action, meta) => {
      delete wait[meta.id]
      delete stateHistory[meta.id]
    })

    let previous = []
    let ignores = { }
    log.each((action, meta) => {
      if (!meta.tab) {
        if (action.type === 'logux/undo') {
          ignores[action.id] = true
        } else if (!ignores[meta.id]) {
          previous.push([action, meta])
        }
      }
    }).then(() => {
      if (previous.length > 0) {
        Promise.all(previous.map(i => process(...i))).then(init)
      } else {
        init()
      }
    })

    return store
  }
}

module.exports = { createLoguxCreator }
<commit_msg>Return the ClientMeta from commit.sync. (#23)<commit_after>let { createNanoEvents } = require('nanoevents')
let { CrossTabClient } = require('@logux/client/cross-tab-client')
let { isFirstOlder } = require('@logux/core/is-first-older')
let { createStore } = require('redux')

function hackReducer (reducer) {
  return (state, action) => {
    if (action.type === 'logux/state') {
      return action.state
    } else {
      return reducer(state, action)
    }
  }
}

function createLoguxCreator (config = { }) {
  let cleanEvery = config.cleanEvery || 25
  delete config.cleanEvery
  let reasonlessHistory = config.reasonlessHistory || 1000
  delete config.reasonlessHistory
  let saveStateEvery = config.saveStateEvery || 50
  delete config.saveStateEvery
  let onMissedHistory = config.onMissedHistory
  delete config.onMissedHistory

  let client = new CrossTabClient(config)
  let log = client.log

  return function createLoguxStore (reducer, preloadedState, enhancer) {
    let store = createStore(hackReducer(reducer), preloadedState, enhancer)

    let emitter = createNanoEvents()

    store.client = client
    store.log = log
    let historyCleaned = false
    let stateHistory = { }

    let processing = { }

    let actionCount = 0
    function saveHistory (meta) {
      actionCount += 1
      if (saveStateEvery === 1 || actionCount % saveStateEvery === 1) {
        stateHistory[meta.id] = store.getState()
      }
    }

    let originReplace = store.replaceReducer
    store.replaceReducer = newReducer => {
      reducer = newReducer
      return originReplace(hackReducer(newReducer))
    }

    store.on = emitter.on.bind(emitter)

    let init
    store.initialize = new Promise(resolve => {
      init = resolve
    })

    let prevMeta
    let originDispatch = store.dispatch
    store.dispatch = action => {
      let meta = {
        id: log.generateId(),
        tab: store.client.tabId,
        reasons: ['timeTravelTab' + store.client.tabId],
        dispatch: true
      }
      log.add(action, meta)

      prevMeta = meta
      let prevState = store.getState()
      originDispatch(action)
      emitter.emit('change', store.getState(), prevState, action, meta)
      saveHistory(meta)
    }

    store.dispatch.local = (action, meta = { }) => {
      meta.tab = client.tabId
      if (meta.reasons || meta.keepLast) meta.noAutoReason = true
      return log.add(action, meta)
    }

    store.dispatch.crossTab = (action, meta = { }) => {
      if (meta.reasons || meta.keepLast) meta.noAutoReason = true
      return log.add(action, meta)
    }

    store.dispatch.sync = (action, meta = { }) => {
      if (meta.reasons || meta.keepLast) meta.noAutoReason = true

      meta.sync = true

      if (typeof meta.id === 'undefined') {
        meta.id = log.generateId()
      }

      return new Promise((resolve, reject) => {
        processing[meta.id] = [resolve, reject]
        log.add(action, meta)
      })
    }

    function replaceState (state, actions, pushHistory) {
      let last = actions[actions.length - 1][1]
      let newState = actions.reduceRight((prev, [action, id]) => {
        let changed = reducer(prev, action)
        if (pushHistory && id === last) {
          stateHistory[pushHistory] = changed
        } else if (stateHistory[id]) {
          stateHistory[id] = changed
        }
        return changed
      }, state)
      originDispatch({ type: 'logux/state', state: newState })
      return newState
    }

    let replaying
    function replay (actionId) {
      let ignore = { }
      let actions = []
      let replayed = false
      let newAction
      let collecting = true

      replaying = new Promise(resolve => {
        log.each((action, meta) => {
          if (meta.tab && meta.tab !== client.tabId) return true

          if (collecting || !stateHistory[meta.id]) {
            if (action.type === 'logux/undo') {
              ignore[action.id] = true
              return true
            } else if (action.type.startsWith('logux/')) {
              return true
            }

            if (!ignore[meta.id]) actions.push([action, meta.id])
            if (meta.id === actionId) {
              newAction = action
              collecting = false
            }

            return true
          } else {
            replayed = true
            replaceState(stateHistory[meta.id], actions)
            return false
          }
        }).then(() => {
          if (!replayed) {
            if (historyCleaned) {
              if (onMissedHistory) {
                onMissedHistory(newAction)
              }
              for (let i = actions.length - 1; i >= 0; i--) {
                let id = actions[i][1]
                if (stateHistory[id]) {
                  replayed = true
                  replaceState(
                    stateHistory[id],
                    actions.slice(0, i).concat([[newAction, actionId]]),
                    id
                  )
                  break
                }
              }
            }

            if (!replayed) {
              replaceState(preloadedState, actions.concat([
                [{ type: '@@redux/INIT' }]
              ]))
            }
          }

          replaying = false
          resolve()
        })
      })

      return replaying
    }

    log.on('preadd', (action, meta) => {
      let type = action.type
      let isLogux = type.startsWith('logux/')
      if (type === 'logux/undo') {
        meta.reasons.push('reasonsLoading')
      }
      if (!isLogux && !isFirstOlder(prevMeta, meta)) {
        meta.reasons.push('replay')
      }
      if (!isLogux && !meta.noAutoReason && !meta.dispatch) {
        meta.reasons.push('timeTravel')
      }
    })

    let wait = { }

    async function process (action, meta) {
      if (replaying) {
        wait[meta.id] = true
        await replaying
        if (wait[meta.id]) {
          delete wait[meta.id]
          await process(action, meta)
        }
        return
      }

      if (action.type === 'logux/undo') {
        let [undoAction, undoMeta] = await log.byId(action.id)
        if (undoAction) {
          log.changeMeta(meta.id, {
            reasons: undoMeta.reasons.filter(i => i !== 'syncing')
          })
          delete stateHistory[action.id]
          await replay(action.id)
        } else {
          await log.changeMeta(meta.id, { reasons: [] })
        }
        if (processing[action.id]) {
          let error = new Error(
            'Server undid Logux action because of ' + action.reason
          )
          error.action = action
          processing[action.id][1](error)
          delete processing[action.id]
        }
      } else if (!action.type.startsWith('logux/')) {
        if (isFirstOlder(prevMeta, meta)) {
          prevMeta = meta
          originDispatch(action)
          if (meta.added) saveHistory(meta)
        } else {
          await replay(meta.id)
          if (meta.reasons.includes('replay')) {
            log.changeMeta(meta.id, {
              reasons: meta.reasons.filter(i => i !== 'replay')
            })
          }
        }
      }
    }

    let lastAdded = 0
    let addCalls = 0
    client.on('add', (action, meta) => {
      if (meta.added > lastAdded) lastAdded = meta.added

      if (action.type === 'logux/processed') {
        if (processing[action.id]) {
          processing[action.id][0](meta)
          delete processing[action.id]
        }
      } else if (!meta.noAutoReason) {
        addCalls += 1
        if (addCalls % cleanEvery === 0 && lastAdded > reasonlessHistory) {
          historyCleaned = true
          log.removeReason('timeTravel', {
            maxAdded: lastAdded - reasonlessHistory
          })
          log.removeReason('timeTravelTab' + store.client.tabId, {
            maxAdded: lastAdded - reasonlessHistory
          })
        }
      }

      if (!meta.dispatch) {
        let prevState = store.getState()
        process(action, meta).then(() => {
          emitter.emit('change', store.getState(), prevState, action, meta)
        })
      }
    })

    client.on('clean', (action, meta) => {
      delete wait[meta.id]
      delete stateHistory[meta.id]
    })

    let previous = []
    let ignores = { }
    log.each((action, meta) => {
      if (!meta.tab) {
        if (action.type === 'logux/undo') {
          ignores[action.id] = true
        } else if (!ignores[meta.id]) {
          previous.push([action, meta])
        }
      }
    }).then(() => {
      if (previous.length > 0) {
        Promise.all(previous.map(i => process(...i))).then(init)
      } else {
        init()
      }
    })

    return store
  }
}

module.exports = { createLoguxCreator }
<|endoftext|>