You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by st...@apache.org on 2017/05/02 00:09:01 UTC

[41/68] [abbrv] cordova-lib git commit: CB-11242: updated tests and fixtures

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/pluginHandlers.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/pluginHandlers.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/pluginHandlers.js
new file mode 100644
index 0000000..5e745fd
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/pluginHandlers.js
@@ -0,0 +1,308 @@
+/*
+ *
+ * Copyright 2013 Anis Kadri
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+/* jshint unused: vars */
+
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var events = require('cordova-common').events;
+var CordovaError = require('cordova-common').CordovaError;
+
+var handlers = {
+    'source-file':{
+        install:function(obj, plugin, project, options) {
+            if (!obj.src) throw new CordovaError(generateAttributeError('src', 'source-file', plugin.id));
+            if (!obj.targetDir) throw new CordovaError(generateAttributeError('target-dir', 'source-file', plugin.id));
+
+            var dest = path.join(obj.targetDir, path.basename(obj.src));
+
+            if(options && options.android_studio === true) {
+              dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
+            }
+
+            if (options && options.force) {
+                copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
+            } else {
+                copyNewFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
+            }
+        },
+        uninstall:function(obj, plugin, project, options) {
+            var dest = path.join(obj.targetDir, path.basename(obj.src));
+            
+            if(options && options.android_studio === true) {
+              dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
+            }
+
+            deleteJava(project.projectDir, dest);
+        }
+    },
+    'lib-file':{
+        install:function(obj, plugin, project, options) {
+            var dest = path.join('libs', path.basename(obj.src));
+            if(options && options.android_studio === true) {
+              dest = path.join('app/libs', path.basename(obj.src));
+            }
+            copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
+        },
+        uninstall:function(obj, plugin, project, options) {
+            var dest = path.join('libs', path.basename(obj.src));
+            if(options && options.android_studio === true) {
+              dest = path.join('app/libs', path.basename(obj.src));
+            }
+            removeFile(project.projectDir, dest);
+        }
+    },
+    'resource-file':{
+        install:function(obj, plugin, project, options) {
+            copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), !!(options && options.link));
+        },
+        uninstall:function(obj, plugin, project, options) {
+            removeFile(project.projectDir, path.normalize(obj.target));
+        }
+    },
+    'framework': {
+        install:function(obj, plugin, project, options) {
+            var src = obj.src;
+            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));
+
+            events.emit('verbose', 'Installing Android library: ' + src);
+            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
+            var subDir;
+
+            if (obj.custom) {
+                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
+                copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, !!(options && options.link));
+                subDir = path.resolve(project.projectDir, subRelativeDir);
+            } else {
+                obj.type = 'sys';
+                subDir = src;
+            }
+
+            if (obj.type == 'gradleReference') {
+                project.addGradleReference(parentDir, subDir);
+            } else if (obj.type == 'sys') {
+                project.addSystemLibrary(parentDir, subDir);
+            } else {
+                project.addSubProject(parentDir, subDir);
+            }
+        },
+        uninstall:function(obj, plugin, project, options) {
+            var src = obj.src;
+            if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));
+
+            events.emit('verbose', 'Uninstalling Android library: ' + src);
+            var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
+            var subDir;
+
+            if (obj.custom) {
+                var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
+                removeFile(project.projectDir, subRelativeDir);
+                subDir = path.resolve(project.projectDir, subRelativeDir);
+                // If it's the last framework in the plugin, remove the parent directory.
+                var parDir = path.dirname(subDir);
+                if (fs.existsSync(parDir) && fs.readdirSync(parDir).length === 0) {
+                    fs.rmdirSync(parDir);
+                }
+            } else {
+                obj.type = 'sys';
+                subDir = src;
+            }
+
+            if (obj.type == 'gradleReference') {
+                project.removeGradleReference(parentDir, subDir);
+            } else if (obj.type == 'sys') {
+                project.removeSystemLibrary(parentDir, subDir);
+            } else {
+                project.removeSubProject(parentDir, subDir);
+            }
+        }
+    },
+    asset:{
+        install:function(obj, plugin, project, options) {
+            if (!obj.src) {
+                throw new CordovaError(generateAttributeError('src', 'asset', plugin.id));
+            }
+            if (!obj.target) {
+                throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
+            }
+
+            copyFile(plugin.dir, obj.src, project.www, obj.target);
+            if (options && options.usePlatformWww) {
+                // CB-11022 copy file to both directories if usePlatformWww is specified
+                copyFile(plugin.dir, obj.src, project.platformWww, obj.target);
+            }
+        },
+        uninstall:function(obj, plugin, project, options) {
+            var target = obj.target || obj.src;
+
+            if (!target) throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
+
+            removeFileF(path.resolve(project.www, target));
+            removeFileF(path.resolve(project.www, 'plugins', plugin.id));
+            if (options && options.usePlatformWww) {
+                // CB-11022 remove file from both directories if usePlatformWww is specified
+                removeFileF(path.resolve(project.platformWww, target));
+                removeFileF(path.resolve(project.platformWww, 'plugins', plugin.id));
+            }
+        }
+    },
+    'js-module': {
+        install: function (obj, plugin, project, options) {
+            // Copy the plugin's files into the www directory.
+            var moduleSource = path.resolve(plugin.dir, obj.src);
+            var moduleName = plugin.id + '.' + (obj.name || path.basename(obj.src, path.extname (obj.src)));
+
+            // Read in the file, prepend the cordova.define, and write it back out.
+            var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
+            if (moduleSource.match(/.*\.json$/)) {
+                scriptContent = 'module.exports = ' + scriptContent;
+            }
+            scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n';
+
+            var wwwDest = path.resolve(project.www, 'plugins', plugin.id, obj.src);
+            shell.mkdir('-p', path.dirname(wwwDest));
+            fs.writeFileSync(wwwDest, scriptContent, 'utf-8');
+
+            if (options && options.usePlatformWww) {
+                // CB-11022 copy file to both directories if usePlatformWww is specified
+                var platformWwwDest = path.resolve(project.platformWww, 'plugins', plugin.id, obj.src);
+                shell.mkdir('-p', path.dirname(platformWwwDest));
+                fs.writeFileSync(platformWwwDest, scriptContent, 'utf-8');
+            }
+        },
+        uninstall: function (obj, plugin, project, options) {
+            var pluginRelativePath = path.join('plugins', plugin.id, obj.src);
+            removeFileAndParents(project.www, pluginRelativePath);
+            if (options && options.usePlatformWww) {
+                // CB-11022 remove file from both directories if usePlatformWww is specified
+                removeFileAndParents(project.platformWww, pluginRelativePath);
+            }
+        }
+    }
+};
+
+module.exports.getInstaller = function (type) {
+    if (handlers[type] && handlers[type].install) {
+        return handlers[type].install;
+    }
+
+    events.emit('verbose', '<' + type + '> is not supported for android plugins');
+};
+
+module.exports.getUninstaller = function(type) {
+    if (handlers[type] && handlers[type].uninstall) {
+        return handlers[type].uninstall;
+    }
+
+    events.emit('verbose', '<' + type + '> is not supported for android plugins');
+};
+
+function copyFile (plugin_dir, src, project_dir, dest, link) {
+    src = path.resolve(plugin_dir, src);
+    if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');
+
+    // check that src path is inside plugin directory
+    var real_path = fs.realpathSync(src);
+    var real_plugin_path = fs.realpathSync(plugin_dir);
+    if (real_path.indexOf(real_plugin_path) !== 0)
+        throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"');
+
+    dest = path.resolve(project_dir, dest);
+
+    // check that dest path is located in project directory
+    if (dest.indexOf(project_dir) !== 0)
+        throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project');
+
+    shell.mkdir('-p', path.dirname(dest));
+    if (link) {
+        symlinkFileOrDirTree(src, dest);
+    } else if (fs.statSync(src).isDirectory()) {
+        // XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
+        shell.cp('-Rf', src+'/*', dest);
+    } else {
+        shell.cp('-f', src, dest);
+    }
+}
+
+// Same as copy file but throws error if target exists
+function copyNewFile (plugin_dir, src, project_dir, dest, link) {
+    var target_path = path.resolve(project_dir, dest);
+    if (fs.existsSync(target_path))
+        throw new CordovaError('"' + target_path + '" already exists!');
+
+    copyFile(plugin_dir, src, project_dir, dest, !!link);
+}
+
+function symlinkFileOrDirTree(src, dest) {
+    if (fs.existsSync(dest)) {
+        shell.rm('-Rf', dest);
+    }
+
+    if (fs.statSync(src).isDirectory()) {
+        shell.mkdir('-p', dest);
+        fs.readdirSync(src).forEach(function(entry) {
+            symlinkFileOrDirTree(path.join(src, entry), path.join(dest, entry));
+        });
+    }
+    else {
+        fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), src), dest);
+    }
+}
+
+// checks if file exists and then deletes. Error if doesn't exist
+function removeFile (project_dir, src) {
+    var file = path.resolve(project_dir, src);
+    shell.rm('-Rf', file);
+}
+
+// deletes file/directory without checking
+function removeFileF (file) {
+    shell.rm('-Rf', file);
+}
+
+// Sometimes we want to remove some java, and prune any unnecessary empty directories
+function deleteJava (project_dir, destFile) {
+    removeFileAndParents(project_dir, destFile, 'src');
+}
+
+function removeFileAndParents (baseDir, destFile, stopper) {
+    stopper = stopper || '.';
+    var file = path.resolve(baseDir, destFile);
+    if (!fs.existsSync(file)) return;
+
+    removeFileF(file);
+
+    // check if directory is empty
+    var curDir = path.dirname(file);
+
+    while(curDir !== path.resolve(baseDir, stopper)) {
+        if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
+            fs.rmdirSync(curDir);
+            curDir = path.resolve(curDir, '..');
+        } else {
+            // directory not empty...do nothing
+            break;
+        }
+    }
+}
+
+function generateAttributeError(attribute, element, id) {
+    return 'Required attribute "' + attribute + '" not specified in <' + element + '> element from plugin: ' + id;
+}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/prepare.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/prepare.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/prepare.js
new file mode 100644
index 0000000..504eb61
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/prepare.js
@@ -0,0 +1,471 @@
+/**
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+var Q = require('q');
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var events = require('cordova-common').events;
+var AndroidManifest = require('./AndroidManifest');
+var xmlHelpers = require('cordova-common').xmlHelpers;
+var CordovaError = require('cordova-common').CordovaError;
+var ConfigParser = require('cordova-common').ConfigParser;
+var FileUpdater = require('cordova-common').FileUpdater;
+var PlatformJson = require('cordova-common').PlatformJson;
+var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
+var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
+
+module.exports.prepare = function (cordovaProject, options) {
+    var self = this;
+
+    var platformJson = PlatformJson.load(this.locations.root, this.platform);
+    var munger = new PlatformMunger(this.platform, this.locations.root, platformJson, new PluginInfoProvider());
+
+    this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations);
+
+    // Update own www dir with project's www assets and plugins' assets and js-files
+    return Q.when(updateWww(cordovaProject, this.locations))
+    .then(function () {
+        // update project according to config.xml changes.
+        return updateProjectAccordingTo(self._config, self.locations);
+    })
+    .then(function () {
+        updateIcons(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
+        updateSplashes(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
+        updateFileResources(cordovaProject, path.relative(cordovaProject.root, self.locations.root));
+    })
+    .then(function () {
+        events.emit('verbose', 'Prepared android project successfully');
+    });
+};
+
+module.exports.clean = function (options) {
+    // A cordovaProject isn't passed into the clean() function, because it might have
+    // been called from the platform shell script rather than the CLI. Check for the
+    // noPrepare option passed in by the non-CLI clean script. If that's present, or if
+    // there's no config.xml found at the project root, then don't clean prepared files.
+    var projectRoot = path.resolve(this.root, '../..');
+    if ((options && options.noPrepare) || !fs.existsSync(this.locations.configXml) ||
+            !fs.existsSync(this.locations.configXml)) {
+        return Q();
+    }
+
+    var projectConfig = new ConfigParser(this.locations.configXml);
+
+    var self = this;
+    return Q().then(function () {
+        cleanWww(projectRoot, self.locations);
+        cleanIcons(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res));
+        cleanSplashes(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res));
+        cleanFileResources(projectRoot, projectConfig, path.relative(projectRoot, self.locations.root));
+    });
+};
+
+/**
+ * Updates config files in project based on app's config.xml and config munge,
+ *   generated by plugins.
+ *
+ * @param   {ConfigParser}   sourceConfig  A project's configuration that will
+ *   be merged into platform's config.xml
+ * @param   {ConfigChanges}  configMunger  An initialized ConfigChanges instance
+ *   for this platform.
+ * @param   {Object}         locations     A map of locations for this platform
+ *
+ * @return  {ConfigParser}                 An instance of ConfigParser, that
+ *   represents current project's configuration. When returned, the
+ *   configuration is already dumped to appropriate config.xml file.
+ */
+function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
+    events.emit('verbose', 'Generating platform-specific config.xml from defaults for android at ' + locations.configXml);
+
+    // First cleanup current config and merge project's one into own
+    // Overwrite platform config.xml with defaults.xml.
+    shell.cp('-f', locations.defaultConfigXml, locations.configXml);
+
+    // Then apply config changes from global munge to all config files
+    // in project (including project's config)
+    configMunger.reapply_global_munge().save_all();
+
+    events.emit('verbose', 'Merging project\'s config.xml into platform-specific android config.xml');
+    // Merge changes from app's config.xml into platform's one
+    var config = new ConfigParser(locations.configXml);
+    xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
+        config.doc.getroot(), 'android', /*clobber=*/true);
+
+    config.write();
+    return config;
+}
+
+/**
+ * Logs all file operations via the verbose event stream, indented.
+ */
+function logFileOp(message) {
+    events.emit('verbose', '  ' + message);
+}
+
+/**
+ * Updates platform 'www' directory by replacing it with contents of
+ *   'platform_www' and app www. Also copies project's overrides' folder into
+ *   the platform 'www' folder
+ *
+ * @param   {Object}  cordovaProject    An object which describes cordova project.
+ * @param   {Object}  destinations      An object that contains destination
+ *   paths for www files.
+ */
+function updateWww(cordovaProject, destinations) {
+    var sourceDirs = [
+        path.relative(cordovaProject.root, cordovaProject.locations.www),
+        path.relative(cordovaProject.root, destinations.platformWww)
+    ];
+
+    // If project contains 'merges' for our platform, use them as another overrides
+    var merges_path = path.join(cordovaProject.root, 'merges', 'android');
+    if (fs.existsSync(merges_path)) {
+        events.emit('verbose', 'Found "merges/android" folder. Copying its contents into the android project.');
+        sourceDirs.push(path.join('merges', 'android'));
+    }
+
+    var targetDir = path.relative(cordovaProject.root, destinations.www);
+    events.emit(
+        'verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir);
+    FileUpdater.mergeAndUpdateDir(
+        sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);
+}
+
+/**
+ * Cleans all files from the platform 'www' directory.
+ */
+function cleanWww(projectRoot, locations) {
+    var targetDir = path.relative(projectRoot, locations.www);
+    events.emit('verbose', 'Cleaning ' + targetDir);
+
+    // No source paths are specified, so mergeAndUpdateDir() will clear the target directory.
+    FileUpdater.mergeAndUpdateDir(
+        [], targetDir, { rootDir: projectRoot, all: true }, logFileOp);
+}
+
+/**
+ * Updates project structure and AndroidManifest according to project's configuration.
+ *
+ * @param   {ConfigParser}  platformConfig  A project's configuration that will
+ *   be used to update project
+ * @param   {Object}  locations       A map of locations for this platform
+ */
+function updateProjectAccordingTo(platformConfig, locations) {
+    // Update app name by editing res/values/strings.xml
+    var name = platformConfig.name();
+    var strings = xmlHelpers.parseElementtreeSync(locations.strings);
+    strings.find('string[@name="app_name"]').text = name.replace(/\'/g, '\\\'');
+    fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');
+    events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings);
+
+    // Java packages cannot support dashes
+    var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
+
+    var manifest = new AndroidManifest(locations.manifest);
+    var orig_pkg = manifest.getPackageId();
+
+    manifest.getActivity()
+        .setOrientation(platformConfig.getPreference('orientation'))
+        .setLaunchMode(findAndroidLaunchModePreference(platformConfig));
+
+    manifest.setVersionName(platformConfig.version())
+        .setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
+        .setPackageId(pkg)
+        .setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
+        .setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
+        .setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
+        .write();
+
+    var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\./g, '/'), '*.java');
+    var java_files = shell.ls(javaPattern).filter(function(f) {
+        return shell.grep(/extends\s+CordovaActivity/g, f);
+    });
+
+    if (java_files.length === 0) {
+        throw new CordovaError('No Java files found that extend CordovaActivity.');
+    } else if(java_files.length > 1) {
+        events.emit('log', 'Multiple candidate Java files that extend CordovaActivity found. Guessing at the first one, ' + java_files[0]);
+    }
+
+    var destFile = path.join(locations.root, 'src', pkg.replace(/\./g, '/'), path.basename(java_files[0]));
+    shell.mkdir('-p', path.dirname(destFile));
+    shell.sed(/package [\w\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile);
+    events.emit('verbose', 'Wrote out Android package name "' + pkg + '" to ' + destFile);
+
+    if (orig_pkg !== pkg) {
+        // If package was name changed we need to remove old java with main activity
+        shell.rm('-Rf',java_files[0]);
+        // remove any empty directories
+        var currentDir = path.dirname(java_files[0]);
+        var sourcesRoot = path.resolve(locations.root, 'src');
+        while(currentDir !== sourcesRoot) {
+            if(fs.existsSync(currentDir) && fs.readdirSync(currentDir).length === 0) {
+                fs.rmdirSync(currentDir);
+                currentDir = path.resolve(currentDir, '..');
+            } else {
+                break;
+            }
+        }
+    }
+}
+
+// Consturct the default value for versionCode as
+// PATCH + MINOR * 100 + MAJOR * 10000
+// see http://developer.android.com/tools/publishing/versioning.html
+function default_versionCode(version) {
+    var nums = version.split('-')[0].split('.');
+    var versionCode = 0;
+    if (+nums[0]) {
+        versionCode += +nums[0] * 10000;
+    }
+    if (+nums[1]) {
+        versionCode += +nums[1] * 100;
+    }
+    if (+nums[2]) {
+        versionCode += +nums[2];
+    }
+
+    events.emit('verbose', 'android-versionCode not found in config.xml. Generating a code based on version in config.xml (' + version + '): ' + versionCode);
+    return versionCode;
+}
+
+function getImageResourcePath(resourcesDir, type, density, name, sourceName) {
+    if (/\.9\.png$/.test(sourceName)) {
+        name = name.replace(/\.png$/, '.9.png');
+    }
+    var resourcePath = path.join(resourcesDir, (density ? type + '-' + density : type), name);
+    return resourcePath;
+}
+
+function updateSplashes(cordovaProject, platformResourcesDir) {
+    var resources = cordovaProject.projectConfig.getSplashScreens('android');
+
+    // if there are "splash" elements in config.xml
+    if (resources.length === 0) {
+        events.emit('verbose', 'This app does not have splash screens defined');
+        return;
+    }
+
+    var resourceMap = mapImageResources(cordovaProject.root, platformResourcesDir, 'drawable', 'screen.png');
+
+    var hadMdpi = false;
+    resources.forEach(function (resource) {
+        if (!resource.density) {
+            return;
+        }
+        if (resource.density == 'mdpi') {
+            hadMdpi = true;
+        }
+        var targetPath = getImageResourcePath(
+            platformResourcesDir, 'drawable', resource.density, 'screen.png', path.basename(resource.src));
+        resourceMap[targetPath] = resource.src;
+    });
+
+    // There's no "default" drawable, so assume default == mdpi.
+    if (!hadMdpi && resources.defaultResource) {
+        var targetPath = getImageResourcePath(
+            platformResourcesDir, 'drawable', 'mdpi', 'screen.png', path.basename(resources.defaultResource.src));
+        resourceMap[targetPath] = resources.defaultResource.src;
+    }
+
+    events.emit('verbose', 'Updating splash screens at ' + platformResourcesDir);
+    FileUpdater.updatePaths(
+        resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+}
+
+function cleanSplashes(projectRoot, projectConfig, platformResourcesDir) {
+    var resources = projectConfig.getSplashScreens('android');
+    if (resources.length > 0) {
+        var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'drawable', 'screen.png');
+        events.emit('verbose', 'Cleaning splash screens at ' + platformResourcesDir);
+
+        // No source paths are specified in the map, so updatePaths() will delete the target files.
+        FileUpdater.updatePaths(
+            resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
+    }
+}
+
+function updateIcons(cordovaProject, platformResourcesDir) {
+    var icons = cordovaProject.projectConfig.getIcons('android');
+
+    // if there are icon elements in config.xml
+    if (icons.length === 0) {
+        events.emit('verbose', 'This app does not have launcher icons defined');
+        return;
+    }
+
+    var resourceMap = mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'icon.png');
+
+    var android_icons = {};
+    var default_icon;
+    // http://developer.android.com/design/style/iconography.html
+    var sizeToDensityMap = {
+        36: 'ldpi',
+        48: 'mdpi',
+        72: 'hdpi',
+        96: 'xhdpi',
+        144: 'xxhdpi',
+        192: 'xxxhdpi'
+    };
+    // find the best matching icon for a given density or size
+    // @output android_icons
+    var parseIcon = function(icon, icon_size) {
+        // do I have a platform icon for that density already
+        var density = icon.density || sizeToDensityMap[icon_size];
+        if (!density) {
+            // invalid icon defition ( or unsupported size)
+            return;
+        }
+        var previous = android_icons[density];
+        if (previous && previous.platform) {
+            return;
+        }
+        android_icons[density] = icon;
+    };
+
+    // iterate over all icon elements to find the default icon and call parseIcon
+    for (var i=0; i<icons.length; i++) {
+        var icon = icons[i];
+        var size = icon.width;
+        if (!size) {
+            size = icon.height;
+        }
+        if (!size && !icon.density) {
+            if (default_icon) {
+                events.emit('verbose', 'Found extra default icon: ' + icon.src + ' (ignoring in favor of ' + default_icon.src + ')');
+            } else {
+                default_icon = icon;
+            }
+        } else {
+            parseIcon(icon, size);
+        }
+    }
+
+    // The source paths for icons and splashes are relative to
+    // project's config.xml location, so we use it as base path.
+    for (var density in android_icons) {
+        var targetPath = getImageResourcePath(
+            platformResourcesDir, 'mipmap', density, 'icon.png', path.basename(android_icons[density].src));
+        resourceMap[targetPath] = android_icons[density].src;
+    }
+
+    // There's no "default" drawable, so assume default == mdpi.
+    if (default_icon && !android_icons.mdpi) {
+        var defaultTargetPath = getImageResourcePath(
+            platformResourcesDir, 'mipmap', 'mdpi', 'icon.png', path.basename(default_icon.src));
+        resourceMap[defaultTargetPath] = default_icon.src;
+    }
+
+    events.emit('verbose', 'Updating icons at ' + platformResourcesDir);
+    FileUpdater.updatePaths(
+        resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+}
+
+function cleanIcons(projectRoot, projectConfig, platformResourcesDir) {
+    var icons = projectConfig.getIcons('android');
+    if (icons.length > 0) {
+        var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'icon.png');
+        events.emit('verbose', 'Cleaning icons at ' + platformResourcesDir);
+
+        // No source paths are specified in the map, so updatePaths() will delete the target files.
+        FileUpdater.updatePaths(
+            resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
+    }
+}
+
+/**
+ * Gets a map containing resources of a specified name from all drawable folders in a directory.
+ */
+function mapImageResources(rootDir, subDir, type, resourceName) {
+    var pathMap = {};
+    shell.ls(path.join(rootDir, subDir, type + '-*'))
+    .forEach(function (drawableFolder) {
+        var imagePath = path.join(subDir, path.basename(drawableFolder), resourceName);
+        pathMap[imagePath] = null;
+    });
+    return pathMap;
+}
+
+
+function updateFileResources(cordovaProject, platformDir) {
+    var files = cordovaProject.projectConfig.getFileResources('android');
+
+    // if there are resource-file elements in config.xml
+    if (files.length === 0) {
+        events.emit('verbose', 'This app does not have additional resource files defined');
+        return;
+    }
+
+    var resourceMap = {};
+    files.forEach(function(res) {
+        var targetPath = path.join(platformDir, res.target);
+        resourceMap[targetPath] = res.src;
+    });
+
+    events.emit('verbose', 'Updating resource files at ' + platformDir);
+    FileUpdater.updatePaths(
+        resourceMap, { rootDir: cordovaProject.root }, logFileOp);
+}
+
+
+function cleanFileResources(projectRoot, projectConfig, platformDir) {
+    var files = projectConfig.getFileResources('android');
+    if (files.length > 0) {
+        events.emit('verbose', 'Cleaning resource files at ' + platformDir);
+
+        var resourceMap = {};
+        files.forEach(function(res) {
+            var filePath = path.join(platformDir, res.target);
+            resourceMap[filePath] = null;
+        });
+
+        FileUpdater.updatePaths(
+                resourceMap, { rootDir: projectRoot, all: true}, logFileOp);
+    }
+}
+
+/**
+ * Gets and validates 'AndroidLaunchMode' prepference from config.xml. Returns
+ *   preference value and warns if it doesn't seems to be valid
+ *
+ * @param   {ConfigParser}  platformConfig  A configParser instance for
+ *   platform.
+ *
+ * @return  {String}                  Preference's value from config.xml or
+ *   default value, if there is no such preference. The default value is
+ *   'singleTop'
+ */
+function findAndroidLaunchModePreference(platformConfig) {
+    var launchMode = platformConfig.getPreference('AndroidLaunchMode');
+    if (!launchMode) {
+        // Return a default value
+        return 'singleTop';
+    }
+
+    var expectedValues = ['standard', 'singleTop', 'singleTask', 'singleInstance'];
+    var valid = expectedValues.indexOf(launchMode) >= 0;
+    if (!valid) {
+        // Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future
+        events.emit('warn', 'Unrecognized value for AndroidLaunchMode preference: ' +
+            launchMode + '. Expected values are: ' + expectedValues.join(', '));
+    }
+
+    return launchMode;
+}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/retry.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/retry.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/retry.js
new file mode 100644
index 0000000..3cb4927
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/retry.js
@@ -0,0 +1,68 @@
+#!/usr/bin/env node
+
+/*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+
+/* jshint node: true */
+
+'use strict';
+
+var events = require('cordova-common').events;
+
+/*
+ * Retry a promise-returning function a number of times, propagating its
+ * results on success or throwing its error on a failed final attempt.
+ *
+ * @arg {Number}   attemts_left    - The number of times to retry the passed call.
+ * @arg {Function} promiseFunction - A function that returns a promise.
+ * @arg {...}                      - Arguments to pass to promiseFunction.
+ *
+ * @returns {Promise}
+ */
+module.exports.retryPromise = function (attemts_left, promiseFunction) {
+
+    // NOTE:
+    //      get all trailing arguments, by skipping the first two (attemts_left and
+    //      promiseFunction) because they shouldn't get passed to promiseFunction
+    var promiseFunctionArguments = Array.prototype.slice.call(arguments, 2);
+
+    return promiseFunction.apply(undefined, promiseFunctionArguments).then(
+
+        // on success pass results through
+        function onFulfilled(value) {
+            return value;
+        },
+
+        // on rejection either retry, or throw the error
+        function onRejected(error) {
+
+            attemts_left -= 1;
+
+            if (attemts_left < 1) {
+                throw error;
+            }
+
+            events.emit('verbose', 'A retried call failed. Retrying ' + attemts_left + ' more time(s).');
+
+            // retry call self again with the same arguments, except attemts_left is now lower
+            var fullArguments = [attemts_left, promiseFunction].concat(promiseFunctionArguments);
+            return module.exports.retryPromise.apply(undefined, fullArguments);
+        }
+    );
+};

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/run.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/run.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/run.js
new file mode 100644
index 0000000..214a1e1
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/run.js
@@ -0,0 +1,141 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+/* jshint loopfunc:true */
+
+var path  = require('path'),
+    build = require('./build'),
+    emulator = require('./emulator'),
+    device   = require('./device'),
+    Q = require('q'),
+    events = require('cordova-common').events;
+
+function getInstallTarget(runOptions) {
+    var install_target;
+    if (runOptions.target) {
+        install_target = runOptions.target;
+    } else if (runOptions.device) {
+        install_target = '--device';
+    } else if (runOptions.emulator) {
+        install_target = '--emulator';
+    }
+
+    return install_target;
+}
+
+/**
+ * Runs the application on a device if available. If no device is found, it will
+ *   use a started emulator. If no started emulators are found it will attempt
+ *   to start an avd. If no avds are found it will error out.
+ *
+ * @param   {Object}  runOptions  various run/build options. See Api.js build/run
+ *   methods for reference.
+ *
+ * @return  {Promise}
+ */
+ module.exports.run = function(runOptions) {
+
+    var self = this;
+    var install_target = getInstallTarget(runOptions);
+
+    return Q()
+    .then(function() {
+        if (!install_target) {
+            // no target given, deploy to device if available, otherwise use the emulator.
+            return device.list()
+            .then(function(device_list) {
+                if (device_list.length > 0) {
+                    events.emit('warn', 'No target specified, deploying to device \'' + device_list[0] + '\'.');
+                    install_target = device_list[0];
+                } else {
+                    events.emit('warn', 'No target specified and no devices found, deploying to emulator');
+                    install_target = '--emulator';
+                }
+            });
+        }
+    }).then(function() {
+        if (install_target == '--device') {
+            return device.resolveTarget(null);
+        } else if (install_target == '--emulator') {
+            // Give preference to any already started emulators. Else, start one.
+            return emulator.list_started()
+            .then(function(started) {
+                return started && started.length > 0 ? started[0] : emulator.start();
+            }).then(function(emulatorId) {
+                return emulator.resolveTarget(emulatorId);
+            });
+        }
+        // They specified a specific device/emulator ID.
+        return device.list()
+        .then(function(devices) {
+            if (devices.indexOf(install_target) > -1) {
+                return device.resolveTarget(install_target);
+            }
+            return emulator.list_started()
+            .then(function(started_emulators) {
+                if (started_emulators.indexOf(install_target) > -1) {
+                    return emulator.resolveTarget(install_target);
+                }
+                return emulator.list_images()
+                .then(function(avds) {
+                    // if target emulator isn't started, then start it.
+                    for (var avd in avds) {
+                        if (avds[avd].name == install_target) {
+                            return emulator.start(install_target)
+                            .then(function(emulatorId) {
+                                return emulator.resolveTarget(emulatorId);
+                            });
+                        }
+                    }
+                    return Q.reject('Target \'' + install_target + '\' not found, unable to run project');
+                });
+            });
+        });
+    }).then(function(resolvedTarget) {
+        // Better just call self.build, but we're doing some processing of
+        // build results (according to platformApi spec) so they are in different
+        // format than emulator.install expects.
+        // TODO: Update emulator/device.install to handle this change
+        return build.run.call(self, runOptions, resolvedTarget)
+        .then(function(buildResults) {
+            if (resolvedTarget.isEmulator) {
+                return emulator.wait_for_boot(resolvedTarget.target)
+                .then(function () {
+                    return emulator.install(resolvedTarget, buildResults);
+                });
+            }
+            return device.install(resolvedTarget, buildResults);
+        });
+    });
+};
+
+module.exports.help = function() {
+    console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]) + ' [options]');
+    console.log('Build options :');
+    console.log('    --debug : Builds project in debug mode');
+    console.log('    --release : Builds project in release mode');
+    console.log('    --nobuild : Runs the currently built project without recompiling');
+    console.log('Deploy options :');
+    console.log('    --device : Will deploy the built project to a device');
+    console.log('    --emulator : Will deploy the built project to an emulator if one exists');
+    console.log('    --target=<target_id> : Installs to the target with the specified id.');
+    process.exit(0);
+};

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/start-emulator
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/start-emulator b/cordova-lib/spec-plugman/projects/android/cordova/lib/start-emulator
new file mode 100755
index 0000000..f96bdc3
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/start-emulator
@@ -0,0 +1,39 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var emulator = require('./emulator'),
+      args   = process.argv;
+
+var install_target;
+if(args.length > 2) {
+    if (args[2].substring(0, 9) == '--target=') {
+        install_target = args[2].substring(9, args[2].length);
+     } else {
+        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+        process.exit(2);
+     }
+}
+
+emulator.start(install_target).done(null, function(err) {
+    console.error('ERROR: ' + err);
+    process.exit(2);
+});
+

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/start-emulator.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/start-emulator.bat b/cordova-lib/spec-plugman/projects/android/cordova/lib/start-emulator.bat
new file mode 100644
index 0000000..9329d95
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/start-emulator.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+:: 
+:: http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0start-emulator"
+IF EXIST %script_path% (
+        node "%script_path%" %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'start-emulator' script in 'cordova\lib' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/log
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/log b/cordova-lib/spec-plugman/projects/android/cordova/log
new file mode 100755
index 0000000..47f0605
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/log
@@ -0,0 +1,36 @@
+#!/usr/bin/env node
+
+/*
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+*/
+
+var log  = require('./lib/log'),
+    reqs = require('./lib/check_reqs'),
+    args = process.argv;
+
+// Usage support for when args are given
+if(args.length > 2) {
+    log.help();
+} else {
+    reqs.run().done(function() {
+        return log.run();
+    }, function(err) {
+        console.error('ERROR: ' + err);
+        process.exit(2);
+    });
+}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/log.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/log.bat b/cordova-lib/spec-plugman/projects/android/cordova/log.bat
new file mode 100644
index 0000000..4b2b434
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/log.bat
@@ -0,0 +1,26 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+SET script_path="%~dp0log"
+IF EXIST %script_path% (
+        node %script_path% %*
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'log' script in 'cordova' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/loggingHelper.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/loggingHelper.js b/cordova-lib/spec-plugman/projects/android/cordova/loggingHelper.js
new file mode 100644
index 0000000..32b2ee0
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/loggingHelper.js
@@ -0,0 +1,18 @@
+var CordovaLogger = require('cordova-common').CordovaLogger;
+
+module.exports = {
+    adjustLoggerLevel: function (opts) {
+        if (opts instanceof Array) {
+            opts.silent = opts.indexOf('--silent') !== -1;
+            opts.verbose = opts.indexOf('--verbose') !== -1;
+        }
+
+        if (opts.silent) {
+            CordovaLogger.get().setLevel('error');
+        }
+
+        if (opts.verbose) {
+            CordovaLogger.get().setLevel('verbose');
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/nopt
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/nopt b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/nopt
new file mode 100755
index 0000000..3232d4c
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/nopt
@@ -0,0 +1,54 @@
+#!/usr/bin/env node
+var nopt = require("../lib/nopt")
+  , path = require("path")
+  , types = { num: Number
+            , bool: Boolean
+            , help: Boolean
+            , list: Array
+            , "num-list": [Number, Array]
+            , "str-list": [String, Array]
+            , "bool-list": [Boolean, Array]
+            , str: String
+            , clear: Boolean
+            , config: Boolean
+            , length: Number
+            , file: path
+            }
+  , shorthands = { s: [ "--str", "astring" ]
+                 , b: [ "--bool" ]
+                 , nb: [ "--no-bool" ]
+                 , tft: [ "--bool-list", "--no-bool-list", "--bool-list", "true" ]
+                 , "?": ["--help"]
+                 , h: ["--help"]
+                 , H: ["--help"]
+                 , n: [ "--num", "125" ]
+                 , c: ["--config"]
+                 , l: ["--length"]
+                 , f: ["--file"]
+                 }
+  , parsed = nopt( types
+                 , shorthands
+                 , process.argv
+                 , 2 )
+
+console.log("parsed", parsed)
+
+if (parsed.help) {
+  console.log("")
+  console.log("nopt cli tester")
+  console.log("")
+  console.log("types")
+  console.log(Object.keys(types).map(function M (t) {
+    var type = types[t]
+    if (Array.isArray(type)) {
+      return [t, type.map(function (type) { return type.name })]
+    }
+    return [t, type && type.name]
+  }).reduce(function (s, i) {
+    s[i[0]] = i[1]
+    return s
+  }, {}))
+  console.log("")
+  console.log("shorthands")
+  console.log(shorthands)
+}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/semver
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/semver b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/semver
new file mode 100755
index 0000000..c5f2e85
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/semver
@@ -0,0 +1,133 @@
+#!/usr/bin/env node
+// Standalone semver comparison program.
+// Exits successfully and prints matching version(s) if
+// any supplied version is valid and passes all tests.
+
+var argv = process.argv.slice(2)
+  , versions = []
+  , range = []
+  , gt = []
+  , lt = []
+  , eq = []
+  , inc = null
+  , version = require("../package.json").version
+  , loose = false
+  , identifier = undefined
+  , semver = require("../semver")
+  , reverse = false
+
+main()
+
+function main () {
+  if (!argv.length) return help()
+  while (argv.length) {
+    var a = argv.shift()
+    var i = a.indexOf('=')
+    if (i !== -1) {
+      a = a.slice(0, i)
+      argv.unshift(a.slice(i + 1))
+    }
+    switch (a) {
+      case "-rv": case "-rev": case "--rev": case "--reverse":
+        reverse = true
+        break
+      case "-l": case "--loose":
+        loose = true
+        break
+      case "-v": case "--version":
+        versions.push(argv.shift())
+        break
+      case "-i": case "--inc": case "--increment":
+        switch (argv[0]) {
+          case "major": case "minor": case "patch": case "prerelease":
+          case "premajor": case "preminor": case "prepatch":
+            inc = argv.shift()
+            break
+          default:
+            inc = "patch"
+            break
+        }
+        break
+      case "--preid":
+        identifier = argv.shift()
+        break
+      case "-r": case "--range":
+        range.push(argv.shift())
+        break
+      case "-h": case "--help": case "-?":
+        return help()
+      default:
+        versions.push(a)
+        break
+    }
+  }
+
+  versions = versions.filter(function (v) {
+    return semver.valid(v, loose)
+  })
+  if (!versions.length) return fail()
+  if (inc && (versions.length !== 1 || range.length))
+    return failInc()
+
+  for (var i = 0, l = range.length; i < l ; i ++) {
+    versions = versions.filter(function (v) {
+      return semver.satisfies(v, range[i], loose)
+    })
+    if (!versions.length) return fail()
+  }
+  return success(versions)
+}
+
+function failInc () {
+  console.error("--inc can only be used on a single version with no range")
+  fail()
+}
+
+function fail () { process.exit(1) }
+
+function success () {
+  var compare = reverse ? "rcompare" : "compare"
+  versions.sort(function (a, b) {
+    return semver[compare](a, b, loose)
+  }).map(function (v) {
+    return semver.clean(v, loose)
+  }).map(function (v) {
+    return inc ? semver.inc(v, inc, loose, identifier) : v
+  }).forEach(function (v,i,_) { console.log(v) })
+}
+
+function help () {
+  console.log(["SemVer " + version
+              ,""
+              ,"A JavaScript implementation of the http://semver.org/ specification"
+              ,"Copyright Isaac Z. Schlueter"
+              ,""
+              ,"Usage: semver [options] <version> [<version> [...]]"
+              ,"Prints valid versions sorted by SemVer precedence"
+              ,""
+              ,"Options:"
+              ,"-r --range <range>"
+              ,"        Print versions that match the specified range."
+              ,""
+              ,"-i --increment [<level>]"
+              ,"        Increment a version by the specified level.  Level can"
+              ,"        be one of: major, minor, patch, premajor, preminor,"
+              ,"        prepatch, or prerelease.  Default level is 'patch'."
+              ,"        Only one version may be specified."
+              ,""
+              ,"--preid <identifier>"
+              ,"        Identifier to be used to prefix premajor, preminor,"
+              ,"        prepatch or prerelease version increments."
+              ,""
+              ,"-l --loose"
+              ,"        Interpret versions and ranges loosely"
+              ,""
+              ,"Program exits successfully if any valid version satisfies"
+              ,"all supplied ranges, and prints all satisfying versions."
+              ,""
+              ,"If no satisfying versions are found, then exits failure."
+              ,""
+              ,"Versions are printed in ascending order, so supplying"
+              ,"multiple versions to the utility will just sort them."
+              ].join("\n"))
+}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/shjs
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/shjs b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/shjs
new file mode 100755
index 0000000..d239a7a
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/.bin/shjs
@@ -0,0 +1,51 @@
+#!/usr/bin/env node
+require('../global');
+
+if (process.argv.length < 3) {
+  console.log('ShellJS: missing argument (script name)');
+  console.log();
+  process.exit(1);
+}
+
+var args,
+  scriptName = process.argv[2];
+env['NODE_PATH'] = __dirname + '/../..';
+
+if (!scriptName.match(/\.js/) && !scriptName.match(/\.coffee/)) {
+  if (test('-f', scriptName + '.js'))
+    scriptName += '.js';
+  if (test('-f', scriptName + '.coffee'))
+    scriptName += '.coffee';
+}
+
+if (!test('-f', scriptName)) {
+  console.log('ShellJS: script not found ('+scriptName+')');
+  console.log();
+  process.exit(1);
+}
+
+args = process.argv.slice(3);
+
+for (var i = 0, l = args.length; i < l; i++) {
+  if (args[i][0] !== "-"){
+    args[i] = '"' + args[i] + '"'; // fixes arguments with multiple words
+  }
+}
+
+if (scriptName.match(/\.coffee$/)) {
+  //
+  // CoffeeScript
+  //
+  if (which('coffee')) {
+    exec('coffee ' + scriptName + ' ' + args.join(' '), { async: true });
+  } else {
+    console.log('ShellJS: CoffeeScript interpreter not found');
+    console.log();
+    process.exit(1);
+  }
+} else {
+  //
+  // JavaScript
+  //
+  exec('node ' + scriptName + ' ' + args.join(' '), { async: true });
+}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/LICENSE
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/LICENSE b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/LICENSE
new file mode 100644
index 0000000..19129e3
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/LICENSE
@@ -0,0 +1,15 @@
+The ISC License
+
+Copyright (c) Isaac Z. Schlueter and Contributors
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/README.md
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/README.md b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/README.md
new file mode 100644
index 0000000..99746fe
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/README.md
@@ -0,0 +1,23 @@
+# abbrev-js
+
+Just like [ruby's Abbrev](http://apidock.com/ruby/Abbrev).
+
+Usage:
+
+    var abbrev = require("abbrev");
+    abbrev("foo", "fool", "folding", "flop");
+    
+    // returns:
+    { fl: 'flop'
+    , flo: 'flop'
+    , flop: 'flop'
+    , fol: 'folding'
+    , fold: 'folding'
+    , foldi: 'folding'
+    , foldin: 'folding'
+    , folding: 'folding'
+    , foo: 'foo'
+    , fool: 'fool'
+    }
+
+This is handy for command-line scripts, or other cases where you want to be able to accept shorthands.

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/abbrev.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/abbrev.js b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/abbrev.js
new file mode 100644
index 0000000..7b1dc5d
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/abbrev.js
@@ -0,0 +1,61 @@
+module.exports = exports = abbrev.abbrev = abbrev
+
+abbrev.monkeyPatch = monkeyPatch
+
+function monkeyPatch () {
+  Object.defineProperty(Array.prototype, 'abbrev', {
+    value: function () { return abbrev(this) },
+    enumerable: false, configurable: true, writable: true
+  })
+
+  Object.defineProperty(Object.prototype, 'abbrev', {
+    value: function () { return abbrev(Object.keys(this)) },
+    enumerable: false, configurable: true, writable: true
+  })
+}
+
+function abbrev (list) {
+  if (arguments.length !== 1 || !Array.isArray(list)) {
+    list = Array.prototype.slice.call(arguments, 0)
+  }
+  for (var i = 0, l = list.length, args = [] ; i < l ; i ++) {
+    args[i] = typeof list[i] === "string" ? list[i] : String(list[i])
+  }
+
+  // sort them lexicographically, so that they're next to their nearest kin
+  args = args.sort(lexSort)
+
+  // walk through each, seeing how much it has in common with the next and previous
+  var abbrevs = {}
+    , prev = ""
+  for (var i = 0, l = args.length ; i < l ; i ++) {
+    var current = args[i]
+      , next = args[i + 1] || ""
+      , nextMatches = true
+      , prevMatches = true
+    if (current === next) continue
+    for (var j = 0, cl = current.length ; j < cl ; j ++) {
+      var curChar = current.charAt(j)
+      nextMatches = nextMatches && curChar === next.charAt(j)
+      prevMatches = prevMatches && curChar === prev.charAt(j)
+      if (!nextMatches && !prevMatches) {
+        j ++
+        break
+      }
+    }
+    prev = current
+    if (j === cl) {
+      abbrevs[current] = current
+      continue
+    }
+    for (var a = current.substr(0, j) ; j <= cl ; j ++) {
+      abbrevs[a] = current
+      a += current.charAt(j)
+    }
+  }
+  return abbrevs
+}
+
+function lexSort (a, b) {
+  return a === b ? 0 : a > b ? 1 : -1
+}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/package.json
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/package.json b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/package.json
new file mode 100644
index 0000000..42fa362
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/abbrev/package.json
@@ -0,0 +1,92 @@
+{
+  "_args": [
+    [
+      {
+        "raw": "abbrev@1",
+        "scope": null,
+        "escapedName": "abbrev",
+        "name": "abbrev",
+        "rawSpec": "1",
+        "spec": ">=1.0.0 <2.0.0",
+        "type": "range"
+      },
+      "/Users/steveng/repo/cordova/cordova-android/node_modules/nopt"
+    ]
+  ],
+  "_from": "abbrev@>=1.0.0 <2.0.0",
+  "_id": "abbrev@1.1.0",
+  "_inCache": true,
+  "_location": "/cordova-android/abbrev",
+  "_nodeVersion": "8.0.0-pre",
+  "_npmOperationalInternal": {
+    "host": "packages-12-west.internal.npmjs.com",
+    "tmp": "tmp/abbrev-1.1.0.tgz_1487054000015_0.9229173036292195"
+  },
+  "_npmUser": {
+    "name": "isaacs",
+    "email": "i@izs.me"
+  },
+  "_npmVersion": "4.3.0",
+  "_phantomChildren": {},
+  "_requested": {
+    "raw": "abbrev@1",
+    "scope": null,
+    "escapedName": "abbrev",
+    "name": "abbrev",
+    "rawSpec": "1",
+    "spec": ">=1.0.0 <2.0.0",
+    "type": "range"
+  },
+  "_requiredBy": [
+    "/cordova-android/nopt"
+  ],
+  "_resolved": "http://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
+  "_shasum": "d0554c2256636e2f56e7c2e5ad183f859428d81f",
+  "_shrinkwrap": null,
+  "_spec": "abbrev@1",
+  "_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/nopt",
+  "author": {
+    "name": "Isaac Z. Schlueter",
+    "email": "i@izs.me"
+  },
+  "bugs": {
+    "url": "https://github.com/isaacs/abbrev-js/issues"
+  },
+  "dependencies": {},
+  "description": "Like ruby's abbrev module, but in js",
+  "devDependencies": {
+    "tap": "^10.1"
+  },
+  "directories": {},
+  "dist": {
+    "shasum": "d0554c2256636e2f56e7c2e5ad183f859428d81f",
+    "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz"
+  },
+  "files": [
+    "abbrev.js"
+  ],
+  "gitHead": "7136d4d95449dc44115d4f78b80ec907724f64e0",
+  "homepage": "https://github.com/isaacs/abbrev-js#readme",
+  "license": "ISC",
+  "main": "abbrev.js",
+  "maintainers": [
+    {
+      "name": "isaacs",
+      "email": "i@izs.me"
+    }
+  ],
+  "name": "abbrev",
+  "optionalDependencies": {},
+  "readme": "ERROR: No README data found!",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://git@github.com/isaacs/abbrev-js.git"
+  },
+  "scripts": {
+    "postpublish": "git push origin --all; git push origin --tags",
+    "postversion": "npm publish",
+    "preversion": "npm test",
+    "test": "tap test.js --100"
+  },
+  "version": "1.1.0"
+}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/.jshintrc
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/.jshintrc b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/.jshintrc
new file mode 100644
index 0000000..248c542
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/.jshintrc
@@ -0,0 +1,4 @@
+{
+  "laxcomma": true,
+  "asi": true
+}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/.npmignore
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/.npmignore b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/.npmignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/.npmignore
@@ -0,0 +1 @@
+node_modules

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/History.md
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/History.md b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/History.md
new file mode 100644
index 0000000..aea8aaf
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/History.md
@@ -0,0 +1,23 @@
+
+0.3.1 / 2016-01-14
+==================
+
+  * add MIT LICENSE file (#23, @kasicka)
+  * preserve chaining after redundant style-method calls (#19, @drewblaisdell)
+  * package: add "license" field (#16, @BenjaminTsai)
+
+0.3.0 / 2014-05-09
+==================
+
+  * package: remove "test" script and "devDependencies"
+  * package: remove "engines" section
+  * pacakge: remove "bin" section
+  * package: beautify
+  * examples: remove `starwars` example (#15)
+  * Documented goto, horizontalAbsolute, and eraseLine methods in README.md (#12, @Jammerwoch)
+  * add `.jshintrc` file
+
+< 0.3.0
+=======
+
+  * Prehistoric

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/LICENSE
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/LICENSE b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/LICENSE
new file mode 100644
index 0000000..2ea4dc5
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/LICENSE
@@ -0,0 +1,24 @@
+(The MIT License)
+
+Copyright (c) 2012 Nathan Rajlich <na...@tootallnate.net>
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/README.md
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/README.md b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/README.md
new file mode 100644
index 0000000..6ce1940
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/README.md
@@ -0,0 +1,98 @@
+ansi.js
+=========
+### Advanced ANSI formatting tool for Node.js
+
+`ansi.js` is a module for Node.js that provides an easy-to-use API for
+writing ANSI escape codes to `Stream` instances. ANSI escape codes are used to do
+fancy things in a terminal window, like render text in colors, delete characters,
+lines, the entire window, or hide and show the cursor, and lots more!
+
+#### Features:
+
+ * 256 color support for the terminal!
+ * Make a beep sound from your terminal!
+ * Works with *any* writable `Stream` instance.
+ * Allows you to move the cursor anywhere on the terminal window.
+ * Allows you to delete existing contents from the terminal window.
+ * Allows you to hide and show the cursor.
+ * Converts CSS color codes and RGB values into ANSI escape codes.
+ * Low-level; you are in control of when escape codes are used, it's not abstracted.
+
+
+Installation
+------------
+
+Install with `npm`:
+
+``` bash
+$ npm install ansi
+```
+
+
+Example
+-------
+
+``` js
+var ansi = require('ansi')
+  , cursor = ansi(process.stdout)
+
+// You can chain your calls forever:
+cursor
+  .red()                 // Set font color to red
+  .bg.grey()             // Set background color to grey
+  .write('Hello World!') // Write 'Hello World!' to stdout
+  .bg.reset()            // Reset the bgcolor before writing the trailing \n,
+                         //      to avoid Terminal glitches
+  .write('\n')           // And a final \n to wrap things up
+
+// Rendering modes are persistent:
+cursor.hex('#660000').bold().underline()
+
+// You can use the regular logging functions, text will be green:
+console.log('This is blood red, bold text')
+
+// To reset just the foreground color:
+cursor.fg.reset()
+
+console.log('This will still be bold')
+
+// to go to a location (x,y) on the console
+// note: 1-indexed, not 0-indexed:
+cursor.goto(10, 5).write('Five down, ten over')
+
+// to clear the current line:
+cursor.horizontalAbsolute(0).eraseLine().write('Starting again')
+
+// to go to a different column on the current line:
+cursor.horizontalAbsolute(5).write('column five')
+
+// Clean up after yourself!
+cursor.reset()
+```
+
+
+License
+-------
+
+(The MIT License)
+
+Copyright (c) 2012 Nathan Rajlich &lt;nathan@tootallnate.net&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/beep/index.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/beep/index.js b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/beep/index.js
new file mode 100755
index 0000000..c1ec929
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/beep/index.js
@@ -0,0 +1,16 @@
+#!/usr/bin/env node
+
+/**
+ * Invokes the terminal "beep" sound once per second on every exact second.
+ */
+
+process.title = 'beep'
+
+var cursor = require('../../')(process.stdout)
+
+function beep () {
+  cursor.beep()
+  setTimeout(beep, 1000 - (new Date()).getMilliseconds())
+}
+
+setTimeout(beep, 1000 - (new Date()).getMilliseconds())

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/clear/index.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/clear/index.js b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/clear/index.js
new file mode 100755
index 0000000..6ac21ff
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/clear/index.js
@@ -0,0 +1,15 @@
+#!/usr/bin/env node
+
+/**
+ * Like GNU ncurses "clear" command.
+ * https://github.com/mscdex/node-ncurses/blob/master/deps/ncurses/progs/clear.c
+ */
+
+process.title = 'clear'
+
+function lf () { return '\n' }
+
+require('../../')(process.stdout)
+  .write(Array.apply(null, Array(process.stdout.getWindowSize()[1])).map(lf).join(''))
+  .eraseData(2)
+  .goto(1, 1)

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/cursorPosition.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/cursorPosition.js b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/cursorPosition.js
new file mode 100755
index 0000000..50f9644
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/cursorPosition.js
@@ -0,0 +1,32 @@
+#!/usr/bin/env node
+
+var tty = require('tty')
+var cursor = require('../')(process.stdout)
+
+// listen for the queryPosition report on stdin
+process.stdin.resume()
+raw(true)
+
+process.stdin.once('data', function (b) {
+  var match = /\[(\d+)\;(\d+)R$/.exec(b.toString())
+  if (match) {
+    var xy = match.slice(1, 3).reverse().map(Number)
+    console.error(xy)
+  }
+
+  // cleanup and close stdin
+  raw(false)
+  process.stdin.pause()
+})
+
+
+// send the query position request code to stdout
+cursor.queryPosition()
+
+function raw (mode) {
+  if (process.stdin.setRawMode) {
+    process.stdin.setRawMode(mode)
+  } else {
+    tty.setRawMode(mode)
+  }
+}

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/progress/index.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/progress/index.js b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/progress/index.js
new file mode 100644
index 0000000..d28dbda
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/examples/progress/index.js
@@ -0,0 +1,87 @@
+#!/usr/bin/env node
+
+var assert = require('assert')
+  , ansi = require('../../')
+
+function Progress (stream, width) {
+  this.cursor = ansi(stream)
+  this.delta = this.cursor.newlines
+  this.width = width | 0 || 10
+  this.open = '['
+  this.close = ']'
+  this.complete = '\u2588'
+  this.incomplete = '_'
+
+  // initial render
+  this.progress = 0
+}
+
+Object.defineProperty(Progress.prototype, 'progress', {
+    get: get
+  , set: set
+  , configurable: true
+  , enumerable: true
+})
+
+function get () {
+  return this._progress
+}
+
+function set (v) {
+  this._progress = Math.max(0, Math.min(v, 100))
+
+  var w = this.width - this.complete.length - this.incomplete.length
+    , n = w * (this._progress / 100) | 0
+    , i = w - n
+    , com = c(this.complete, n)
+    , inc = c(this.incomplete, i)
+    , delta = this.cursor.newlines - this.delta
+
+  assert.equal(com.length + inc.length, w)
+
+  if (delta > 0) {
+    this.cursor.up(delta)
+    this.delta = this.cursor.newlines
+  }
+
+  this.cursor
+    .horizontalAbsolute(0)
+    .eraseLine(2)
+    .fg.white()
+    .write(this.open)
+    .fg.grey()
+    .bold()
+    .write(com)
+    .resetBold()
+    .write(inc)
+    .fg.white()
+    .write(this.close)
+    .fg.reset()
+    .write('\n')
+}
+
+function c (char, length) {
+  return Array.apply(null, Array(length)).map(function () {
+    return char
+  }).join('')
+}
+
+
+
+
+// Usage
+var width = parseInt(process.argv[2], 10) || process.stdout.getWindowSize()[0] / 2
+  , p = new Progress(process.stdout, width)
+
+;(function tick () {
+  p.progress += Math.random() * 5
+  p.cursor
+    .eraseLine(2)
+    .write('Progress: ')
+    .bold().write(p.progress.toFixed(2))
+    .write('%')
+    .resetBold()
+    .write('\n')
+  if (p.progress < 100)
+    setTimeout(tick, 100)
+})()

http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/lib/ansi.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/lib/ansi.js b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/lib/ansi.js
new file mode 100644
index 0000000..b1714e3
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/node_modules/ansi/lib/ansi.js
@@ -0,0 +1,405 @@
+
+/**
+ * References:
+ *
+ *   - http://en.wikipedia.org/wiki/ANSI_escape_code
+ *   - http://www.termsys.demon.co.uk/vtansi.htm
+ *
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var emitNewlineEvents = require('./newlines')
+  , prefix = '\x1b[' // For all escape codes
+  , suffix = 'm'     // Only for color codes
+
+/**
+ * The ANSI escape sequences.
+ */
+
+var codes = {
+    up: 'A'
+  , down: 'B'
+  , forward: 'C'
+  , back: 'D'
+  , nextLine: 'E'
+  , previousLine: 'F'
+  , horizontalAbsolute: 'G'
+  , eraseData: 'J'
+  , eraseLine: 'K'
+  , scrollUp: 'S'
+  , scrollDown: 'T'
+  , savePosition: 's'
+  , restorePosition: 'u'
+  , queryPosition: '6n'
+  , hide: '?25l'
+  , show: '?25h'
+}
+
+/**
+ * Rendering ANSI codes.
+ */
+
+var styles = {
+    bold: 1
+  , italic: 3
+  , underline: 4
+  , inverse: 7
+}
+
+/**
+ * The negating ANSI code for the rendering modes.
+ */
+
+var reset = {
+    bold: 22
+  , italic: 23
+  , underline: 24
+  , inverse: 27
+}
+
+/**
+ * The standard, styleable ANSI colors.
+ */
+
+var colors = {
+    white: 37
+  , black: 30
+  , blue: 34
+  , cyan: 36
+  , green: 32
+  , magenta: 35
+  , red: 31
+  , yellow: 33
+  , grey: 90
+  , brightBlack: 90
+  , brightRed: 91
+  , brightGreen: 92
+  , brightYellow: 93
+  , brightBlue: 94
+  , brightMagenta: 95
+  , brightCyan: 96
+  , brightWhite: 97
+}
+
+
+/**
+ * Creates a Cursor instance based off the given `writable stream` instance.
+ */
+
+function ansi (stream, options) {
+  if (stream._ansicursor) {
+    return stream._ansicursor
+  } else {
+    return stream._ansicursor = new Cursor(stream, options)
+  }
+}
+module.exports = exports = ansi
+
+/**
+ * The `Cursor` class.
+ */
+
+function Cursor (stream, options) {
+  if (!(this instanceof Cursor)) {
+    return new Cursor(stream, options)
+  }
+  if (typeof stream != 'object' || typeof stream.write != 'function') {
+    throw new Error('a valid Stream instance must be passed in')
+  }
+
+  // the stream to use
+  this.stream = stream
+
+  // when 'enabled' is false then all the functions are no-ops except for write()
+  this.enabled = options && options.enabled
+  if (typeof this.enabled === 'undefined') {
+    this.enabled = stream.isTTY
+  }
+  this.enabled = !!this.enabled
+
+  // then `buffering` is true, then `write()` calls are buffered in
+  // memory until `flush()` is invoked
+  this.buffering = !!(options && options.buffering)
+  this._buffer = []
+
+  // controls the foreground and background colors
+  this.fg = this.foreground = new Colorer(this, 0)
+  this.bg = this.background = new Colorer(this, 10)
+
+  // defaults
+  this.Bold = false
+  this.Italic = false
+  this.Underline = false
+  this.Inverse = false
+
+  // keep track of the number of "newlines" that get encountered
+  this.newlines = 0
+  emitNewlineEvents(stream)
+  stream.on('newline', function () {
+    this.newlines++
+  }.bind(this))
+}
+exports.Cursor = Cursor
+
+/**
+ * Helper function that calls `write()` on the underlying Stream.
+ * Returns `this` instead of the write() return value to keep
+ * the chaining going.
+ */
+
+Cursor.prototype.write = function (data) {
+  if (this.buffering) {
+    this._buffer.push(arguments)
+  } else {
+    this.stream.write.apply(this.stream, arguments)
+  }
+  return this
+}
+
+/**
+ * Buffer `write()` calls into memory.
+ *
+ * @api public
+ */
+
+Cursor.prototype.buffer = function () {
+  this.buffering = true
+  return this
+}
+
+/**
+ * Write out the in-memory buffer.
+ *
+ * @api public
+ */
+
+Cursor.prototype.flush = function () {
+  this.buffering = false
+  var str = this._buffer.map(function (args) {
+    if (args.length != 1) throw new Error('unexpected args length! ' + args.length);
+    return args[0];
+  }).join('');
+  this._buffer.splice(0); // empty
+  this.write(str);
+  return this
+}
+
+
+/**
+ * The `Colorer` class manages both the background and foreground colors.
+ */
+
+function Colorer (cursor, base) {
+  this.current = null
+  this.cursor = cursor
+  this.base = base
+}
+exports.Colorer = Colorer
+
+/**
+ * Write an ANSI color code, ensuring that the same code doesn't get rewritten.
+ */
+
+Colorer.prototype._setColorCode = function setColorCode (code) {
+  var c = String(code)
+  if (this.current === c) return
+  this.cursor.enabled && this.cursor.write(prefix + c + suffix)
+  this.current = c
+  return this
+}
+
+
+/**
+ * Set up the positional ANSI codes.
+ */
+
+Object.keys(codes).forEach(function (name) {
+  var code = String(codes[name])
+  Cursor.prototype[name] = function () {
+    var c = code
+    if (arguments.length > 0) {
+      c = toArray(arguments).map(Math.round).join(';') + code
+    }
+    this.enabled && this.write(prefix + c)
+    return this
+  }
+})
+
+/**
+ * Set up the functions for the rendering ANSI codes.
+ */
+
+Object.keys(styles).forEach(function (style) {
+  var name = style[0].toUpperCase() + style.substring(1)
+    , c = styles[style]
+    , r = reset[style]
+
+  Cursor.prototype[style] = function () {
+    if (this[name]) return this
+    this.enabled && this.write(prefix + c + suffix)
+    this[name] = true
+    return this
+  }
+
+  Cursor.prototype['reset' + name] = function () {
+    if (!this[name]) return this
+    this.enabled && this.write(prefix + r + suffix)
+    this[name] = false
+    return this
+  }
+})
+
+/**
+ * Setup the functions for the standard colors.
+ */
+
+Object.keys(colors).forEach(function (color) {
+  var code = colors[color]
+
+  Colorer.prototype[color] = function () {
+    this._setColorCode(this.base + code)
+    return this.cursor
+  }
+
+  Cursor.prototype[color] = function () {
+    return this.foreground[color]()
+  }
+})
+
+/**
+ * Makes a beep sound!
+ */
+
+Cursor.prototype.beep = function () {
+  this.enabled && this.write('\x07')
+  return this
+}
+
+/**
+ * Moves cursor to specific position
+ */
+
+Cursor.prototype.goto = function (x, y) {
+  x = x | 0
+  y = y | 0
+  this.enabled && this.write(prefix + y + ';' + x + 'H')
+  return this
+}
+
+/**
+ * Resets the color.
+ */
+
+Colorer.prototype.reset = function () {
+  this._setColorCode(this.base + 39)
+  return this.cursor
+}
+
+/**
+ * Resets all ANSI formatting on the stream.
+ */
+
+Cursor.prototype.reset = function () {
+  this.enabled && this.write(prefix + '0' + suffix)
+  this.Bold = false
+  this.Italic = false
+  this.Underline = false
+  this.Inverse = false
+  this.foreground.current = null
+  this.background.current = null
+  return this
+}
+
+/**
+ * Sets the foreground color with the given RGB values.
+ * The closest match out of the 216 colors is picked.
+ */
+
+Colorer.prototype.rgb = function (r, g, b) {
+  var base = this.base + 38
+    , code = rgb(r, g, b)
+  this._setColorCode(base + ';5;' + code)
+  return this.cursor
+}
+
+/**
+ * Same as `cursor.fg.rgb(r, g, b)`.
+ */
+
+Cursor.prototype.rgb = function (r, g, b) {
+  return this.foreground.rgb(r, g, b)
+}
+
+/**
+ * Accepts CSS color codes for use with ANSI escape codes.
+ * For example: `#FF000` would be bright red.
+ */
+
+Colorer.prototype.hex = function (color) {
+  return this.rgb.apply(this, hex(color))
+}
+
+/**
+ * Same as `cursor.fg.hex(color)`.
+ */
+
+Cursor.prototype.hex = function (color) {
+  return this.foreground.hex(color)
+}
+
+
+// UTIL FUNCTIONS //
+
+/**
+ * Translates a 255 RGB value to a 0-5 ANSI RGV value,
+ * then returns the single ANSI color code to use.
+ */
+
+function rgb (r, g, b) {
+  var red = r / 255 * 5
+    , green = g / 255 * 5
+    , blue = b / 255 * 5
+  return rgb5(red, green, blue)
+}
+
+/**
+ * Turns rgb 0-5 values into a single ANSI color code to use.
+ */
+
+function rgb5 (r, g, b) {
+  var red = Math.round(r)
+    , green = Math.round(g)
+    , blue = Math.round(b)
+  return 16 + (red*36) + (green*6) + blue
+}
+
+/**
+ * Accepts a hex CSS color code string (# is optional) and
+ * translates it into an Array of 3 RGB 0-255 values, which
+ * can then be used with rgb().
+ */
+
+function hex (color) {
+  var c = color[0] === '#' ? color.substring(1) : color
+    , r = c.substring(0, 2)
+    , g = c.substring(2, 4)
+    , b = c.substring(4, 6)
+  return [parseInt(r, 16), parseInt(g, 16), parseInt(b, 16)]
+}
+
+/**
+ * Turns an array-like object into a real array.
+ */
+
+function toArray (a) {
+  var i = 0
+    , l = a.length
+    , rtn = []
+  for (; i<l; i++) {
+    rtn.push(a[i])
+  }
+  return rtn
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org