<commit_before>/**
 * Module dependencies
 */

var path = require('path'),
    fs = require('fs'),
    async = require('async'),
    install = require('./install'),
    utils = require('../utils'),
    rimraf = require('rimraf'),
    settings = require('../settings'),
    project = require('../project'),
    tree = require('../tree');
    logger = require('../logger'),
    argParse = require('../args').parse,
    _ = require('underscore/underscore')._;

/**
 * Usage information and docs
 */

exports.summary = 'Removes unused packages from the package directory';

exports.usage = '' +
'jam clean\n' +
'\n' +
'Options:\n' +
'  -d, --package-dir  Package directory (defaults to "PATH/jam")\n' +
'  -f, --force        Do not confirm package removal';

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

exports.run = function (settings, args) {
    var a = argParse(args, {
        'target_dir': {match: ['-d', '--package-dir'], value: true},
        'force': {match: ['-f', '--force']}
    });
    var opt = a.options;
    var cwd = process.cwd();

    opt.target_dir = opt.target_dir || settings.package_dir;
    exports.clean(cwd, opt, function (err) {
        if (err) {
            return logger.error(err);
        }
        logger.end();
    });
};

/**
 * Clean the project directory's dependencies.
 *
 * @param {Object} opt - the options object
 * @param {Function} callback
 */

exports.clean = function (cwd, opt, callback) {
    exports.unusedDirs(cwd, opt, function (err, dirs) {
        if (err) {
            return callback(err);
        }
        if (!dirs.length) {
            // nothing to remove
            return logger.end();
        }
        var reldirs = dirs.map(function (d) {
            return path.relative(opt.taget_dir, d);
        });

        if (opt.force) {
            exports.deleteDirs(dirs, callback);
        }
        else {
            console.log(
                '\n' +
                'The following directories are not required by packages in\n' +
                'package.json and will be REMOVED:\n\n' +
                '    ' + reldirs.join('\n    ') +
                '\n'
            );
            utils.getConfirmation('Continue', function (err, ok) {
                if (err) {
                    return callback(err);
                }
                if (ok) {
                    exports.deleteDirs(dirs, function (err) {
                        if (err) {
                            return callback(err);
                        }
                        project.updateRequireConfig(
                            opt.target_dir,
                            opt.baseurl,
                            callback
                        );
                    });
                }
                else {
                    logger.clean_exit = true;
                }
            });
        }
    });
};

/**
 * Delete multiple directory paths.
 *
 * @param {Array} dirs
 * @param {Function} callback
 */

exports.deleteDirs = function (dirs, callback) {
    async.forEach(dirs, function (d, cb) {
        logger.info('removing', path.basename(d));
        rimraf(d, cb);
    },
    callback);
};

/**
 * Discover package directories that do not form part of the current
 * package version tree.
 *
 * @param {Object} opt - the options object
 * @param {Function} callback
 */

exports.unusedDirs = function (cwd, opt, callback) {
    project.loadPackageJSON(cwd, function (err, cfg) {
        if (err) {
            return callback(err);
        }
        var sources = [
            install.dirSource(opt.target_dir)
        ];
        var newcfg = _.extend({name: '_root'}, cfg);
        var pkg = {
            config: newcfg,
            source: 'root'
        };
        logger.info('Building version tree...');
        tree.build(pkg, sources, function (err, packages) {
            if (err) {
                return callback(err);
            }
            return exports.unusedDirsTree(packages, opt, callback);
        });
    });
};

/**
 * Lists packages in the package dir and compares against the provided
 * version tree, returning the packages not in the tree.
 *
 * @param {Object} packages - version tree
 * @param {Object} opt - options object
 * @param {Function} callback
 */

exports.unusedDirsTree = function (packages, opt, callback) {
    utils.listDirs(opt.target_dir, function (err, dirs) {
        if (err) {
            return callback(err);
        }
        var unused = _.difference(dirs, Object.keys(packages));
        var unused = [];
        var names = Object.keys(packages);
        dirs.forEach(function (d) {
            if (!_.contains(names, path.basename(d))) {
                unused.push(d);
            }
        });
        return callback(null, unused);
    });
};
<commit_msg>update clean command to read values from package.json<commit_after>/**
 * Module dependencies
 */

var path = require('path'),
    fs = require('fs'),
    async = require('async'),
    install = require('./install'),
    utils = require('../utils'),
    rimraf = require('rimraf'),
    settings = require('../settings'),
    project = require('../project'),
    tree = require('../tree');
    logger = require('../logger'),
    argParse = require('../args').parse,
    _ = require('underscore/underscore')._;

/**
 * Usage information and docs
 */

exports.summary = 'Removes unused packages from the package directory';

exports.usage = '' +
'jam clean\n' +
'\n' +
'Options:\n' +
'  -d, --package-dir  Package directory (defaults to "PATH/jam")\n' +
'  -f, --force        Do not confirm package removal';

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

exports.run = function (settings, args) {
    var a = argParse(args, {
        'target_dir': {match: ['-d', '--package-dir'], value: true},
        'baseurl': {match: ['-b', '--baseurl'], value: true},
        'force': {match: ['-f', '--force']}
    });
    var opt = a.options;
    var cwd = process.cwd();

    install.initDir(settings, cwd, opt, function (err, opt, cfg, proj_dir) {
        if (err) {
            return logger.error(err);
        }

        if (!opt.target_dir) {
            if (cfg.jam && cfg.jam.packageDir) {
                opt.target_dir = path.resolve(proj_dir, cfg.jam.packageDir);
            }
            else {
                opt.target_dir = path.resolve(proj_dir, settings.package_dir);
            }
        }
        if (!opt.baseurl) {
            if (cfg.jam && cfg.jam.baseUrl) {
                opt.baseurl = path.resolve(proj_dir, cfg.jam.baseUrl);
            }
            else {
                opt.baseurl = path.resolve(proj_dir, settings.baseUrl);
            }
        }

        exports.clean(cwd, opt, function (err) {
            if (err) {
                return logger.error(err);
            }
            logger.end();
        });
    });
};

/**
 * Clean the project directory's dependencies.
 *
 * @param {Object} opt - the options object
 * @param {Function} callback
 */

exports.clean = function (cwd, opt, callback) {
    exports.unusedDirs(cwd, opt, function (err, dirs) {
        if (err) {
            return callback(err);
        }
        if (!dirs.length) {
            // nothing to remove
            return logger.end();
        }
        var reldirs = dirs.map(function (d) {
            return path.relative(opt.taget_dir, d);
        });

        if (opt.force) {
            exports.deleteDirs(dirs, callback);
        }
        else {
            console.log(
                '\n' +
                'The following directories are not required by packages in\n' +
                'package.json and will be REMOVED:\n\n' +
                '    ' + reldirs.join('\n    ') +
                '\n'
            );
            utils.getConfirmation('Continue', function (err, ok) {
                if (err) {
                    return callback(err);
                }
                if (ok) {
                    exports.deleteDirs(dirs, function (err) {
                        if (err) {
                            return callback(err);
                        }
                        project.updateRequireConfig(
                            opt.target_dir,
                            opt.baseurl,
                            callback
                        );
                    });
                }
                else {
                    logger.clean_exit = true;
                }
            });
        }
    });
};

/**
 * Delete multiple directory paths.
 *
 * @param {Array} dirs
 * @param {Function} callback
 */

exports.deleteDirs = function (dirs, callback) {
    async.forEach(dirs, function (d, cb) {
        logger.info('removing', path.basename(d));
        rimraf(d, cb);
    },
    callback);
};

/**
 * Discover package directories that do not form part of the current
 * package version tree.
 *
 * @param {Object} opt - the options object
 * @param {Function} callback
 */

exports.unusedDirs = function (cwd, opt, callback) {
    project.loadPackageJSON(cwd, function (err, cfg) {
        if (err) {
            return callback(err);
        }
        var sources = [
            install.dirSource(opt.target_dir)
        ];
        var newcfg = _.extend({name: '_root'}, cfg);
        var pkg = {
            config: newcfg,
            source: 'root'
        };
        logger.info('Building version tree...');
        tree.build(pkg, sources, function (err, packages) {
            if (err) {
                return callback(err);
            }
            return exports.unusedDirsTree(packages, opt, callback);
        });
    });
};

/**
 * Lists packages in the package dir and compares against the provided
 * version tree, returning the packages not in the tree.
 *
 * @param {Object} packages - version tree
 * @param {Object} opt - options object
 * @param {Function} callback
 */

exports.unusedDirsTree = function (packages, opt, callback) {
    utils.listDirs(opt.target_dir, function (err, dirs) {
        if (err) {
            return callback(err);
        }
        var unused = _.difference(dirs, Object.keys(packages));
        var unused = [];
        var names = Object.keys(packages);
        dirs.forEach(function (d) {
            if (!_.contains(names, path.basename(d))) {
                unused.push(d);
            }
        });
        return callback(null, unused);
    });
};
<|endoftext|>


<commit_before>'use strict';

var CdvBuildTask    = require('../tasks/cordova-build');
var HookTask        = require('../tasks/run-hook');
var ServeTask       = require('../tasks/ember-build-serve');
var Promise         = require('ember-cli/lib/ext/promise');
var PortFinder      = require('portfinder');
var chalk           = require('chalk');
var _merge          = require('lodash').merge;

var validateLocationType    = require('../utils/validate-location-type');
var getCordovaConfig        = require('../utils/get-cordova-config');
var validateAllowNavigation = require('../utils/validate-allow-navigation');

var getPort     = Promise.denodeify(PortFinder.getPort);
var defaultPort = process.env.PORT || 4200;

module.exports = {
  name: 'cordova:serve',
  aliases: [
    'cordova:serve',
    'cdv:serve',
    'cdv:s'
  ],
  description: 'Builds app, then runs liveReload server',
  works: 'insideProject',

  /* eslint-disable max-len */
  availableOptions: [
    { name: 'platform',             type: String,  default: 'ios' },
    { name: 'reload-url',           type: String,                          aliases: ['r'] },
    { name: 'verbose',              type: Boolean, default: false,         aliases: ['v'] },
    { name: 'port',                 type: Number,  default: defaultPort,   aliases: ['p'] },
    { name: 'host',                 type: String,                          aliases: ['H'],     description: 'Listens on all interfaces by default' },
    { name: 'proxy',                type: String,                          aliases: ['pr', 'pxy'] },
    { name: 'insecure-proxy',       type: Boolean, default: false,         aliases: ['inspr'], description: 'Set false to proxy self-signed SSL certificates' },
    { name: 'transparent-proxy',    type: Boolean, default: true,          aliases: ['transp'], description: 'Set to false to omit x-forwarded-* headers when proxying' },
    { name: 'watcher',              type: String,  default: 'events',      aliases: ['w'] },
    { name: 'live-reload',          type: Boolean, default: true,          aliases: ['lr'] },
    { name: 'live-reload-host',     type: String,                          aliases: ['lrh'],   description: 'Defaults to host' },
    { name: 'live-reload-base-url', type: String,                          aliases: ['lrbu'],  description: 'Defaults to baseURL' },
    { name: 'live-reload-port',     type: Number,                          aliases: ['lrp'],   description: '(Defaults to port number within [49152...65535])' },
    { name: 'environment',          type: String,  default: 'development', aliases: ['e', 'env', { 'dev': 'development' }, { 'prod': 'production' }] },
    { name: 'output-path',          type: 'Path',  default: 'ember-cordova/cordova/www/',       aliases: ['op', 'out'] },
    { name: 'ssl',                  type: Boolean, default: false },
    { name: 'ssl-key',              type: String,  default: 'ssl/server.key' },
    { name: 'ssl-cert',             type: String,  default: 'ssl/server.crt' }
  ],
  /* eslint-enable max-len */

  run: function(options) {
    var hook, watch, serve, cordovaBuild, validateCordovaConfig;

    validateLocationType(this.project.config());

    this.project.targetIsCordova = true;
    var platform = this.project.CORDOVA_PLATFORM = options.platform;
    this.project.RELOAD_PORT = options.port;

    validateCordovaConfig = getCordovaConfig(this.project)
    .then(function(cordovaConfig) {
      return validateAllowNavigation(
        cordovaConfig,
        true
      );
    });

    hook = new HookTask({
      project: this.project,
      ui: this.ui
    });

    cordovaBuild = new CdvBuildTask({
      project: this.project,
      ui: this.ui
    });

    serve = new ServeTask({
      project: this.project,
      ui: this.ui,
      analytics: this.analytics
    });

    return validateCordovaConfig
      .then(hook.prepare('beforeBuild'))
      .then(this._autoFindLiveReloadPort.bind(this, options))
      .then(function(serveOpts) {
        _merge(serveOpts, {
          baseURL: this.project.config().baseURL,
          project: this.project
        })

        return serve.run(serveOpts)
          .then(cordovaBuild.prepare(platform))
          .then(hook.prepare('afterBuild'))
          .then(function() {
            return new Promise(function() {
              // hang until the user exits.
            });
        }.bind(this))
      .catch(function(e) {
        throw e;
      });
    }.bind(this));
  },

  //Taken from from ember-cli
  //https://github.com/ember-cli/ember-cli/blob/master/lib/commands/serve.js#L97-L117
  _autoFindLiveReloadPort: function(commandOptions) {
    return getPort({ port: commandOptions.liveReloadPort, host: commandOptions.liveReloadHost })
      .then(function(foundPort) {

        // if live reload port matches express port, try one higher
        if (foundPort === commandOptions.port) {
          commandOptions.liveReloadPort = foundPort + 1;
          return this._autoFindLiveReloadPort(commandOptions);
        }

        // port was already open
        if (foundPort === commandOptions.liveReloadPort) {
          return commandOptions;
        }

        // use found port as live reload port
        commandOptions.liveReloadPort = foundPort;

        return commandOptions;
      });
  }.bind(this)
};
<commit_msg>fix(liveReload): default baseURL if it does not exist<commit_after>'use strict';

var CdvBuildTask    = require('../tasks/cordova-build');
var HookTask        = require('../tasks/run-hook');
var ServeTask       = require('../tasks/ember-build-serve');
var Promise         = require('ember-cli/lib/ext/promise');
var PortFinder      = require('portfinder');
var chalk           = require('chalk');
var _merge          = require('lodash').merge;

var validateLocationType    = require('../utils/validate-location-type');
var getCordovaConfig        = require('../utils/get-cordova-config');
var validateAllowNavigation = require('../utils/validate-allow-navigation');

var getPort     = Promise.denodeify(PortFinder.getPort);
var defaultPort = process.env.PORT || 4200;

module.exports = {
  name: 'cordova:serve',
  aliases: [
    'cordova:serve',
    'cdv:serve',
    'cdv:s'
  ],
  description: 'Builds app, then runs liveReload server',
  works: 'insideProject',

  /* eslint-disable max-len */
  availableOptions: [
    { name: 'platform',             type: String,  default: 'ios' },
    { name: 'reload-url',           type: String,                          aliases: ['r'] },
    { name: 'verbose',              type: Boolean, default: false,         aliases: ['v'] },
    { name: 'port',                 type: Number,  default: defaultPort,   aliases: ['p'] },
    { name: 'host',                 type: String,                          aliases: ['H'],     description: 'Listens on all interfaces by default' },
    { name: 'proxy',                type: String,                          aliases: ['pr', 'pxy'] },
    { name: 'insecure-proxy',       type: Boolean, default: false,         aliases: ['inspr'], description: 'Set false to proxy self-signed SSL certificates' },
    { name: 'transparent-proxy',    type: Boolean, default: true,          aliases: ['transp'], description: 'Set to false to omit x-forwarded-* headers when proxying' },
    { name: 'watcher',              type: String,  default: 'events',      aliases: ['w'] },
    { name: 'live-reload',          type: Boolean, default: true,          aliases: ['lr'] },
    { name: 'live-reload-host',     type: String,                          aliases: ['lrh'],   description: 'Defaults to host' },
    { name: 'live-reload-base-url', type: String,                          aliases: ['lrbu'],  description: 'Defaults to baseURL' },
    { name: 'live-reload-port',     type: Number,                          aliases: ['lrp'],   description: '(Defaults to port number within [49152...65535])' },
    { name: 'environment',          type: String,  default: 'development', aliases: ['e', 'env', { 'dev': 'development' }, { 'prod': 'production' }] },
    { name: 'output-path',          type: 'Path',  default: 'ember-cordova/cordova/www/',       aliases: ['op', 'out'] },
    { name: 'ssl',                  type: Boolean, default: false },
    { name: 'ssl-key',              type: String,  default: 'ssl/server.key' },
    { name: 'ssl-cert',             type: String,  default: 'ssl/server.crt' }
  ],
  /* eslint-enable max-len */

  run: function(options) {
    var hook, watch, serve, cordovaBuild, validateCordovaConfig;

    validateLocationType(this.project.config());

    this.project.targetIsCordova = true;
    var platform = this.project.CORDOVA_PLATFORM = options.platform;
    this.project.RELOAD_PORT = options.port;

    validateCordovaConfig = getCordovaConfig(this.project)
    .then(function(cordovaConfig) {
      return validateAllowNavigation(
        cordovaConfig,
        true
      );
    });

    hook = new HookTask({
      project: this.project,
      ui: this.ui
    });

    cordovaBuild = new CdvBuildTask({
      project: this.project,
      ui: this.ui
    });

    serve = new ServeTask({
      project: this.project,
      ui: this.ui,
      analytics: this.analytics
    });

    return validateCordovaConfig
      .then(hook.prepare('beforeBuild'))
      .then(this._autoFindLiveReloadPort.bind(this, options))
      .then(function(serveOpts) {
        var baseURL = this.project.config.baseURL;
        if (baseURL === undefined) baseURL = '/';

        _merge(serveOpts, {
          baseURL: this.project.config().baseURL,
          project: this.project
        })

        return serve.run(serveOpts)
          .then(cordovaBuild.prepare(platform))
          .then(hook.prepare('afterBuild'))
          .then(function() {
            return new Promise(function() {
              // hang until the user exits.
            });
        }.bind(this))
      .catch(function(e) {
        throw e;
      });
    }.bind(this));
  },

  //Taken from from ember-cli
  //https://github.com/ember-cli/ember-cli/blob/master/lib/commands/serve.js#L97-L117
  _autoFindLiveReloadPort: function(commandOptions) {
    return getPort({ port: commandOptions.liveReloadPort, host: commandOptions.liveReloadHost })
      .then(function(foundPort) {

        // if live reload port matches express port, try one higher
        if (foundPort === commandOptions.port) {
          commandOptions.liveReloadPort = foundPort + 1;
          return this._autoFindLiveReloadPort(commandOptions);
        }

        // port was already open
        if (foundPort === commandOptions.liveReloadPort) {
          return commandOptions;
        }

        // use found port as live reload port
        commandOptions.liveReloadPort = foundPort;

        return commandOptions;
      });
  }.bind(this)
};
<|endoftext|>


<commit_before>/*
 * setup.js: Titanium CLI setup command
 *
 * Copyright (c) 2012, Appcelerator, Inc.  All Rights Reserved.
 * See the LICENSE file for more information.
 */

var appc = require('node-appc'),
	afs = appc.fs,
	prompt = require('prompt'),
	async = require('async'),
	exec = require('child_process').exec,
	i18n = appc.i18n(__dirname),
	__ = i18n.__,
	__n = i18n.__n;

exports.desc = __('run the setup wizard');

exports.config = function (logger, config, cli) {
	return {
		noAuth: true,
		flags: {
			advanced: {
				abbr: 'a',
				desc: __('prompts for all configuration options')
			}
		}
	};
};

exports.run = function (logger, config, cli) {
	logger.log(__('Enter %s at any time to quit', 'ctrl-c'.cyan) + '\n');

	appc.ios.detect(function (env) {
		var validate = require('revalidator').validate,
			devNames = env && env.certs.devNames.map(function (name) {
				var m = name.match(/^([^(]+?)*/);
				return m && m[0].trim();
			}),
			distNames = env && env.certs.distNames.map(function (name) {
				var m = name.match(/^([^(]+?)*/);
				return m && m[0].trim();
			}),
			props = {
				'user.name': {
					default: config.user.name,
					description: __('What is your name?').bold + ' ' + __('(this is used as the default for the "author" field in the tiapp.xml or module manifest file when creating new projects)').grey,
					errorMsg: __('Invalid name'),
					conform: function (value) {
						return !!value.trim()
					}
				},
				'user.email': {
					default: config.user.email,
					description: __('What is your email address used for logging into the Appcelerator Network?').bold,
					errorMsg: __('Invalid e-mail address'),
					conform: function (value) {
						return !!value.trim()
					}
				},
				'user.locale': {
					default: config.user.locale,
					description: __('What would you like as your default locale?').bold + ' ' + __('(examples: "en", "de", "fr")').grey,
					errorMsg: __('Invalid locale'),
					conform: function (value) {
						return !!value.trim()
					}

				},
				'app.idprefix': {
					advanced: true,
					default: config.app.idprefix,
					description: __('What is your prefix for application IDs?').bold + ' ' + __('(example: com.mycompany)').grey
				},
				'app.publisher': {
					advanced: true,
					default: config.app.publisher,
					description: __('Used for populating the "publisher" field in new projects:').bold
				},
				'app.url': {
					advanced: true,
					default: config.app.url,
					description: __('Used for populating the "url" field in new projects:').bold
				},
				'app.sdk': {
					default: cli.env.getSDK(config.user.sdk).name,
					description: __('What Titanium SDK would you like to use by default?').bold,
					conform: function (value) {
						if (!cli.env.sdks[value]) {
							throw new appc.exception(__('Invalid Titanium SDK'));
						}
						return true;
					}
				},
				'app.workspace': {
					default: config.app.workspace,
					description: __('Path to your workspace where your projects should be created:').bold,
					conform: function (value) {
						if (!afs.exists(afs.resolvePath(value))) {
							throw new appc.exception(__('Invalid workspace directory'));
						}
						return true;
					}
				},
				'cli.colors': {
					advanced: true,
					default: !!config.cli.colors,
					description: __('Enable colors in the CLI?').bold,
					before: function (value) {
						return value === 'true';
					},
					conform: function (value) {
						if (!/^true|false$/.test(value)) {
							throw new appc.exception(__('Please specify %s or %s', 'true', 'false'));
						}
						return true;
					}
				},
				'cli.logLevel': {
					advanced: true,
					default: config.cli.logLevel || 'info',
					description: __('Default logging output level').bold,
					conform: function (value) {
						if (logger.getLevels().indexOf(value.toLowerCase()) == -1) {
							throw new appc.exception(
								__('Invalid log level'),
								[__('Available log levels:')].concat(logger.getLevels().map(function (level) {
									return '    ' + level.cyan;
								}))
							);
						}
						return true;
					}
				},
				'cli.prompt': {
					advanced: true,
					default: config.cli.hasOwnProperty('prompt') ? !!config.cli.prompt : true,
					description: __('Would you like to be prompted for missing options and arguments?').bold,
					before: function (value) {
						return value === 'true';
					},
					conform: function (value) {
						if (!/^true|false$/.test(value)) {
							throw new appc.exception(__('Please specify %s or %s', 'true', 'false'));
						}
						return true;
					}
				},
				'cli.failOnWrongSDK': {
					advanced: true,
					default: !!config.cli.failOnWrongSDK || false,
					description: __('Fail if trying to compile an app on different version in the tiapp.xml?').bold,
					before: function (value) {
						return value === 'true';
					},
					conform: function (value) {
						if (!/^true|false$/.test(value)) {
							throw new appc.exception(__('Please specify %s or %s', 'true', 'false'));
						}
						return true;
					}
				},
				'android.sdkPath': {
					default: config.android && config.android.sdkPath,
					description: __('Path to the Android SDK:').bold + ' ' + __('(this is needed for building Android apps)').grey,
					conform: function (value) {
						if (value && !afs.exists(afs.resolvePath(value))) {
							throw new appc.exception(__('Invalid Android SDK path'));
						}
						return true;
					}
				},
				'android.ndkPath': {
					advanced: true,
					default: config.android && config.android.ndkPath,
					description: __('Path to the Android NDK:').bold + ' ' + __('(this is needed for building native Titainum Modules for Android)').grey,
					conform: function (value) {
						if (value && !afs.exists(afs.resolvePath(value))) {
							throw new appc.exception(__('Invalid Android NDK path'));
						}
						return true;
					}
				},
				'ios.developerName': {
					advanced: true,
					default: config.ios && config.ios.developerName,
					description: __('What is the name of the iOS developer certificate you want to use by default?').bold
						+ ' ' + __('(this is used if you want to test on device)').grey,
					conform: function (name) {
						if (devNames.indexOf(name) == -1) {
							throw new appc.exception(__('Unable to find an iOS Developer Certificate for "%s"', name), [
								__('Available names: %s', devNames.map(function (d) { return ('"' + d + '"').cyan; }).join(', '))
							]);
						}
						return true;
					}
				},
				'ios.distributionName': {
					advanced: true,
					default: config.ios && config.ios.distributionName,
					description: __('What is the name of the iOS distribution certificate you want to use by default?').bold
						+ ' ' + __('(this is used if you want to distribute the app either through the App Store or Ad Hoc)').grey,
					conform: function (name) {
						if (distNames.indexOf(name) == -1) {
							throw new appc.exception(__('Unable to find an iOS Distribution Certificate for "%s"', name), [
								__('Available names: %s', distNames.map(function (d) { return ('"' + d + '"').cyan; }).join(', '))
							]);
						}
						return true;
					}
				}
			};

		// if we're not doing an advanced setup, then let's remove the advanced props now
		if (!cli.argv.advanced) {
			Object.keys(props).forEach(function (name) {
				if (props[name].advanced) {
					delete props[name];
				}
			});
		}

		// remove ios props if we're not on mac os x
		if (process.platform != 'darwin') {
			delete props['ios.developerName'];
			delete props['ios.distributionName'];
		}

		// overwrite prompt settings and render function
		prompt.colors = false;
		prompt.delimiter = prompt.message = '';
		prompt._performValidation = function (name, prop, against, schema, line, callback) {
			var result = { valid: false },
				msg,
				errorMsg = prop.schema.errorMsg;

			try {
				result = validate(against, schema);
			} catch (err) {
				if (err.type == 'AppcException') {
					logger.error(err.message);
					err.details.forEach(function (line) {
						logger.log(line);
					});
					return false;
				} else {
					return (line !== -1) ? callback(err) : false;
				}
			}

			if (!result.valid) {
				if (errorMsg) {
					logger.error(errorMsg);
				} else {
					msg = line !== -1 ? 'Invalid input for ' : 'Invalid command-line input for ';
					logger.error(msg + name.stripColors);
					prop.schema.message && logger.error(prop.schema.message);
				}

				prompt.emit('invalid', prop, line);
			}

			return result.valid;
		};

		prompt.start();
		prompt.get({
			properties: props
		}, function (err, results) {
			if (err) {
				logger.log('\n');
				process.exit(1);
			}

			Object.keys(results).forEach(function (key) {
				config.set(key, (results[key] || '').trim());
			});

			config.save();
			logger.log('\n' + __('Configuration saved') + '\n');
		});
	});
};
<commit_msg>[TIMOB-12003] Fixed iOS developer cert name validation to allow names with and without an ID.<commit_after>/*
 * setup.js: Titanium CLI setup command
 *
 * Copyright (c) 2012, Appcelerator, Inc.  All Rights Reserved.
 * See the LICENSE file for more information.
 */

var appc = require('node-appc'),
	afs = appc.fs,
	prompt = require('prompt'),
	async = require('async'),
	exec = require('child_process').exec,
	i18n = appc.i18n(__dirname),
	__ = i18n.__,
	__n = i18n.__n;

exports.desc = __('run the setup wizard');

exports.config = function (logger, config, cli) {
	return {
		noAuth: true,
		flags: {
			advanced: {
				abbr: 'a',
				desc: __('prompts for all configuration options')
			}
		}
	};
};

exports.run = function (logger, config, cli) {
	logger.log(__('Enter %s at any time to quit', 'ctrl-c'.cyan) + '\n');

	appc.ios.detect(function (env) {
		var validate = require('revalidator').validate,
			distNames = env && env.certs.distNames.map(function (name) {
				var m = name.match(/^([^(]+?)*/);
				return m && m[0].trim();
			}),
			props = {
				'user.name': {
					default: config.user.name,
					description: __('What is your name?').bold + ' ' + __('(this is used as the default for the "author" field in the tiapp.xml or module manifest file when creating new projects)').grey,
					errorMsg: __('Invalid name'),
					conform: function (value) {
						return !!value.trim()
					}
				},
				'user.email': {
					default: config.user.email,
					description: __('What is your email address used for logging into the Appcelerator Network?').bold,
					errorMsg: __('Invalid e-mail address'),
					conform: function (value) {
						return !!value.trim()
					}
				},
				'user.locale': {
					default: config.user.locale,
					description: __('What would you like as your default locale?').bold + ' ' + __('(examples: "en", "de", "fr")').grey,
					errorMsg: __('Invalid locale'),
					conform: function (value) {
						return !!value.trim()
					}

				},
				'app.idprefix': {
					advanced: true,
					default: config.app.idprefix,
					description: __('What is your prefix for application IDs?').bold + ' ' + __('(example: com.mycompany)').grey
				},
				'app.publisher': {
					advanced: true,
					default: config.app.publisher,
					description: __('Used for populating the "publisher" field in new projects:').bold
				},
				'app.url': {
					advanced: true,
					default: config.app.url,
					description: __('Used for populating the "url" field in new projects:').bold
				},
				'app.sdk': {
					default: cli.env.getSDK(config.user.sdk).name,
					description: __('What Titanium SDK would you like to use by default?').bold,
					conform: function (value) {
						if (!cli.env.sdks[value]) {
							throw new appc.exception(__('Invalid Titanium SDK'));
						}
						return true;
					}
				},
				'app.workspace': {
					default: config.app.workspace,
					description: __('Path to your workspace where your projects should be created:').bold,
					conform: function (value) {
						if (!afs.exists(afs.resolvePath(value))) {
							throw new appc.exception(__('Invalid workspace directory'));
						}
						return true;
					}
				},
				'cli.colors': {
					advanced: true,
					default: !!config.cli.colors,
					description: __('Enable colors in the CLI?').bold,
					before: function (value) {
						return value === 'true';
					},
					conform: function (value) {
						if (!/^true|false$/.test(value)) {
							throw new appc.exception(__('Please specify %s or %s', 'true', 'false'));
						}
						return true;
					}
				},
				'cli.logLevel': {
					advanced: true,
					default: config.cli.logLevel || 'info',
					description: __('Default logging output level').bold,
					conform: function (value) {
						if (logger.getLevels().indexOf(value.toLowerCase()) == -1) {
							throw new appc.exception(
								__('Invalid log level'),
								[__('Available log levels:')].concat(logger.getLevels().map(function (level) {
									return '    ' + level.cyan;
								}))
							);
						}
						return true;
					}
				},
				'cli.prompt': {
					advanced: true,
					default: config.cli.hasOwnProperty('prompt') ? !!config.cli.prompt : true,
					description: __('Would you like to be prompted for missing options and arguments?').bold,
					before: function (value) {
						return value === 'true';
					},
					conform: function (value) {
						if (!/^true|false$/.test(value)) {
							throw new appc.exception(__('Please specify %s or %s', 'true', 'false'));
						}
						return true;
					}
				},
				'cli.failOnWrongSDK': {
					advanced: true,
					default: !!config.cli.failOnWrongSDK || false,
					description: __('Fail if trying to compile an app on different version in the tiapp.xml?').bold,
					before: function (value) {
						return value === 'true';
					},
					conform: function (value) {
						if (!/^true|false$/.test(value)) {
							throw new appc.exception(__('Please specify %s or %s', 'true', 'false'));
						}
						return true;
					}
				},
				'android.sdkPath': {
					default: config.android && config.android.sdkPath,
					description: __('Path to the Android SDK:').bold + ' ' + __('(this is needed for building Android apps)').grey,
					conform: function (value) {
						if (value && !afs.exists(afs.resolvePath(value))) {
							throw new appc.exception(__('Invalid Android SDK path'));
						}
						return true;
					}
				},
				'android.ndkPath': {
					advanced: true,
					default: config.android && config.android.ndkPath,
					description: __('Path to the Android NDK:').bold + ' ' + __('(this is needed for building native Titainum Modules for Android)').grey,
					conform: function (value) {
						if (value && !afs.exists(afs.resolvePath(value))) {
							throw new appc.exception(__('Invalid Android NDK path'));
						}
						return true;
					}
				},
				'ios.developerName': {
					advanced: true,
					default: config.ios && config.ios.developerName,
					description: __('What is the name of the iOS developer certificate you want to use by default?').bold
						+ ' ' + __('(this is used if you want to test on device)').grey,
					conform: function (devname) {
						var devNames;

						if (env && devname) {
							var lowerCasedDevname = devname.trim().toLowerCase();

							if (/\([0-9A-Za-z]*\)$/.test(lowerCasedDevname)) {
								devNames = env.certs.devNames.map(function (name) {
									return name.trim().toLowerCase();
								});
							} else {
								devNames = env.certs.devNames.map(function (name) {
									var m = name.match(/^([^(]+?)*/);
									return (m ? m[0] : name).trim().toLowerCase();
								});
							}

							if (devNames.indexOf(lowerCasedDevname) == -1) {
								var width = 0,
									i = 0,
									l = env.certs.devNames.length,
									h = Math.ceil(l / 2),
									output = [__('Available names:')];

								for (; i < h; i++) {
									if (env.certs.devNames[i].length > width) {
										width = env.certs.devNames[i].length;
									}
									output.push('    ' + env.certs.devNames[i]);
								}

								width += 12; // 4 spaces left padding, 8 spaces between columns
								for (h = 1; i < l; h++, i++) {
									output[h] = appc.string.rpad(output[h], width) + env.certs.devNames[i];
								}

								throw new appc.exception(
									__('Unable to find an iOS Developer Certificate for "%s"', devname),
									output.map(function (s, i) { return i ? s.cyan : s; })
								);
							}
						}
						return true;
					}
				},
				'ios.distributionName': {
					advanced: true,
					default: config.ios && config.ios.distributionName,
					description: __('What is the name of the iOS distribution certificate you want to use by default?').bold
						+ ' ' + __('(this is used if you want to distribute the app either through the App Store or Ad Hoc)').grey,
					conform: function (name) {
						if (distNames.indexOf(name) == -1) {
							throw new appc.exception(__('Unable to find an iOS Distribution Certificate for "%s"', name), [
								__('Available names:')
							].concat(distNames.map(function (d) { return '    ' + d.cyan; })));
						}
						return true;
					}
				}
			};

		// if we're not doing an advanced setup, then let's remove the advanced props now
		if (!cli.argv.advanced) {
			Object.keys(props).forEach(function (name) {
				if (props[name].advanced) {
					delete props[name];
				}
			});
		}

		// remove ios props if we're not on mac os x
		if (process.platform != 'darwin' || !env || !env.certs.devNames.length) {
			delete props['ios.developerName'];
		}
		if (process.platform != 'darwin' || !env || !env.certs.distNames.length) {
			delete props['ios.distributionName'];
		}

		// overwrite prompt settings and render function
		prompt.colors = false;
		prompt.delimiter = prompt.message = '';
		prompt._performValidation = function (name, prop, against, schema, line, callback) {
			var result = { valid: false },
				msg,
				errorMsg = prop.schema.errorMsg;

			try {
				result = validate(against, schema);
			} catch (err) {
				if (err.type == 'AppcException') {
					logger.error(err.message);
					err.details.forEach(function (line) {
						logger.log(line);
					});
					return false;
				} else {
					return (line !== -1) ? callback(err) : false;
				}
			}

			if (!result.valid) {
				if (errorMsg) {
					logger.error(errorMsg);
				} else {
					msg = line !== -1 ? 'Invalid input for ' : 'Invalid command-line input for ';
					logger.error(msg + name.stripColors);
					prop.schema.message && logger.error(prop.schema.message);
				}

				prompt.emit('invalid', prop, line);
			}

			return result.valid;
		};

		prompt.start();
		prompt.get({
			properties: props
		}, function (err, results) {
			if (err) {
				logger.log('\n');
				process.exit(1);
			}

			Object.keys(results).forEach(function (key) {
				config.set(key, (results[key] || '').trim());
			});

			config.save();
			logger.log('\n' + __('Configuration saved') + '\n');
		});
	});
};
<|endoftext|>


<commit_before>import _ from 'lodash'
import { join, resolve } from 'path'
import { existsSync } from 'fs'
import { isUrl, isPureObject } from 'utils'

const Options = {}

export default Options

Options.from = function (_options) {
  // Clone options to prevent unwanted side-effects
  const options = Object.assign({}, _options)

  // Normalize options
  if (options.loading === true) {
    delete options.loading
  }
  if (options.router && typeof options.router.middleware === 'string') {
    options.router.middleware = [options.router.middleware]
  }
  if (options.router && typeof options.router.base === 'string') {
    options._routerBaseSpecified = true
  }
  if (typeof options.transition === 'string') {
    options.transition = { name: options.transition }
  }

  // Apply defaults
  _.defaultsDeep(options, Options.defaults)

  // Resolve dirs
  const hasValue = v => typeof v === 'string' && v
  options.rootDir = hasValue(options.rootDir) ? options.rootDir : process.cwd()
  options.srcDir = hasValue(options.srcDir) ? resolve(options.rootDir, options.srcDir) : options.rootDir
  options.modulesDir = resolve(options.rootDir, hasValue(options.modulesDir) ? options.modulesDir : 'node_modules')
  options.buildDir = join(options.rootDir, options.buildDir)

  // If app.html is defined, set the template path to the user template
  options.appTemplatePath = resolve(options.buildDir, 'views/app.template.html')
  if (existsSync(join(options.srcDir, 'app.html'))) {
    options.appTemplatePath = join(options.srcDir, 'app.html')
  }

  // Ignore publicPath on dev
  /* istanbul ignore if */
  if (options.dev && isUrl(options.build.publicPath)) {
    options.build.publicPath = Options.defaults.build.publicPath
  }

  // If store defined, update store options to true unless explicitly disabled
  if (options.store !== false && existsSync(join(options.srcDir, 'store'))) {
    options.store = true
  }

  // Normalize loadingIndicator
  if (!isPureObject(options.loadingIndicator)) {
    options.loadingIndicator = { name: options.loadingIndicator }
  }

  // Apply defaults to loadingIndicator
  options.loadingIndicator = Object.assign({
    name: 'circle',
    color: '#222',
    background: 'white'
  }, options.loadingIndicator)

  // Postcss
  // 1. Check if it is explicitly disabled by false value
  // ... Disable all postcss loaders
  // 2. Check if any standard source of postcss config exists
  // ... Make postcss = true letting loaders find this kind of config
  // 3. Else (Easy Usage)
  // ... Auto merge it with defaults
  if (options.build.postcss !== false) {
    // Detect postcss config existence
    // https://github.com/michael-ciniawsky/postcss-load-config
    let postcssConfigExists = false
    for (let dir of [options.srcDir, options.rootDir]) {
      for (let file of ['postcss.config.js', '.postcssrc.js', '.postcssrc', '.postcssrc.json', '.postcssrc.yaml']) {
        if (existsSync(resolve(dir, file))) {
          postcssConfigExists = true
          break
        }
      }
      if (postcssConfigExists) break
    }

    // Default postcss options
    if (postcssConfigExists) {
      options.build.postcss = true
    }

    // Normalize & Apply default plugins
    if (Array.isArray(options.build.postcss)) {
      options.build.postcss = { plugins: options.build.postcss }
    }
    if (isPureObject(options.build.postcss)) {
      options.build.postcss = Object.assign({
        sourceMap: options.build.cssSourceMap,
        plugins: {
          // https://github.com/postcss/postcss-import
          'postcss-import': {
            root: options.rootDir,
            path: [
              options.srcDir,
              options.rootDir,
              options.modulesDir
            ]
          },
          // https://github.com/postcss/postcss-url
          'postcss-url': {},
          // http://cssnext.io/postcss
          'postcss-cssnext': {}
        }
      }, options.build.postcss)
    }
  }

  // Debug errors
  if (options.debug === undefined) {
    options.debug = options.dev
  }

  // Resolve mode
  let mode = options.mode
  if (typeof mode === 'function') {
    mode = mode()
  }
  if (typeof mode === 'string') {
    mode = Options.modes[mode]
  }

  // Apply mode
  _.defaultsDeep(options, mode)

  return options
}

Options.modes = {
  universal: {
    build: {
      ssr: true
    },
    render: {
      ssr: true
    }
  },
  spa: {
    build: {
      ssr: false
    },
    render: {
      ssr: false
    }
  },
  static: {
    build: {
      ssr: true
    },
    render: {
      ssr: 'static'
    }
  }
}

Options.defaults = {
  mode: 'universal',
  dev: process.env.NODE_ENV !== 'production',
  debug: undefined, // Will be equal to dev if not provided
  buildDir: '.nuxt',
  nuxtAppDir: resolve(__dirname, '../lib/app/'), // Relative to dist
  build: {
    analyze: false,
    extractCSS: false,
    cssSourceMap: true,
    ssr: undefined,
    publicPath: '/_nuxt/',
    filenames: {
      css: 'common.[contenthash].css',
      manifest: 'manifest.[hash].js',
      vendor: 'common.[chunkhash].js',
      app: 'app.[chunkhash].js',
      chunk: '[name].[chunkhash].js'
    },
    vendor: [],
    plugins: [],
    babel: {},
    postcss: {},
    templates: [],
    watch: [],
    devMiddleware: {},
    hotMiddleware: {}
  },
  generate: {
    dir: 'dist',
    routes: [],
    concurrency: 500,
    interval: 0,
    minify: {
      collapseBooleanAttributes: true,
      collapseWhitespace: true,
      decodeEntities: true,
      minifyCSS: true,
      minifyJS: true,
      processConditionalComments: true,
      removeAttributeQuotes: false,
      removeComments: false,
      removeEmptyAttributes: true,
      removeOptionalTags: true,
      removeRedundantAttributes: true,
      removeScriptTypeAttributes: false,
      removeStyleLinkTypeAttributes: false,
      removeTagWhitespace: false,
      sortAttributes: true,
      sortClassName: false,
      trimCustomFragments: true,
      useShortDoctype: true
    }
  },
  env: {},
  head: {
    meta: [],
    link: [],
    style: [],
    script: []
  },
  plugins: [],
  css: [],
  modules: [],
  layouts: {},
  serverMiddleware: [],
  ErrorPage: null,
  loading: {
    color: 'black',
    failedColor: 'red',
    height: '2px',
    duration: 5000
  },
  loadingIndicator: {},
  transition: {
    name: 'page',
    mode: 'out-in'
  },
  router: {
    mode: 'history',
    base: '/',
    routes: [],
    middleware: [],
    linkActiveClass: 'nuxt-link-active',
    linkExactActiveClass: 'nuxt-link-exact-active',
    extendRoutes: null,
    scrollBehavior: null,
    fallback: false
  },
  render: {
    bundleRenderer: {},
    resourceHints: true,
    ssr: undefined,
    http2: {
      push: false
    },
    static: {},
    gzip: {
      threshold: 0
    },
    etag: {
      weak: true // Faster for responses > 5KB
    }
  },
  watchers: {
    webpack: {},
    chokidar: {}
  }
}
<commit_msg>Use Nuxt.js color by default<commit_after>import _ from 'lodash'
import { join, resolve } from 'path'
import { existsSync } from 'fs'
import { isUrl, isPureObject } from 'utils'

const Options = {}

export default Options

Options.from = function (_options) {
  // Clone options to prevent unwanted side-effects
  const options = Object.assign({}, _options)

  // Normalize options
  if (options.loading === true) {
    delete options.loading
  }
  if (options.router && typeof options.router.middleware === 'string') {
    options.router.middleware = [options.router.middleware]
  }
  if (options.router && typeof options.router.base === 'string') {
    options._routerBaseSpecified = true
  }
  if (typeof options.transition === 'string') {
    options.transition = { name: options.transition }
  }

  // Apply defaults
  _.defaultsDeep(options, Options.defaults)

  // Resolve dirs
  const hasValue = v => typeof v === 'string' && v
  options.rootDir = hasValue(options.rootDir) ? options.rootDir : process.cwd()
  options.srcDir = hasValue(options.srcDir) ? resolve(options.rootDir, options.srcDir) : options.rootDir
  options.modulesDir = resolve(options.rootDir, hasValue(options.modulesDir) ? options.modulesDir : 'node_modules')
  options.buildDir = join(options.rootDir, options.buildDir)

  // If app.html is defined, set the template path to the user template
  options.appTemplatePath = resolve(options.buildDir, 'views/app.template.html')
  if (existsSync(join(options.srcDir, 'app.html'))) {
    options.appTemplatePath = join(options.srcDir, 'app.html')
  }

  // Ignore publicPath on dev
  /* istanbul ignore if */
  if (options.dev && isUrl(options.build.publicPath)) {
    options.build.publicPath = Options.defaults.build.publicPath
  }

  // If store defined, update store options to true unless explicitly disabled
  if (options.store !== false && existsSync(join(options.srcDir, 'store'))) {
    options.store = true
  }

  // Normalize loadingIndicator
  if (!isPureObject(options.loadingIndicator)) {
    options.loadingIndicator = { name: options.loadingIndicator }
  }

  // Apply defaults to loadingIndicator
  options.loadingIndicator = Object.assign({
    name: 'circle',
    color: '#3B8070',
    background: 'white'
  }, options.loadingIndicator)

  // Postcss
  // 1. Check if it is explicitly disabled by false value
  // ... Disable all postcss loaders
  // 2. Check if any standard source of postcss config exists
  // ... Make postcss = true letting loaders find this kind of config
  // 3. Else (Easy Usage)
  // ... Auto merge it with defaults
  if (options.build.postcss !== false) {
    // Detect postcss config existence
    // https://github.com/michael-ciniawsky/postcss-load-config
    let postcssConfigExists = false
    for (let dir of [options.srcDir, options.rootDir]) {
      for (let file of ['postcss.config.js', '.postcssrc.js', '.postcssrc', '.postcssrc.json', '.postcssrc.yaml']) {
        if (existsSync(resolve(dir, file))) {
          postcssConfigExists = true
          break
        }
      }
      if (postcssConfigExists) break
    }

    // Default postcss options
    if (postcssConfigExists) {
      options.build.postcss = true
    }

    // Normalize & Apply default plugins
    if (Array.isArray(options.build.postcss)) {
      options.build.postcss = { plugins: options.build.postcss }
    }
    if (isPureObject(options.build.postcss)) {
      options.build.postcss = Object.assign({
        sourceMap: options.build.cssSourceMap,
        plugins: {
          // https://github.com/postcss/postcss-import
          'postcss-import': {
            root: options.rootDir,
            path: [
              options.srcDir,
              options.rootDir,
              options.modulesDir
            ]
          },
          // https://github.com/postcss/postcss-url
          'postcss-url': {},
          // http://cssnext.io/postcss
          'postcss-cssnext': {}
        }
      }, options.build.postcss)
    }
  }

  // Debug errors
  if (options.debug === undefined) {
    options.debug = options.dev
  }

  // Resolve mode
  let mode = options.mode
  if (typeof mode === 'function') {
    mode = mode()
  }
  if (typeof mode === 'string') {
    mode = Options.modes[mode]
  }

  // Apply mode
  _.defaultsDeep(options, mode)

  return options
}

Options.modes = {
  universal: {
    build: {
      ssr: true
    },
    render: {
      ssr: true
    }
  },
  spa: {
    build: {
      ssr: false
    },
    render: {
      ssr: false
    }
  },
  static: {
    build: {
      ssr: true
    },
    render: {
      ssr: 'static'
    }
  }
}

Options.defaults = {
  mode: 'universal',
  dev: process.env.NODE_ENV !== 'production',
  debug: undefined, // Will be equal to dev if not provided
  buildDir: '.nuxt',
  nuxtAppDir: resolve(__dirname, '../lib/app/'), // Relative to dist
  build: {
    analyze: false,
    extractCSS: false,
    cssSourceMap: true,
    ssr: undefined,
    publicPath: '/_nuxt/',
    filenames: {
      css: 'common.[contenthash].css',
      manifest: 'manifest.[hash].js',
      vendor: 'common.[chunkhash].js',
      app: 'app.[chunkhash].js',
      chunk: '[name].[chunkhash].js'
    },
    vendor: [],
    plugins: [],
    babel: {},
    postcss: {},
    templates: [],
    watch: [],
    devMiddleware: {},
    hotMiddleware: {}
  },
  generate: {
    dir: 'dist',
    routes: [],
    concurrency: 500,
    interval: 0,
    minify: {
      collapseBooleanAttributes: true,
      collapseWhitespace: true,
      decodeEntities: true,
      minifyCSS: true,
      minifyJS: true,
      processConditionalComments: true,
      removeAttributeQuotes: false,
      removeComments: false,
      removeEmptyAttributes: true,
      removeOptionalTags: true,
      removeRedundantAttributes: true,
      removeScriptTypeAttributes: false,
      removeStyleLinkTypeAttributes: false,
      removeTagWhitespace: false,
      sortAttributes: true,
      sortClassName: false,
      trimCustomFragments: true,
      useShortDoctype: true
    }
  },
  env: {},
  head: {
    meta: [],
    link: [],
    style: [],
    script: []
  },
  plugins: [],
  css: [],
  modules: [],
  layouts: {},
  serverMiddleware: [],
  ErrorPage: null,
  loading: {
    color: 'black',
    failedColor: 'red',
    height: '2px',
    duration: 5000
  },
  loadingIndicator: {},
  transition: {
    name: 'page',
    mode: 'out-in'
  },
  router: {
    mode: 'history',
    base: '/',
    routes: [],
    middleware: [],
    linkActiveClass: 'nuxt-link-active',
    linkExactActiveClass: 'nuxt-link-exact-active',
    extendRoutes: null,
    scrollBehavior: null,
    fallback: false
  },
  render: {
    bundleRenderer: {},
    resourceHints: true,
    ssr: undefined,
    http2: {
      push: false
    },
    static: {},
    gzip: {
      threshold: 0
    },
    etag: {
      weak: true // Faster for responses > 5KB
    }
  },
  watchers: {
    webpack: {},
    chokidar: {}
  }
}
<|endoftext|>


<commit_before>function Ant(a_board) {
    this.row(5);
    this.column(5);
    this.direction('up');
    this.board(a_board);
}

accessor(Ant, "row");
accessor(Ant, "column");
accessor(Ant, "direction");
accessor(Ant, "board");

Ant.prototype.direction_table= {
    up:    {turn_left: 'left',  turn_right: 'right', row_increment: -1, column_increment: 0},
    left:  {turn_left: 'down',  turn_right: 'up',    row_increment:  0, column_increment: -1},
    down:  {turn_left: 'right', turn_right: 'left',  row_increment:  1, column_increment: 0},
    right: {turn_left: 'up',    turn_right: 'down',  row_increment:  0, column_increment: 1}
};

Ant.prototype.color_table= {
    'black': {flipped_color: 'white', turn_direction: 'turn_right'},
    'white': {flipped_color: 'black', turn_direction: 'turn_left'},
};

Ant.prototype.color_table_lookup= function() {
    return this.color_table[this.color()];
};

Ant.prototype.direction_table_lookup= function() {
    return this.direction_table[this.direction()];
}

Ant.prototype.new_direction= function() {
    var turn_direction= this.color_table_lookup().turn_direction;
    return this.direction_table_lookup()[turn_direction];
};

Ant.prototype.flipped_color= function() {
    return this.color_table_lookup().flipped_color;
};

Ant.prototype.row_increment= function() {
    return this.direction_table_lookup().row_increment;
};

Ant.prototype.column_increment= function() {
    return this.direction_table_lookup().column_increment;
};

Ant.prototype.color= function(new_value) {
    return this.board().cell_color(this.row(), this.column(), new_value);
};

Ant.prototype.flip_color= function() {
    this.color(this.flipped_color());
};

Ant.prototype.move_forward= function() {
    this.row(this.row() + this.row_increment());
    this.column(this.column() + this.column_increment());
};

Ant.prototype.turn= function() {
    this.direction(this.new_direction());
};

Ant.prototype.on_board= function() {
    return this.board() &&
	this.column() >= 0 && this.column() < this.board().width() &&
	this.row() >= 0 && this.row() < this.board().height();
};

Ant.prototype.step= function() {
    if (!this.on_board())
	return;

    this.flip_color();
    this.turn();
    this.move_forward();
};
<commit_msg>First try at making specs pass.<commit_after>function Ant(a_board) {
    this.row(5);
    this.column(5);
    this.direction('up');
    this.board(a_board);
}

accessor(Ant, "row");
accessor(Ant, "column");
accessor(Ant, "direction");
accessor(Ant, "board");

Ant.prototype.direction_table= {
    up:    {turn_left: 'left',  turn_right: 'right', row_increment: -1, column_increment: 0},
    left:  {turn_left: 'down',  turn_right: 'up',    row_increment:  0, column_increment: -1},
    down:  {turn_left: 'right', turn_right: 'left',  row_increment:  1, column_increment: 0},
    right: {turn_left: 'up',    turn_right: 'down',  row_increment:  0, column_increment: 1}
};

Ant.prototype.color_table= {
    'black': {flipped_color: 'white', turn_direction: 'turn_right'},
    'white': {flipped_color: 'black', turn_direction: 'turn_left'},
};

Ant.prototype.color_table_lookup= function() {
    return this.color_table[this.color()];
};

Ant.prototype.direction_table_lookup= function() {
    return this.direction_table[this.direction()];
}

Ant.prototype.new_direction= function() {
    var turn_direction= this.color_table_lookup().turn_direction;
    return this.direction_table_lookup()[turn_direction];
};

Ant.prototype.flipped_color= function() {
    return this.color_table_lookup().flipped_color;
};

Ant.prototype.row_increment= function() {
    return this.direction_table_lookup().row_increment;
};

Ant.prototype.column_increment= function() {
    return this.direction_table_lookup().column_increment;
};

Ant.prototype.color= function(new_value) {
    return this.board().cell_color(this.row(), this.column(), new_value);
};

Ant.prototype.flip_color= function() {
    this.color(this.flipped_color());
};

Ant.prototype.move_forward= function() {
    this.row(this.row() + this.row_increment());
    this.row(this.row() % this.board().height());
    this.column(this.column() + this.column_increment());
    this.column(this.column() % this.board().width());
};

Ant.prototype.turn= function() {
    this.direction(this.new_direction());
};

Ant.prototype.on_board= function() {
    return this.board() &&
	this.column() >= 0 && this.column() < this.board().width() &&
	this.row() >= 0 && this.row() < this.board().height();
};

Ant.prototype.step= function() {
    if (!this.on_board())
	return;

    this.flip_color();
    this.turn();
    this.move_forward();
};
<|endoftext|>


<commit_before>'use strict';

var http = require('http'),
    semver = require('semver'),
    pkg = require('../../package.json');

var getCurrentPackageVersion = function () {
  return pkg.version;
};

var getCurrentPackageName = function () {
  return pkg.name;
};

var getNpmPackageLatestVersion = function (packageName, callback) {
  http.get('http://registry.npmjs.org/' + packageName + '/latest', function (res) {
    var data = '';

    res.on('data', function (chunk) {
      data += chunk;
    });

    res.on('end', function () {
      try {
        var packageJson = JSON.parse(data);
        callback(undefined, packageJson.version);
      } catch (err) {
        callback(err);
      }
    });
  }).on('error', function (err) {
    callback(err);
  });
};

var checkForUpdate = function (callback) {
  var name = getCurrentPackageName();
  getNpmPackageLatestVersion(name, function (err, latestVersion) {
    if (err) {
      return callback && callback(err);
    }

    var currentVersion = getCurrentPackageVersion();
    callback && callback(undefined, semver.lt(currentVersion, latestVersion) ? latestVersion : undefined);
  });
};

module.exports = {
  getCurrentPackageName : getCurrentPackageName,
  getCurrentPackageVersion: getCurrentPackageVersion,
  getNpmPackageLatestVersion: getNpmPackageLatestVersion,
  checkForUpdate : checkForUpdate
};
<commit_msg>Fixed jshint warning<commit_after>'use strict';

var http = require('http'),
    semver = require('semver'),
    pkg = require('../../package.json');

var getCurrentPackageVersion = function () {
  return pkg.version;
};

var getCurrentPackageName = function () {
  return pkg.name;
};

var getNpmPackageLatestVersion = function (packageName, callback) {
  http.get('http://registry.npmjs.org/' + packageName + '/latest', function (res) {
    var data = '';

    res.on('data', function (chunk) {
      data += chunk;
    });

    res.on('end', function () {
      try {
        var packageJson = JSON.parse(data);
        callback(undefined, packageJson.version);
      } catch (err) {
        callback(err);
      }
    });
  }).on('error', function (err) {
    callback(err);
  });
};

var checkForUpdate = function (callback) {
  var name = getCurrentPackageName();
  getNpmPackageLatestVersion(name, function (err, latestVersion) {
    if (err) {
      return callback && callback(err);
    }

    var currentVersion = getCurrentPackageVersion();
    return callback && callback(undefined, semver.lt(currentVersion, latestVersion) ? latestVersion : undefined);
  });
};

module.exports = {
  getCurrentPackageName : getCurrentPackageName,
  getCurrentPackageVersion: getCurrentPackageVersion,
  getNpmPackageLatestVersion: getNpmPackageLatestVersion,
  checkForUpdate : checkForUpdate
};
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of iotagent-ul
 *
 * iotagent-ul is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * iotagent-ul is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with iotagent-ul.
 * If not, seehttp://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::[iot_support@tid.es]
 *
 * Modified by: Fernando Méndez, Daniel Calvo - ATOS Research & Innovation
 */

/* eslint-disable no-prototype-builtins */

const iotAgentLib = require('iotagent-node-lib');
const regenerateTransid = iotAgentLib.regenerateTransid;
const config = require('./configService');
const transportSelector = require('./transportSelector');
const intoTrans = iotAgentLib.intoTrans;
const finishSouthBoundTransaction = iotAgentLib.finishSouthBoundTransaction;
const fillService = iotAgentLib.fillService;
const _ = require('underscore');
const utils = require('./iotaUtils');
const async = require('async');
const ulParser = require('./ulParser');
const constants = require('./constants');
let context = {
    op: 'IOTAUL.Common.Binding'
};

/**
 * Find the attribute given by its name between all the active attributes of the given device, returning its type, or
 * null otherwise.
 *
 * @param {String} attribute        Name of the attribute to find.
 * @param {Object} device           Device object containing all the information about a device.
 * @return {String}                 String identifier of the attribute type.
 */
function guessType(attribute, device) {
    for (let i = 0; i < device.active.length; i++) {
        if (device.active[i].name === attribute) {
            return device.active[i].type;
        }
    }

    if (attribute === constants.TIMESTAMP_ATTRIBUTE) {
        return constants.TIMESTAMP_TYPE_NGSI2;
    }
    return constants.DEFAULT_ATTRIBUTE_TYPE;
}

function sendConfigurationToDevice(device, apiKey, deviceId, results, callback) {
    transportSelector.applyFunctionFromBinding(
        [apiKey, deviceId, results],
        'sendConfigurationToDevice',
        device.transport,
        callback
    );
}

/**
 * Deals with configuration requests coming from the device. Whenever a new configuration requests arrives with a list
 * of attributes to retrieve, this handler asks the Context Broker for the values of those attributes, and publish a
 * new message in the "/1234/MQTT_2/configuration/values" topic
 *
 * @param {String} apiKey           API Key corresponding to the Devices configuration.
 * @param {String} deviceId         Id of the device to be updated.
 * @param {Object} device           Device object containing all the information about a device.
 * @param {Object} objMessage          JSON object received.
 */
function manageConfigurationRequest(apiKey, deviceId, device, objMessage) {
    utils.manageConfiguration(
        apiKey,
        deviceId,
        device,
        objMessage,
        async.apply(sendConfigurationToDevice, device),
        function (error) {
            if (error) {
                iotAgentLib.alarms.raise(constants.MQTTB_ALARM, error);
            } else {
                iotAgentLib.alarms.release(constants.MQTTB_ALARM);
                config
                    .getLogger()
                    .debug(context, 'Configuration request finished for APIKey [%s] and Device [%s]', apiKey, deviceId);
            }
            finishSouthBoundTransaction(null);
        }
    );
}

/**
 * Utility function used to reduce UL Payload group arrays and process them to update their value in the Context Broker.
 * This function process a new element of the payload group, generating a function ready to be called with a callback
 * in a async.series() call.
 *
 * @param {Object} device       Object containing all the information about the device sending the measures.
 * @param {String} apikey       APIKey of the service the device belongs to.
 * @param {Array} previous      Array of prepared functions that send information to the Context Broker.
 * @param {Object} current      Information sent by the device.
 * @param {Number} index        Index of the group in the array.
 * @return {Array}             Updated array of functions.
 */

/* eslint-disable-next-line no-unused-vars */
function processMeasureGroup(device, apikey, previous, current, index) {
    const values = [];
    if (current.command) {
        previous.push(
            iotAgentLib.setCommandResult.bind(
                null,
                device.name,
                config.getConfig().iota.defaultResource,
                apikey,
                current.command,
                current.value,
                constants.COMMAND_STATUS_COMPLETED,
                device
            )
        );
    } else {
        for (const k in current) {
            if (current.hasOwnProperty(k)) {
                values.push({
                    name: k,
                    type: guessType(k, device),
                    value: current[k]
                });
            }
        }

        previous.push(iotAgentLib.update.bind(null, device.name, device.type, '', values, device));
    }

    return previous;
}

/**
 * Adds multiple measures to the Context Broker. Multiple measures come in the form of single-level JSON objects,
 * whose keys are the attribute names and whose values are the attribute values.
 *
 * @param {String} apiKey           API Key corresponding to the Devices configuration.
 * @param {Object} device           Device object containing all the information about a device.
 * @param {String} message          UL payload.
 */
function multipleMeasures(apiKey, device, message) {
    let updates = [];
    const messageStr = message.toString();
    let parsedMessage;

    config.getLogger().debug('Processing multiple measures for device [%s] with apiKey [%s]', device.id, apiKey);

    try {
        parsedMessage = ulParser.parse(messageStr);
    } catch (e) {
        config.getLogger().error(context, 'MEASURES-003: Parse error parsing incoming message [%]', messageStr);
        return;
    }

    updates = parsedMessage.reduce(processMeasureGroup.bind(null, device, apiKey), []);

    async.series(updates, function (error) {
        if (error) {
            config.getLogger().error(
                context,
                /*jshint quotmark: double */
                " MEASURES-002: Couldn't send the updated values to the Context Broker due to an error: %j",
                /*jshint quotmark: single */
                error
            );
        } else {
            // prettier-ignore
            config.getLogger().info(
                context,
                'Multiple measures for device [%s] with apiKey [%s] successfully updated',
                device.id,
                apiKey
            );
        }
        finishSouthBoundTransaction(null);
    });
}

/**
 * Adds a single measure to the context broker. The message for single measures contains the direct value to
 * be inserted in the attribute, given by its name.
 *
 * @param {String} apiKey           API Key corresponding to the Devices configuration.
 * @param {String} attribute        Name of the attribute to update.
 * @param {Object} device           Device object containing all the information about a device.
 * @param {Buffer} message          Raw message coming from the client.
 */
function singleMeasure(apiKey, attribute, device, message) {
    config.getLogger().debug('Processing single measure for device [%s] with apiKey [%s]', device.id, apiKey);

    const values = [
        {
            name: attribute,
            type: guessType(attribute, device),
            value: message.toString()
        }
    ];

    iotAgentLib.update(device.name, device.type, '', values, device, function (error) {
        if (error) {
            config.getLogger().error(
                context,
                /*jshint quotmark: double */
                " MEASURES-002: Couldn't send the updated values to the Context Broker due to an error: %j",
                /*jshint quotmark: single */
                error
            );
        } else {
            // prettier-ignore
            config.getLogger().debug(
                context,
                'Single measure for device [%s] with apiKey [%s] successfully updated',
                device.id,
                apiKey
            );
        }
        finishSouthBoundTransaction(null);
    });
}

/**
 * Handles an incoming message, extracting the API Key, device Id and attribute to update (in the case of single
 * measures) from the topic.
 *
 * @param {String} topic        Topic of the form: '/<APIKey>/deviceId/attributes[/<attributeName>]'.
 * @param {Object} message      message body (Object or Buffer, depending on the value).
 */
function messageHandler(topic, message, protocol) {
    if (topic[0] !== '/') {
        topic = '/' + topic;
    }
    const topicInformation = topic.split('/');
    let parsedMessage;

    if (topicInformation[1].toLowerCase() === 'ul') {
        topicInformation.splice(1, 1);
    }
    const apiKey = topicInformation[1];
    const deviceId = topicInformation[2];
    const messageStr = message.toString();

    function processMessageForDevice(device, apiKey, topicInformation) {
        iotAgentLib.alarms.release(constants.MQTTB_ALARM);

        if (
            topicInformation[3] === constants.CONFIGURATION_SUFIX &&
            topicInformation[4] === constants.CONFIGURATION_COMMAND_SUFIX &&
            message
        ) {
            parsedMessage = ulParser.parseConfigurationRequest(messageStr);
            manageConfigurationRequest(apiKey, deviceId, device, parsedMessage);
        } else if (topicInformation[3] === constants.CONFIGURATION_COMMAND_UPDATE) {
            const commandObj = ulParser.result(message.toString());
            utils.updateCommand(
                apiKey,
                device,
                commandObj.result,
                commandObj.command,
                constants.COMMAND_STATUS_COMPLETED,
                function (error) {
                    config.getLogger().debug('Command updated with result: %s', error);
                }
            );
        } else if (topicInformation[4]) {
            singleMeasure(apiKey, topicInformation[4], device, message);
        } else if (topicInformation[3] === constants.MEASURES_SUFIX) {
            multipleMeasures(apiKey, device, message.toString());
        } else {
            config.getLogger().error(
                context,
                /*jshint quotmark: double */
                "MEASURES-004: Couldn't process message [%s] due to format issues.",
                /*jshint quotmark: single */
                message
            );
        }
    }

    function processDeviceMeasure(error, device) {
        if (error) {
            context = fillService(context, { service: 'n/a', subservice: 'n/a' });
            config.getLogger().warn(context, 'MEASURES-004: Device not found for topic [%s]', topic);
        } else {
            const localContext = _.clone(context);

            localContext.service = device.service;
            localContext.subservice = device.subservice;

            intoTrans(localContext, processMessageForDevice)(device, apiKey, topicInformation);
        }
    }

    utils.retrieveDevice(deviceId, apiKey, protocol, processDeviceMeasure);
}

/**
 * Handles an incoming AMQP message, extracting the API Key, device Id and attribute to update (in the case of single
 * measures) from the AMQP topic.
 *
 * @param {String} topic        Topic of the form: '/<APIKey>/deviceId/attributes[/<attributeName>]'.
 * @param {Object} message      AMQP message body (Object or Buffer, depending on the value).
 */
function amqpMessageHandler(topic, message) {
    regenerateTransid(topic);
    messageHandler(topic, message, 'AMQP');
}

/**
 * Handles an incoming MQTT message, extracting the API Key, device Id and attribute to update (in the case of single
 * measures) from the MQTT topic.
 *
 * @param {String} topic        Topic of the form: '/<APIKey>/deviceId/attributes[/<attributeName>]'.
 * @param {Object} message      MQTT message body (Object or Buffer, depending on the value).
 */
function mqttMessageHandler(topic, message) {
    regenerateTransid(topic);
    config.getLogger().debug(context, 'message topic: %s', topic);
    messageHandler(topic, message, 'MQTT');
}

exports.amqpMessageHandler = amqpMessageHandler;
exports.mqttMessageHandler = mqttMessageHandler;
exports.messageHandler = messageHandler;
exports.processMeasureGroup = processMeasureGroup;
exports.guessType = guessType;
<commit_msg>try toString as hex<commit_after>/*
 * Copyright 2016 Telefonica Investigación y Desarrollo, S.A.U
 *
 * This file is part of iotagent-ul
 *
 * iotagent-ul is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * iotagent-ul is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with iotagent-ul.
 * If not, seehttp://www.gnu.org/licenses/.
 *
 * For those usages not covered by the GNU Affero General Public License
 * please contact with::[iot_support@tid.es]
 *
 * Modified by: Fernando Méndez, Daniel Calvo - ATOS Research & Innovation
 */

/* eslint-disable no-prototype-builtins */

const iotAgentLib = require('iotagent-node-lib');
const regenerateTransid = iotAgentLib.regenerateTransid;
const config = require('./configService');
const transportSelector = require('./transportSelector');
const intoTrans = iotAgentLib.intoTrans;
const finishSouthBoundTransaction = iotAgentLib.finishSouthBoundTransaction;
const fillService = iotAgentLib.fillService;
const _ = require('underscore');
const utils = require('./iotaUtils');
const async = require('async');
const ulParser = require('./ulParser');
const constants = require('./constants');
let context = {
    op: 'IOTAUL.Common.Binding'
};

/**
 * Find the attribute given by its name between all the active attributes of the given device, returning its type, or
 * null otherwise.
 *
 * @param {String} attribute        Name of the attribute to find.
 * @param {Object} device           Device object containing all the information about a device.
 * @return {String}                 String identifier of the attribute type.
 */
function guessType(attribute, device) {
    for (let i = 0; i < device.active.length; i++) {
        if (device.active[i].name === attribute) {
            return device.active[i].type;
        }
    }

    if (attribute === constants.TIMESTAMP_ATTRIBUTE) {
        return constants.TIMESTAMP_TYPE_NGSI2;
    }
    return constants.DEFAULT_ATTRIBUTE_TYPE;
}

function sendConfigurationToDevice(device, apiKey, deviceId, results, callback) {
    transportSelector.applyFunctionFromBinding(
        [apiKey, deviceId, results],
        'sendConfigurationToDevice',
        device.transport,
        callback
    );
}

/**
 * Deals with configuration requests coming from the device. Whenever a new configuration requests arrives with a list
 * of attributes to retrieve, this handler asks the Context Broker for the values of those attributes, and publish a
 * new message in the "/1234/MQTT_2/configuration/values" topic
 *
 * @param {String} apiKey           API Key corresponding to the Devices configuration.
 * @param {String} deviceId         Id of the device to be updated.
 * @param {Object} device           Device object containing all the information about a device.
 * @param {Object} objMessage          JSON object received.
 */
function manageConfigurationRequest(apiKey, deviceId, device, objMessage) {
    utils.manageConfiguration(
        apiKey,
        deviceId,
        device,
        objMessage,
        async.apply(sendConfigurationToDevice, device),
        function (error) {
            if (error) {
                iotAgentLib.alarms.raise(constants.MQTTB_ALARM, error);
            } else {
                iotAgentLib.alarms.release(constants.MQTTB_ALARM);
                config
                    .getLogger()
                    .debug(context, 'Configuration request finished for APIKey [%s] and Device [%s]', apiKey, deviceId);
            }
            finishSouthBoundTransaction(null);
        }
    );
}

/**
 * Utility function used to reduce UL Payload group arrays and process them to update their value in the Context Broker.
 * This function process a new element of the payload group, generating a function ready to be called with a callback
 * in a async.series() call.
 *
 * @param {Object} device       Object containing all the information about the device sending the measures.
 * @param {String} apikey       APIKey of the service the device belongs to.
 * @param {Array} previous      Array of prepared functions that send information to the Context Broker.
 * @param {Object} current      Information sent by the device.
 * @param {Number} index        Index of the group in the array.
 * @return {Array}             Updated array of functions.
 */

/* eslint-disable-next-line no-unused-vars */
function processMeasureGroup(device, apikey, previous, current, index) {
    const values = [];
    if (current.command) {
        previous.push(
            iotAgentLib.setCommandResult.bind(
                null,
                device.name,
                config.getConfig().iota.defaultResource,
                apikey,
                current.command,
                current.value,
                constants.COMMAND_STATUS_COMPLETED,
                device
            )
        );
    } else {
        for (const k in current) {
            if (current.hasOwnProperty(k)) {
                values.push({
                    name: k,
                    type: guessType(k, device),
                    value: current[k]
                });
            }
        }

        previous.push(iotAgentLib.update.bind(null, device.name, device.type, '', values, device));
    }

    return previous;
}

/**
 * Adds multiple measures to the Context Broker. Multiple measures come in the form of single-level JSON objects,
 * whose keys are the attribute names and whose values are the attribute values.
 *
 * @param {String} apiKey           API Key corresponding to the Devices configuration.
 * @param {Object} device           Device object containing all the information about a device.
 * @param {String} message          UL payload.
 */
function multipleMeasures(apiKey, device, messageStr, message) {
    let updates = [];
    let parsedMessage;

    config.getLogger().debug('Processing multiple measures for device [%s] with apiKey [%s]', device.id, apiKey);

    // Parse Message
    try {
        parsedMessage = ulParser.parse(messageStr);
        config.getLogger().debug(context, 'stringMessage: [%s] parsedMessage: [%s]', messageStr, parsedMessage);
    } catch (e) {
        messageStr = message.toString('hex');
        try {
            parsedMessage = ulParser.parse(messageStr);
            config.getLogger().debug(context, 'stringMessage: [%s] parsedMessage: [%s]', messageStr, parsedMessage);
        } catch (e) {
            config.getLogger().error(context, 'MEASURES-003: Parse error parsing incoming message [%]', messageStr);
            return;
        }
    }
    updates = parsedMessage.reduce(processMeasureGroup.bind(null, device, apiKey), []);

    async.series(updates, function (error) {
        if (error) {
            config.getLogger().error(
                context,
                /*jshint quotmark: double */
                " MEASURES-002: Couldn't send the updated values to the Context Broker due to an error: %j",
                /*jshint quotmark: single */
                error
            );
        } else {
            // prettier-ignore
            config.getLogger().info(
                context,
                'Multiple measures for device [%s] with apiKey [%s] successfully updated',
                device.id,
                apiKey
            );
        }
        finishSouthBoundTransaction(null);
    });
}

/**
 * Adds a single measure to the context broker. The message for single measures contains the direct value to
 * be inserted in the attribute, given by its name.
 *
 * @param {String} apiKey           API Key corresponding to the Devices configuration.
 * @param {String} attribute        Name of the attribute to update.
 * @param {Object} device           Device object containing all the information about a device.
 * @param {Buffer} message          Raw message coming from the client.
 */
function singleMeasure(apiKey, attribute, device, messageStr, message) {
    config
        .getLogger()
        .debug('Processing single measure [%s] for device [%s] with apiKey [%s]', messageStr, device.id, apiKey);
    const values = [
        {
            name: attribute,
            type: guessType(attribute, device),
            value: messageStr
        }
    ];

    iotAgentLib.update(device.name, device.type, '', values, device, function (error) {
        if (error) {
            config.getLogger().error(
                context,
                /*jshint quotmark: double */
                " MEASURES-002: Couldn't send the updated values to the Context Broker due to an error: %j",
                /*jshint quotmark: single */
                error
            );
        } else {
            // prettier-ignore
            config.getLogger().debug(
                context,
                'Single measure for device [%s] with apiKey [%s] successfully updated',
                device.id,
                apiKey
            );
        }
        finishSouthBoundTransaction(null);
    });
}

/**
 * Handles an incoming message, extracting the API Key, device Id and attribute to update (in the case of single
 * measures) from the topic.
 *
 * @param {String} topic        Topic of the form: '/<APIKey>/deviceId/attributes[/<attributeName>]'.
 * @param {Object} message      message body (Object or Buffer, depending on the value).
 */
function messageHandler(topic, message, protocol) {
    if (topic[0] !== '/') {
        topic = '/' + topic;
    }
    const topicInformation = topic.split('/');
    let parsedMessage;

    if (topicInformation[1].toLowerCase() === 'ul') {
        topicInformation.splice(1, 1);
    }
    const apiKey = topicInformation[1];
    const deviceId = topicInformation[2];
    const messageStr = message.toString();
    // TBD: msgStr

    function processMessageForDevice(device, apiKey, topicInformation) {
        iotAgentLib.alarms.release(constants.MQTTB_ALARM);

        if (
            topicInformation[3] === constants.CONFIGURATION_SUFIX &&
            topicInformation[4] === constants.CONFIGURATION_COMMAND_SUFIX &&
            message
        ) {
            parsedMessage = ulParser.parseConfigurationRequest(messageStr);
            manageConfigurationRequest(apiKey, deviceId, device, parsedMessage);
        } else if (topicInformation[3] === constants.CONFIGURATION_COMMAND_UPDATE) {
            const commandObj = ulParser.result(messageStr);
            utils.updateCommand(
                apiKey,
                device,
                commandObj.result,
                commandObj.command,
                constants.COMMAND_STATUS_COMPLETED,
                function (error) {
                    config.getLogger().debug('Command updated with result: %s', error);
                }
            );
        } else if (topicInformation[4]) {
            singleMeasure(apiKey, topicInformation[4], device, messageStr, message);
        } else if (topicInformation[3] === constants.MEASURES_SUFIX) {
            multipleMeasures(apiKey, device, messageStr, message);
        } else {
            config.getLogger().error(
                context,
                /*jshint quotmark: double */
                "MEASURES-004: Couldn't process message [%s] due to format issues.",
                /*jshint quotmark: single */
                message
            );
        }
    }

    function processDeviceMeasure(error, device) {
        if (error) {
            context = fillService(context, { service: 'n/a', subservice: 'n/a' });
            config.getLogger().warn(context, 'MEASURES-004: Device not found for topic [%s]', topic);
        } else {
            const localContext = _.clone(context);

            localContext.service = device.service;
            localContext.subservice = device.subservice;

            intoTrans(localContext, processMessageForDevice)(device, apiKey, topicInformation);
        }
    }

    utils.retrieveDevice(deviceId, apiKey, protocol, processDeviceMeasure);
}

/**
 * Handles an incoming AMQP message, extracting the API Key, device Id and attribute to update (in the case of single
 * measures) from the AMQP topic.
 *
 * @param {String} topic        Topic of the form: '/<APIKey>/deviceId/attributes[/<attributeName>]'.
 * @param {Object} message      AMQP message body (Object or Buffer, depending on the value).
 */
function amqpMessageHandler(topic, message) {
    regenerateTransid(topic);
    messageHandler(topic, message, 'AMQP');
}

/**
 * Handles an incoming MQTT message, extracting the API Key, device Id and attribute to update (in the case of single
 * measures) from the MQTT topic.
 *
 * @param {String} topic        Topic of the form: '/<APIKey>/deviceId/attributes[/<attributeName>]'.
 * @param {Object} message      MQTT message body (Object or Buffer, depending on the value).
 */
function mqttMessageHandler(topic, message) {
    regenerateTransid(topic);
    config.getLogger().debug(context, 'message topic: %s', topic);
    messageHandler(topic, message, 'MQTT');
}

exports.amqpMessageHandler = amqpMessageHandler;
exports.mqttMessageHandler = mqttMessageHandler;
exports.messageHandler = messageHandler;
exports.processMeasureGroup = processMeasureGroup;
exports.guessType = guessType;
<|endoftext|>


<commit_before>/* global Headers */

import fetch from 'isomorphic-fetch'
import promise from 'es6-promise'

promise.polyfill()

class Api {
  constructor (apiConfig) {
    this.host = apiConfig.host
    this.port = apiConfig.port
  }

  save (data, callback) {
    const url = '/resource/' + (data['@id'] || '')
    fetch(this.host + ':' + this.port + url, {
      method: 'POST',
      mode: 'cors',
      headers: new Headers({
        'Content-Type': 'application/json'
      }),
      body: JSON.stringify(data)
    }).then(response => {
      return(response.json())
    }).then(data => {
      callback(data)
    }).catch(err => {
      console.error(err)
    })
  }

  load (url, callback) {
    url = url === '/' ? '/resource/' : url
    fetch(this.host + ':' + this.port + url, {
      headers: new Headers({
        'Accept': 'application/json'
      })
    }).then(response => {
      return(response.json())
    }).then(data => {
      callback(data)
    }).catch(err => {
      console.error(err)
    })
  }

  find (term, types, callback) {
    const url = `/resource/?q=${term}` + (types ? `&filter.about.@type=${types.join(',')}` : '')
    fetch(this.host + ':' + this.port + url, {
      headers: new Headers({
        'Accept': 'application/json'
      })
    }).then(response => {
      return(response.json())
    }).then(data => {
      callback(data)
    }).catch(err => {
      console.error(err)
    })
  }

}

export default Api
<commit_msg>Throw HTTP errors<commit_after>/* global Headers */

import fetch from 'isomorphic-fetch'
import promise from 'es6-promise'

promise.polyfill()

const toJson = response => {
  if (response.status >= 400) {
    throw new Error("Bad response from server")
  }
  return response.json()
}

class Api {
  constructor (apiConfig) {
    this.host = apiConfig.host
    this.port = apiConfig.port
  }

  save (data, callback) {
    const url = '/resource/' + (data['@id'] || '')
    fetch(this.host + ':' + this.port + url, {
      method: 'POST',
      mode: 'cors',
      headers: new Headers({
        'Content-Type': 'application/json'
      }),
      body: JSON.stringify(data)
    }).then(response => {
      return(toJson(response))
    }).then(data => {
      callback(data)
    }).catch(err => {
      console.error(err)
    })
  }

  load (url, callback) {
    url = url === '/' ? '/resource/' : url
    fetch(this.host + ':' + this.port + url, {
      headers: new Headers({
        'Accept': 'application/json'
      })
    }).then(response => {
      return(toJson(response))
    }).then(data => {
      callback(data)
    }).catch(err => {
      console.error(err)
    })
  }

  find (term, types, callback) {
    const url = `/resource/?q=${term}` + (types ? `&filter.about.@type=${types.join(',')}` : '')
    fetch(this.host + ':' + this.port + url, {
      headers: new Headers({
        'Accept': 'application/json'
      })
    }).then(response => {
      return(toJson(response))
    }).then(data => {
      callback(data)
    }).catch(err => {
      console.error(err)
    })
  }

}

export default Api
<|endoftext|>


<commit_before>// Copyright (c) 2018, Windel Bouwman & Patrick Quist
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

const BaseCompiler = require('../base-compiler'),
    exec = require('../exec'),
    logger = require('../logger').logger;

class PPCICompiler extends BaseCompiler {
    filterUserOptions(args) {
        return args.filter((item) => {
            if (typeof item == "string") {
                if ((item.endsWith("output.s") || item.endsWith(this.compileFilename) || !item.includes("/")) &&
                    (item.toLowerCase() != "--report") &&
                    (item.toLowerCase() != "--text-report")) {
                        return item;
                    } else {
                        return false;
                    }
            } else {
                return item;
            }
        });
    }

    exec(compiler, args, options) {
        if (compiler.endsWith('.py')) {
            const python = this.env.ceProps('python3');
            options = options || {};

            const matches = compiler.match(/^(.*)(\/ppci\/)(.*).py/);
            if (matches) {
                const pythonPath = matches[1];
                const ppciName = `ppci.${matches[3].replace('/', '.')}`;
                options.env = {PYTHONPATH: pythonPath};
                let python_args = ['-m', ppciName].concat(args);
                return exec.execute(python, python_args, options);
            }
            logger.error(`Invalid ppci path ${compiler}`);
        } else {
            return super.exec(compiler, args, options);
        }
    }
}

module.exports = PPCICompiler;
<commit_msg>shorter<commit_after>// Copyright (c) 2018, Windel Bouwman & Patrick Quist
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

const BaseCompiler = require('../base-compiler'),
    exec = require('../exec'),
    logger = require('../logger').logger;

class PPCICompiler extends BaseCompiler {
    filterUserOptions(args) {
        return args.filter((item) => {
            if (typeof item !== "string") return true;

            return
                ((item.endsWith("output.s") || item.endsWith(this.compileFilename) || !item.includes("/")) &&
                (item.toLowerCase() !== "--report") &&
                (item.toLowerCase() !== "--text-report"));
        });
    }

    exec(compiler, args, options) {
        if (compiler.endsWith('.py')) {
            const python = this.env.ceProps('python3');
            options = options || {};

            const matches = compiler.match(/^(.*)(\/ppci\/)(.*).py/);
            if (matches) {
                const pythonPath = matches[1];
                const ppciName = `ppci.${matches[3].replace('/', '.')}`;
                options.env = {PYTHONPATH: pythonPath};
                let python_args = ['-m', ppciName].concat(args);
                return exec.execute(python, python_args, options);
            }
            logger.error(`Invalid ppci path ${compiler}`);
        } else {
            return super.exec(compiler, args, options);
        }
    }
}

module.exports = PPCICompiler;
<|endoftext|>