http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/58047a3d/template/cordova/lib/build.js
----------------------------------------------------------------------
diff --git a/template/cordova/lib/build.js b/template/cordova/lib/build.js
index 0c065da..e8586f3 100644
--- a/template/cordova/lib/build.js
+++ b/template/cordova/lib/build.js
@@ -17,20 +17,21 @@
        under the License.
 */
 
-var Q     = require('q'),
-    path  = require('path'),
-    nopt  = require('nopt'),
-    shell = require('shelljs'),
-    utils = require('./utils'),
-    et    = require('elementtree'),
-    prepare = require('./prepare'),
-    package = require('./package'),
-    MSBuildTools = require('./MSBuildTools'),
-    ConfigParser = require('./ConfigParser'),
-    fs = require('fs');
-
-// Platform project root folder
-var ROOT = path.join(__dirname, '..', '..');
+var Q     = require('q');
+var path  = require('path');
+var nopt  = require('nopt');
+var shell = require('shelljs');
+var utils = require('./utils');
+var prepare = require('./prepare');
+var package = require('./package');
+var MSBuildTools = require('./MSBuildTools');
+var AppxManifest = require('./AppxManifest');
+var ConfigParser = require('./ConfigParser');
+var fs = require('fs');
+
+var events = require('cordova-common').events;
+var CordovaError = require('cordova-common').CordovaError;
+
 var projFiles = {
     phone: 'CordovaApp.Phone.jsproj',
     win: 'CordovaApp.Windows.jsproj',
@@ -44,72 +45,35 @@ var projFilesToManifests = {
     'CordovaApp.Windows10.jsproj': 'package.windows10.appxmanifest'
 };
 
+var ROOT = path.resolve(__dirname, '../..');
+
 // builds cordova-windows application with parameters provided.
 // See 'help' function for args list
-module.exports.run = function run (argv) {
+module.exports.run = function run (buildOptions) {
+
+    ROOT = this.root || ROOT;
 
-    if (!utils.isCordovaProject(ROOT)){
-        return Q.reject('Could not find project at ' + ROOT);
+    if (!utils.isCordovaProject(this.root)){
+        return Q.reject(new CordovaError('Could not find project at ' + 
this.root));
     }
 
-    return Q.all([parseAndValidateArgs(argv), 
MSBuildTools.findAllAvailableVersions()])
-        .spread(function(buildConfig, msbuildTools) {
-            // Apply build related configs
-            prepare.updateBuildConfig(buildConfig);
-            if (buildConfig.publisherId) {
-                updateManifestWithPublisher(msbuildTools, buildConfig);
-            }
-            // bug: Windows 8 build fails on a system with MSBuild 14 on it.
-            // Don't regress, make sure MSBuild 4 is selected for a Windows 8 
build.
-            cleanIntermediates();
-            return buildTargets(msbuildTools, buildConfig).then(function(pkg) {
-                console.log(' BUILD OUTPUT: ' + pkg.appx);
-                return pkg;
-            });
-        }, function(error) {
-            return Q.reject(error);
-        });
-};
+    var buildConfig = parseAndValidateArgs(buildOptions);
 
-// help/usage function
-module.exports.help = function help() {
-    console.log('');
-    console.log('Usage: build [--debug | --release] [--phone | --win] 
[--bundle]');
-    console.log('             [--archs="<list of architectures...>"');
-    console.log('             [--packageCertificateKeyFile="key path"]');
-    console.log('             [--packageThumbprint="thumbprint"] 
[--publisherId]');
-    console.log('             [--buildConfig="file path"]');
-    console.log('    --help                      : Displays this dialog.');
-    console.log('    --debug                     : Builds project in debug 
mode. (Default).');
-    console.log('    --release  (-r)             : Builds project in release 
mode.');
-    console.log('    --phone, --win              : Specifies, what type of 
project to build.');
-    console.log('    --bundle                    : Tells the compiler to 
create a .appxbundle.');
-    console.log('                                  Bundling is disabled when 
`anycpu` is built.');
-    console.log('    --archs                     : Builds project binaries for 
specific chip');
-    console.log('                                  architectures (`anycpu`, 
`arm`, `x86`, `x64`).');
-    console.log('                                  Separate multiple choices 
with spaces and if');
-    console.log('                                  passing multiple choices, 
enclose with " ".');
-    console.log('    --appx=<8.1-win|8.1-phone|uap>');
-    console.log('                                : Overrides 
windows-target-version to build');
-    console.log('                                  Windows 8.1, Windows Phone 
8.1, or');
-    console.log('                                  Windows 10 Universal.');
-    console.log('    --packageCertificateKeyFile : Builds the project using 
provided certificate.');
-    console.log('    --packageThumbprint         : Thumbprint associated with 
the certificate.');
-    console.log('    --publisherId               : Sets publisher id field in 
manifest.');
-    console.log('    --buildConfig               : Sets build settings from 
configuration file.');
-    console.log('');
-    console.log('examples:');
-    console.log('    build ');
-    console.log('    build --debug');
-    console.log('    build --release');
-    console.log('    build --release --archs="arm x86" --bundle');
-    console.log('    build --appx=8.1-phone -r');
-    console.log('    build 
--packageCertificateKeyFile="CordovaApp_TemporaryKey.pfx"');
-    console.log('    build --publisherId="CN=FakeCorp, C=US"');
-    console.log('    build --buildConfig="build.json"');
-    console.log('');
-
-    process.exit(0);
+    return MSBuildTools.findAllAvailableVersions()
+    .then(function(msbuildTools) {
+        // Apply build related configs
+        prepare.updateBuildConfig(buildConfig);
+        if (buildConfig.publisherId) {
+            updateManifestWithPublisher(msbuildTools, buildConfig);
+        }
+        // bug: Windows 8 build fails on a system with MSBuild 14 on it.
+        // Don't regress, make sure MSBuild 4 is selected for a Windows 8 
build.
+        cleanIntermediates();
+        return buildTargets(msbuildTools, buildConfig).then(function(pkg) {
+            events.emit('verbose', ' BUILD OUTPUT: ' + pkg.appx);
+            return pkg;
+        });
+    });
 };
 
 // returns list of projects to be built based on config.xml and additional 
parameters (-appx)
@@ -125,11 +89,11 @@ module.exports.getBuildTargets  = function(isWinSwitch, 
isPhoneSwitch, projOverr
             case 'uap':
                 return [projFiles.win10];
             default:
-                console.warn('Unrecognized --appx parameter passed to build: 
"' + projOverride + '", ignoring.');
+                events.emit('warn', 'Unrecognized --appx parameter passed to 
build: "' + projOverride + '", ignoring.');
                 break;
         }
     }
-    
+
     var configXML = new ConfigParser(path.join(ROOT, 'config.xml'));
     var targets = [];
     var noSwitches = !(isPhoneSwitch || isWinSwitch);
@@ -150,7 +114,7 @@ module.exports.getBuildTargets  = function(isWinSwitch, 
isPhoneSwitch, projOverr
             targets.push(projFiles.win10);
             break;
         default:
-            throw new Error('Unsupported windows-target-version value: ' + 
windowsTargetVersion);
+            throw new CordovaError('Unsupported windows-target-version value: 
' + windowsTargetVersion);
         }
     }
 
@@ -178,122 +142,130 @@ module.exports.getBuildTargets  = function(isWinSwitch, 
isPhoneSwitch, projOverr
     return targets;
 };
 
-function parseAndValidateArgs(argv) {
-    return Q.promise(function(resolve, reject) {
-        // parse and validate args
-        var args = nopt({
-            'debug': Boolean,
-            'release': Boolean,
-            'archs': [String],
-            'appx': String,
-            'phone': Boolean,
-            'win': Boolean,
-            'bundle': Boolean,
-            'packageCertificateKeyFile': String,
-            'packageThumbprint': String,
-            'publisherId': String,
-            'buildConfig': String
-            }, {'-r': '--release'}, argv);
-
-        var config = {};
-        var buildConfig = {};
-
-        // Validate args
-        if (args.debug && args.release) {
-            reject('Only one of "debug"/"release" options should be 
specified');
-            return;
-        }
-        if (args.phone && args.win) {
-            reject('Only one of "phone"/"win" options should be specified');
-            return;
-        }
+/**
+ * Parses and validates buildOptions object and platform-specific CLI 
arguments,
+ *   provided via argv field
+ *
+ * @param   {Object}  [options]  An options object. If not specified, result
+ *   will be populated with default values.
+ *
+ * @return  {Object}             Build configuration, used by other methods
+ */
+function parseAndValidateArgs(options) {
+    // parse and validate args
+    var args = nopt({
+        'archs': [String],
+        'appx': String,
+        'phone': Boolean,
+        'win': Boolean,
+        'bundle': Boolean,
+        'packageCertificateKeyFile': String,
+        'packageThumbprint': String,
+        'publisherId': String,
+        'buildConfig': String
+    }, {}, options.argv, 0);
+
+    var config = {};
+    var buildConfig = {};
+
+    // Validate args
+    if (options.debug && options.release) {
+        throw new CordovaError('Only one of "debug"/"release" options should 
be specified');
+    }
 
-        // get build options/defaults
-        config.buildType = args.release ? 'release' : 'debug';
-        config.buildArchs = args.archs ? args.archs.split(' ') : ['anycpu'];
-        config.phone = args.phone ? true : false;
-        config.win = args.win ? true : false;
-        config.projVerOverride = args.appx;
-        // only set config.bundle if architecture is not anycpu
-        if (args.bundle) {
-            if ((config.buildArchs.indexOf('anycpu') > -1 || 
config.buildArchs.indexOf('any cpu') > -1) && config.buildArchs.length > 1) {
-                // Not valid to bundle anycpu with cpu-specific architectures. 
 warn, then don't bundle
-                console.warn('Warning: anycpu and CPU-specific architectures 
were selected. This is not valid');
-                console.warn(' when enabling bundling with --bundle.  
Disabling bundling for this build.');
-            } else {
-                config.bundle = true;
-            }
-        }
+    if (args.phone && args.win) {
+        throw new CordovaError('Only one of "phone"/"win" options should be 
specified');
+    }
 
-        // if build.json is provided, parse it
-        var buildConfigPath = args.buildConfig;
-        if (buildConfigPath) {
-            buildConfig = parseBuildConfig(buildConfigPath, config);
-            for (var prop in buildConfig) { config[prop] = buildConfig[prop]; }
+    // get build options/defaults
+    config.buildType = options.release ? 'release' : 'debug';
+    config.buildArchs = args.archs ? args.archs.split(' ') : ['anycpu'];
+    config.phone = args.phone ? true : false;
+    config.win = args.win ? true : false;
+    config.projVerOverride = args.appx;
+    // only set config.bundle if architecture is not anycpu
+    if (args.bundle) {
+        if (config.buildArchs.length > 1 && 
(config.buildArchs.indexOf('anycpu') > -1 || config.buildArchs.indexOf('any 
cpu') > -1)) {
+            // Not valid to bundle anycpu with cpu-specific architectures.  
warn, then don't bundle
+            events.emit('warn', '"anycpu" and CPU-specific architectures were 
selected. ' +
+                'This is not valid when enabling bundling with --bundle. 
Disabling bundling for this build.');
+        } else {
+            config.bundle = true;
         }
+    }
 
-        // CLI arguments override build.json config
-        if (args.packageCertificateKeyFile) {
-            args.packageCertificateKeyFile = path.resolve(process.cwd(), 
args.packageCertificateKeyFile);
-            config.packageCertificateKeyFile = args.packageCertificateKeyFile;
-        }
+    // if build.json is provided, parse it
+    var buildConfigPath = args.buildConfig;
+    if (buildConfigPath) {
+        buildConfig = parseBuildConfig(buildConfigPath, config.buildType);
+        for (var prop in buildConfig) { config[prop] = buildConfig[prop]; }
+    }
 
-        config.packageThumbprint = config.packageThumbprint || 
args.packageThumbprint;
-        config.publisherId = config.publisherId || args.publisherId;
-        resolve(config);
-    });
+    // CLI arguments override build.json config
+    if (args.packageCertificateKeyFile) {
+        args.packageCertificateKeyFile = path.resolve(process.cwd(), 
args.packageCertificateKeyFile);
+        config.packageCertificateKeyFile = args.packageCertificateKeyFile;
+    }
+
+    config.packageThumbprint = config.packageThumbprint || 
args.packageThumbprint;
+    config.publisherId = config.publisherId || args.publisherId;
+
+    return config;
 }
 
-function parseBuildConfig(buildConfigPath, config) {
+function parseBuildConfig(buildConfigPath, buildType) {
     var buildConfig, result = {};
-    console.log('Reading build config file: '+ buildConfigPath);
+    events.emit('verbose', 'Reading build config file: '+ buildConfigPath);
     try {
         var contents = fs.readFileSync(buildConfigPath, 'utf8');
         buildConfig = JSON.parse(contents);
     } catch (e) {
         if (e.code === 'ENOENT') {
-            throw Error('Specified build config file does not exist: ' + 
buildConfigPath);
-        } else {
+            throw new CordovaError('Specified build config file does not 
exist: ' + buildConfigPath);
+        }
+        else {
             throw e;
         }
     }
 
-    if (buildConfig.windows && buildConfig.windows[config.buildType]) {
-        var windowsInfo = buildConfig.windows[config.buildType];
+    if (!(buildConfig.windows && buildConfig.windows[buildType])) return {};
 
-        // If provided assume it's a relative path
-        if(windowsInfo.packageCertificateKeyFile) {
-            var buildPath = path.dirname(fs.realpathSync(buildConfigPath));
-            result.packageCertificateKeyFile = path.resolve(buildPath, 
windowsInfo.packageCertificateKeyFile);
-        }
+    var windowsInfo = buildConfig.windows[buildType];
 
-        if(windowsInfo.packageThumbprint) {
-            result.packageThumbprint = windowsInfo.packageThumbprint;
-        }
+    // If provided assume it's a relative path
+    if(windowsInfo.packageCertificateKeyFile) {
+        var buildPath = path.dirname(fs.realpathSync(buildConfigPath));
+        result.packageCertificateKeyFile = path.resolve(buildPath, 
windowsInfo.packageCertificateKeyFile);
+    }
 
-        if(windowsInfo.publisherId) {
-            // Quickly validate publisherId
-            var publisherRegexStr = 
'(CN|L|O|OU|E|C|S|STREET|T|G|I|SN|DC|SERIALNUMBER|(OID\\.(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))+))='
 +
-                                    '(([^,+="<>#;])+|".*")(, (' +
-                                    
'(CN|L|O|OU|E|C|S|STREET|T|G|I|SN|DC|SERIALNUMBER|(OID\\.(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))+))='
 +
-                                    '(([^,+="<>#;])+|".*")))*';
+    if(windowsInfo.packageThumbprint) {
+        result.packageThumbprint = windowsInfo.packageThumbprint;
+    }
 
-            var publisherRegex = new RegExp(publisherRegexStr);
+    if(windowsInfo.publisherId) {
+        // Quickly validate publisherId
+        var publisherRegexStr = 
'(CN|L|O|OU|E|C|S|STREET|T|G|I|SN|DC|SERIALNUMBER|(OID\\.(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))+))='
 +
+                                '(([^,+="<>#;])+|".*")(, (' +
+                                
'(CN|L|O|OU|E|C|S|STREET|T|G|I|SN|DC|SERIALNUMBER|(OID\\.(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))+))='
 +
+                                '(([^,+="<>#;])+|".*")))*';
 
-            if (!publisherRegex.test(windowsInfo.publisherId)) {
-                throw Error('Invalid publisher id: ' + 
windowsInfo.publisherId);
-            }
+        var publisherRegex = new RegExp(publisherRegexStr);
 
-            result.publisherId = windowsInfo.publisherId;
+        if (!publisherRegex.test(windowsInfo.publisherId)) {
+            throw new CordovaError('Invalid publisher id: ' + 
windowsInfo.publisherId);
         }
+
+        result.publisherId = windowsInfo.publisherId;
     }
 
     return result;
 }
 
-// Note: This function is very narrow and only writes to the app manifest if 
an update is done.  See CB-9450 for the 
+// Note: This function is very narrow and only writes to the app manifest if 
an update is done.  See CB-9450 for the
 // reasoning of why this is the case.
 function updateManifestWithPublisher(allMsBuildVersions, config) {
+    if (!config.publisherId) return;
+
     var selectedBuildTargets = getBuildTargets(config);
     var msbuild = getMsBuildForTargets(selectedBuildTargets, config, 
allMsBuildVersions);
     var myBuildTargets = filterSupportedTargets(selectedBuildTargets, msbuild);
@@ -302,30 +274,20 @@ function updateManifestWithPublisher(allMsBuildVersions, 
config) {
     });
     manifestFiles.forEach(function(file) {
         var manifestPath = path.join(ROOT, file);
-        var contents = fs.readFileSync(manifestPath, 'utf-8');
-        if (!contents) {
-            return;
-        }
-
-        // Skip BOM
-        contents = contents.substring(contents.indexOf('<'));
-        var manifest =  new et.ElementTree(et.XML(contents));
-        var identityNode = manifest.find('.//Identity');
-        if (config.publisherId && config.publisherId !== 
identityNode.attrib.Publisher) {
-            identityNode.attrib.Publisher = config.publisherId;
-            fs.writeFileSync(manifestPath, manifest.write({indent: 4}), 
'utf-8');
-        }
+        AppxManifest.get(manifestPath)
+            .getIdentity().setPublisher(config.publisherId)
+            .write();
     });
 }
 
 function buildTargets(allMsBuildVersions, config) {
     // filter targets to make sure they are supported on this development 
machine
     var selectedBuildTargets = getBuildTargets(config);
-    var msbuild = getMsBuildForTargets(selectedBuildTargets, config, 
allMsBuildVersions); 
+    var msbuild = getMsBuildForTargets(selectedBuildTargets, config, 
allMsBuildVersions);
     if (!msbuild) {
-        return Q.reject('No valid MSBuild was detected for the selected 
target.');
+        return Q.reject(new CordovaError('No valid MSBuild was detected for 
the selected target.'));
     }
-    console.log('MSBuildToolsPath: ' + msbuild.path);
+    events.emit('vebose', 'Using MSBuild v' + msbuild.version + ' from ' + 
msbuild.path);
     var myBuildTargets = filterSupportedTargets(selectedBuildTargets, msbuild);
 
     var buildConfigs = [];
@@ -334,7 +296,7 @@ function buildTargets(allMsBuildVersions, config) {
     var shouldBundle = !!config.bundle;
     if (myBuildTargets.indexOf(projFiles.win80) > -1) {
         if (shouldBundle) {
-            console.warn('Warning: Bundling is disabled because a Windows 8 
project was detected.');
+            events.emit('warn', 'Bundling is disabled because a Windows 8 
project was detected.');
         }
         shouldBundle = false;
     }
@@ -400,8 +362,7 @@ function clearIntermediatesAndGetPackage(bundleTerms, 
config, hasAnyCpu) {
     // However, that generates intermediate bundles, like 
"CordovaApp.Windows10_0.0.1.0_x64.appxbundle"
     // We need to clear the intermediate bundles, or else "cordova run" will 
fail because of too
     // many .appxbundle files.
-
-    console.log('Clearing intermediates...');
+    events.emit('verbose', 'Clearing intermediates...');
     var appPackagesPath = path.join(ROOT, 'AppPackages');
     var childDirectories = shell.ls(path.join(appPackagesPath, 
'*')).map(function(pathName) {
         return { path: pathName, stats: fs.statSync(pathName) };
@@ -422,7 +383,7 @@ function clearIntermediatesAndGetPackage(bundleTerms, 
config, hasAnyCpu) {
     if (hasAnyCpu) {
         archSearchString = 'AnyCPU' + (config.buildType === 'debug' ? '_debug' 
: '') + '.appxbundle';
     }
-    
+
     var filesToDelete = shell.ls(path.join(outputDirectory.path, 
'*.appx*')).filter(function(appxbundle) {
         var isMatch = appxbundle.indexOf(archSearchString) === -1;
         if (!isMatch) {
@@ -498,7 +459,7 @@ function getBuildTargets(buildConfig) {
                 targets = [projFiles.win10];
                 break;
             default:
-                console.warn('Unrecognized --appx parameter passed to build: 
"' + buildConfig.projVerOverride + '", ignoring.');
+                events.emit('warn', 'Unrecognized --appx parameter passed to 
build: "' + buildConfig.projVerOverride + '", ignoring.');
                 break;
         }
     }
@@ -528,7 +489,8 @@ function getBuildTargets(buildConfig) {
 }
 
 function getMsBuildForTargets(selectedTargets, buildConfig, 
allMsBuildVersions) {
-    var availableVersions = allMsBuildVersions.reduce(function(obj, 
msbuildVersion) {
+    var availableVersions = allMsBuildVersions
+    .reduce(function(obj, msbuildVersion) {
         obj[msbuildVersion.version] = msbuildVersion;
         return obj;
     }, {});
@@ -538,7 +500,7 @@ function getMsBuildForTargets(selectedTargets, buildConfig, 
allMsBuildVersions)
     if (selectedTargets.indexOf(projFiles.win80) > -1) {
         // building Windows 8; prefer 4.0, unless phone is also present, in 
which case prefer 12
         // prefer 12.  If not present, can't build this; error in the 
filterSupportedTargets function
-        result = availableVersions['12.0'] || availableVersions['4.0']; 
+        result = availableVersions['12.0'] || availableVersions['4.0'];
     } else {
         // 14 can build Windows 10, Windows 8.1, and Windows Phone 8.1, so 
resolve to 14 if available, else 12
         result = (availableVersions['14.0'] || availableVersions['12.0']);
@@ -565,7 +527,7 @@ function msBuild14TargetsFilter(target) {
 
 function filterSupportedTargets (targets, msbuild) {
     if (!targets || targets.length === 0) {
-        console.warn('\r\nNo build targets are specified.');
+        events.emit('warn', 'No build targets are specified.');
         return [];
     }
 
@@ -577,15 +539,16 @@ function filterSupportedTargets (targets, msbuild) {
 
     var filter = targetFilters[msbuild.version];
     if (!filter) {
-        console.warn('Unsupported msbuild version "' + msbuild.version + '", 
aborting.');
+        events.emit('warn', 'Unsupported msbuild version "' + msbuild.version 
+ '", aborting.');
         return [];
     }
 
     var supportedTargets = targets.filter(filter);
     // unsupported targets have been detected
     if (supportedTargets.length !== targets.length) {
-        console.warn('Warning: Not all desired build targets are compatible 
with the current build environment.');
-        console.warn('Please install Visual Studio 2015 for Windows 8.1 and 
Windows 10, or Visual Studio 2013 Update 2 for Windows 8 and 8.1.');
+        events.emit('warn', 'Not all desired build targets are compatible with 
the current build environment. ' +
+            'Please install Visual Studio 2015 for Windows 8.1 and Windows 10, 
' +
+            'or Visual Studio 2013 Update 2 for Windows 8 and 8.1.');
     }
     return supportedTargets;
 }
@@ -596,3 +559,13 @@ function cleanIntermediates() {
         shell.rm('-rf', buildPath);
     }
 }
+
+// cleans the project, removes AppPackages and build folders.
+module.exports.clean = function () {
+    var projectPath = this.root;
+    ['AppPackages', 'build']
+    .forEach(function(dir) {
+        shell.rm('-rf', path.join(projectPath, dir));
+    });
+    return Q.resolve();
+};

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/58047a3d/template/cordova/lib/deployment.js
----------------------------------------------------------------------
diff --git a/template/cordova/lib/deployment.js 
b/template/cordova/lib/deployment.js
index 9ba17ad..a728d11 100644
--- a/template/cordova/lib/deployment.js
+++ b/template/cordova/lib/deployment.js
@@ -17,40 +17,17 @@
        under the License.
 */
 
+/*jshint -W069 */
+
 var Q     = require('q'),
     fs    = require('fs'),
-    /* jshint ignore:start */ // 'path' only used in ignored blocks
-    path  = require('path'),
-    /* jshint ignore:end */
-    proc  = require('child_process');
+    path  = require('path');
+var spawn = require('cordova-common').superspawn.spawn;
+var events = require('cordova-common').events;
 
 var E_INVALIDARG = 2147942487;
 
-// neither 'exec' nor 'spawn' was sufficient because we need to pass arguments 
via spawn
-// but also need to be able to capture stdout / stderr
-function run(cmd, args, opt_cwd) {
-    var d = Q.defer();
-    try {
-        var child = proc.spawn(cmd, args, {cwd: opt_cwd, maxBuffer: 1024000});
-        var stdout = '', stderr = '';
-        child.stdout.on('data', function(s) { stdout += s; });
-        child.stderr.on('data', function(s) { stderr += s; });
-        child.on('exit', function(code) {
-            if (code) {
-                d.reject({ message: stderr, code: code, toString: function() { 
return stderr; }});
-            } else {
-                d.resolve(stdout);
-            }
-        });
-    } catch(e) {
-        console.error('error caught: ' + e);
-        d.reject(e);
-    }
-    return d.promise;
-}
-
 function DeploymentTool() {
-
 }
 
 /**
@@ -148,10 +125,8 @@ function AppDeployCmdTool(targetOsVersion) {
     DeploymentTool.call(this);
     this.targetOsVersion = targetOsVersion;
 
-    /* jshint ignore:start */ /* Ignore jshint to use dot notation for 2nd 
process.env access for consistency */
     var programFilesPath = process.env['ProgramFiles(x86)'] || 
process.env['ProgramFiles'];
     this.path = path.join(programFilesPath, 'Microsoft SDKs', 'Windows Phone', 
'v' + this.targetOsVersion, 'Tools', 'AppDeploy', 'AppDeployCmd.exe');
-    /* jshint ignore:end */
 }
 
 AppDeployCmdTool.prototype = Object.create(DeploymentTool.prototype);
@@ -164,7 +139,7 @@ AppDeployCmdTool.prototype.enumerateDevices = function() {
     // [(line), 9, 'Emulator 8.1 720P 4.7 inch']
     // Expansion is: space, index, spaces, name
     var LINE_TEST = /^\s(\d+?)\s+(.+?)$/m;
-    return run(that.path, ['/EnumerateDevices']).then(function(result) {
+    return spawn(that.path, ['/EnumerateDevices']).then(function(result) {
         var lines = result.split('\n');
         var matchedLines = lines.filter(function(line) {
             return LINE_TEST.test(line);
@@ -205,12 +180,12 @@ AppDeployCmdTool.prototype.installAppPackage = 
function(pathToAppxPackage, targe
     }
 
     var that = this;
-    var result = run(this.path, [command, pathToAppxPackage, '/targetdevice:' 
+ targetDevice.__shorthand]);
+    var result = spawn(this.path, [command, pathToAppxPackage, 
'/targetdevice:' + targetDevice.__shorthand]);
     if (targetDevice.type === 'emulator') {
         result = result.then(null, function(e) {
             // CB-9482: AppDeployCmd also reports E_INVALIDARG during this 
process.  If so, try to repeat.
             if (e.code === E_INVALIDARG) {
-                return run(that.path, [command, pathToAppxPackage, 
'/targetdevice:' + targetDevice.__shorthand]);
+                return spawn(that.path, [command, pathToAppxPackage, 
'/targetdevice:' + targetDevice.__shorthand]);
             }
 
             throw e;
@@ -227,11 +202,11 @@ AppDeployCmdTool.prototype.uninstallAppPackage = 
function(packageInfo, targetDev
     //  state, it allows install to proceed.  (Install will fail if there is a 
legitimate 
     //  uninstall failure such as due to no device).  
     var assureSuccess = function() {};
-    return run(this.path, ['/uninstall', packageInfo, '/targetdevice:' + 
targetDevice.__shorthand]).then(assureSuccess, assureSuccess);
+    return spawn(this.path, ['/uninstall', packageInfo, '/targetdevice:' + 
targetDevice.__shorthand]).then(assureSuccess, assureSuccess);
 };
 
 AppDeployCmdTool.prototype.launchApp = function(packageInfo, targetDevice) {
-    return run(this.path, ['/launch', packageInfo, '/targetdevice:' + 
targetDevice.__shorthand]);
+    return spawn(this.path, ['/launch', packageInfo, '/targetdevice:' + 
targetDevice.__shorthand]);
 };
 
 function WinAppDeployCmdTool(targetOsVersion) {
@@ -240,10 +215,8 @@ function WinAppDeployCmdTool(targetOsVersion) {
 
     DeploymentTool.call(this);
     this.targetOsVersion = targetOsVersion;
-    /* jshint ignore:start */ /* Ignore jshint to use dot notation for 2nd 
process.env access for consistency */
     var programFilesPath = process.env['ProgramFiles(x86)'] || 
process.env['ProgramFiles'];
     this.path = path.join(programFilesPath, 'Windows Kits', '10', 'bin', 
'x86', 'WinAppDeployCmd.exe');
-    /* jshint ignore:end */
 }
 
 WinAppDeployCmdTool.prototype = Object.create(DeploymentTool.prototype);
@@ -257,7 +230,7 @@ WinAppDeployCmdTool.prototype.enumerateDevices = function() 
{
     // The expansion is: IP address, spaces, GUID, spaces, text name
     var LINE_TEST = /^([\d\.]+?)\s+([\da-fA-F\-]+?)\s+(.+)$/m;
 
-    return run(that.path, ['devices']).then(function(result) {
+    return spawn(that.path, ['devices']).then(function(result) {
         var lines = result.split('\n');
         var matchedLines = lines.filter(function(line) {
             return LINE_TEST.test(line);
@@ -283,8 +256,8 @@ WinAppDeployCmdTool.prototype.enumerateDevices = function() 
{
 
 WinAppDeployCmdTool.prototype.installAppPackage = function(pathToAppxPackage, 
targetDevice, shouldLaunch, shouldUpdate, pin) {
     if (shouldLaunch) {
-        console.warn('Warning: Cannot launch app with current version of 
Windows 10 SDK tools.');
-        console.warn('         You will have to launch the app after 
installation is completed.');
+        events.emit('warn', 'Cannot launch app with current version of Windows 
10 SDK tools. ' +
+            'You will have to launch the app after installation is 
completed.');
     }
 
     var args = [shouldUpdate ? 'update' : 'install', '-file', 
pathToAppxPackage, '-ip', targetDevice.__ip];
@@ -293,13 +266,13 @@ WinAppDeployCmdTool.prototype.installAppPackage = 
function(pathToAppxPackage, ta
         args.push(pin);
     }
 
-    return run(this.path, args).then(function() {
-        console.log('Deployment completed successfully.');
+    return spawn(this.path, args).then(function() {
+        events.emit('log', 'Deployment completed successfully.');
     });
 };
 
 WinAppDeployCmdTool.prototype.uninstallAppPackage = function(packageInfo, 
targetDevice) {
-    return run(this.path, ['uninstall', '-package', packageInfo, '-ip', 
targetDevice.__ip]);
+    return spawn(this.path, ['uninstall', '-package', packageInfo, '-ip', 
targetDevice.__ip]);
 };
 
 // usage: require('deployment').getDeploymentTool('8.1');

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/58047a3d/template/cordova/lib/exec.js
----------------------------------------------------------------------
diff --git a/template/cordova/lib/exec.js b/template/cordova/lib/exec.js
deleted file mode 100644
index d71eda7..0000000
--- a/template/cordova/lib/exec.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-       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 child_process = require('child_process'),
-    Q       = require('q');
-
-// Takes a command and optional current working directory.
-// Returns a promise that either resolves with the stdout, or
-// rejects with an error message and the stderr.
-module.exports = function(cmd, opt_cwd) {
-    var d = Q.defer();
-    try {
-        child_process.exec(cmd, {cwd: opt_cwd, maxBuffer: 1024000}, 
function(err, stdout, stderr) {
-            if (err) d.reject('Error executing "' + cmd + '": ' + stderr);
-            else d.resolve(stdout);
-        });
-    } catch(e) {
-        console.error('error caught: ' + e);
-        d.reject(e);
-    }
-    return d.promise;
-};

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/58047a3d/template/cordova/lib/log.js
----------------------------------------------------------------------
diff --git a/template/cordova/lib/log.js b/template/cordova/lib/log.js
index f095f4b..d01c4af 100644
--- a/template/cordova/lib/log.js
+++ b/template/cordova/lib/log.js
@@ -20,11 +20,11 @@
 // requires
 var path         = require('path'),
     et           = require('elementtree'),
-    Q            = require('q'),
-    cp           = require('child_process'),
     ConfigParser = require('./ConfigParser.js'),
     nopt         = require('nopt');
 
+var spawn = require('cordova-common').superspawn.spawn;
+
 // paths
 var platformRoot = path.join(__dirname, '..', '..'),
     projectRoot  = path.join(platformRoot, '..', '..'),
@@ -186,16 +186,12 @@ function dumpLogs(startTime) {
 }
 
 function getEvents(channel, startTime) {
-    var d = Q.defer();
-    var command = 'wevtutil qe ' + channel + ' /q:"*[System [(TimeCreated 
[@SystemTime>\'' + startTime + '\'])]]" /e:root';
-    cp.exec(command, function (error, stdout, stderr) {
-        if (error) {
-            d.reject('Failed to run wevtutil command. ' + error);
-        } else {
-            d.resolve(parseEvents(stdout));
-        }
+    var command = 'wevtutil';
+    var args = ['qe', channel, '/q:"*[System [(TimeCreated [@SystemTime>\'' + 
startTime + '\'])]]"', '/e:root'];
+    return spawn(command, args)
+    .then(function(stdout) {
+        return parseEvents(stdout);
     });
-    return d.promise;
 }
 
 function getElementValue(et, element, attribute) {
@@ -206,7 +202,7 @@ function getElementValue(et, element, attribute) {
         if (!!attribute) {
             result = found[0].get(attribute);
         } else {
-            result = found[0].text; 
+            result = found[0].text;
         }
     }
 
@@ -267,7 +263,7 @@ function parseEvents(output) {
             result.displayName = undefined;
         }
 
-        // cut out uninformative fields 
+        // cut out uninformative fields
         if ((result.line === '0') && (result.column === '0')) {
             result.line = undefined;
             result.column = undefined;
@@ -333,14 +329,16 @@ function stringifyEvent(event) {
 }
 
 function getLogState(channel) {
-    return exec('wevtutil get-log "' + channel + '"').then(function(output) {
+    return spawn('wevtutil', ['get-log', channel])
+    .then(function(output) {
         return output.indexOf('enabled: true') != -1;
     });
 }
 
 function enableChannel(channel) {
-    return exec('wevtutil set-log "' + channel + '" /e:false 
/q:true').then(function() {
-        return exec('wevtutil set-log "' + channel + '" /e:true /rt:true 
/ms:4194304 /q:true');
+    return spawn('wevtutil', ['set-log', channel, '/e:false', '/q:true'])
+    .then(function() {
+        return spawn('wevtutil', ['set-log', channel, '/e:true', '/rt:true', 
'/ms:4194304','/q:true']);
     }, function() {
         console.warn('Cannot enable log channel: ' + channel);
         console.warn('Try running the script with administrator privileges.');
@@ -349,16 +347,5 @@ function enableChannel(channel) {
 
 function disableChannel(channel) {
     console.log('Disabling channel ' + channel);
-    exec('wevtutil set-log "' + channel + '" /e:false /q:true');
-}
-
-function exec(command) {
-    var d = Q.defer();
-    cp.exec(command, function (error, stdout) {
-        if (error) {
-            d.reject('An error occured while executing following command:\n' + 
command + '\n' + error);
-        }
-        d.resolve(stdout);
-    });
-    return d.promise;
+    spawn('wevtutil', ['set-log', channel, '/e:false', '/q:true']);
 }

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/58047a3d/template/cordova/lib/package.js
----------------------------------------------------------------------
diff --git a/template/cordova/lib/package.js b/template/cordova/lib/package.js
index 9664987..cd3de0e 100644
--- a/template/cordova/lib/package.js
+++ b/template/cordova/lib/package.js
@@ -17,11 +17,14 @@
        under the License.
 */
 
-var Q     = require('q'),
-    fs    = require('fs'),
-    path  = require('path'),
-    spawn = require('./spawn'),
-    utils = require('./utils');
+var Q     = require('q');
+var fs    = require('fs');
+var path  = require('path');
+var utils = require('./utils');
+var AppxManifest = require('./AppxManifest');
+var events = require('cordova-common').events;
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
 
 // returns folder that contains package with chip architecture,
 // build and project types specified by script parameters
@@ -96,9 +99,9 @@ module.exports.getPackageFileInfo = function (packageFile) {
 // return package app ID fetched from appxmanifest
 // return rejected promise if appxmanifest not valid
 module.exports.getAppId = function (platformPath) {
-    var manifest = path.join(platformPath, 'package.phone.appxmanifest');
     try {
-        return /PhoneProductId="(.*?)"/gi.exec(fs.readFileSync(manifest, 
'utf8'))[1];
+        return AppxManifest.get(path.join(platformPath, 
'package.phone.appxmanifest'))
+            .getPhoneIdentity().getPhoneProductId();
     } catch (e) {
         throw new Error('Can\'t read appId from phone manifest', e);
     }
@@ -110,9 +113,9 @@ function getPackageName(platformPath) {
     // Can reliably read from package.windows.appxmanifest even if targeting 
Windows 10
     // because the function is only used for desktop deployment, which always 
has the same
     // package name when uninstalling / reinstalling
-    var manifest = path.join(platformPath, 'package.windows.appxmanifest');
     try {
-        return Q.resolve(/Identity 
Name="(.*?)"/gi.exec(fs.readFileSync(manifest, 'utf8'))[1]);
+        return Q.when(AppxManifest.get(path.join(platformPath, 
'package.windows.appxmanifest'))
+            .getIdentity().getName());
     } catch (e) {
         return Q.reject('Can\'t read package name from manifest ' + e);
     }
@@ -154,23 +157,20 @@ module.exports.findDevice = function (deploymentTool, 
target) {
 
 // returns array of available devices names
 module.exports.listDevices = function (deploymentTool) {
-    
+
     return deploymentTool.enumerateDevices().then(function(deviceList) {
         return deviceList.map(function(device) {
             return device.toString();
         });
 
     }, function(e) {
-        console.warn('Failed to enumerate devices');
-        console.warn(e);
-
-        throw e;
+        events.emit('error', new Error('Failed to enumerate devices: ' + e));
     });
 };
 
 
 function uninstallAppFromPhone(appDeployUtils, package, target) {
-    console.log('Attempting to remove previously installed application...');
+    events.emit('log', 'Attempting to remove previously installed 
application...');
     return appDeployUtils.uninstallAppPackage(package.phoneId, target);
 }
 
@@ -186,24 +186,24 @@ module.exports.deployToPhone = function (package, 
deployTarget, targetWindows10,
 
     return deployment.then(function(deploymentTool) {
         return module.exports.findDevice(deploymentTool, 
deployTarget).then(function(target) {
-            return uninstallAppFromPhone(deploymentTool, package, target).then(
-                function() {}, function() {}).then(function() {
-                    // shouldUpdate = false because we've already uninstalled
-                    console.log('Deploying app package...');
-                    return deploymentTool.installAppPackage(package.appx, 
target, /*shouldLaunch*/ true, /*shouldUpdate*/ false);
-                }).then(function() { }, function(error) {
-                    if (error.message.indexOf('Error code 2148734208 for 
command') === 0) {
-                        return deploymentTool.installAppPackage(package.appx, 
target, /*shouldLaunch*/ true, /*shouldUpdate*/ true);
-                    } else if (error.message.indexOf('Error code -2146233088') 
=== 0) {
-                        throw new Error('No Windows Phone device was 
detected.');
-                    } else {
-                        console.warn('Unexpected error from installation:');
-                        console.warn(error.message);
-                        console.warn('You may have previously installed the 
app with an earlier version of cordova-windows.');
-                        console.warn('Ensure the app is uninstalled from the 
phone and then try to run again.');
-                        throw error;
-                    }
-                });
+            return uninstallAppFromPhone(deploymentTool, package, target)
+            .then(function() {}, function() {})
+            .then(function() {
+                // shouldUpdate = false because we've already uninstalled
+                events.emit('log', 'Deploying app package...');
+                return deploymentTool.installAppPackage(package.appx, target, 
/*shouldLaunch*/ true, /*shouldUpdate*/ false);
+            })
+            .then(function() { }, function(error) {
+                if (error.message.indexOf('Error code 2148734208 for command') 
=== 0) {
+                    return deploymentTool.installAppPackage(package.appx, 
target, /*shouldLaunch*/ true, /*shouldUpdate*/ true);
+                } else if (error.message.indexOf('Error code -2146233088') === 
0) {
+                    throw new CordovaError('No Windows Phone device was 
detected.');
+                } else {
+                    throw new CordovaError('Unexpected error from 
installation: ' + error.message +
+                        ' You may have previously installed the app with an 
earlier version of cordova-windows.' +
+                        ' Ensure the app is uninstalled from the phone and 
then try to run again.');
+                }
+            });
         });
     });
 };
@@ -219,19 +219,25 @@ module.exports.deployToDesktop = function (package, 
deployTarget) {
 
             var oldArch;
             // uninstalls previous application instance (if exists)
-            console.log('Attempt to uninstall previous application 
version...');
-            return spawn('powershell', ['-ExecutionPolicy', 'RemoteSigned', 
'Import-Module "' + appStoreUtils + '"; Uninstall-App ' + pkgname])
+            events.emit('log', 'Attempting to uninstall previous application 
version...');
+            return spawn('powershell', ['-ExecutionPolicy', 'RemoteSigned',
+                'Import-Module "' + appStoreUtils + '"; Uninstall-App ' + 
pkgname],
+                { stdio: 'inherit' })
             .then(function() {
-                console.log('Attempt to install application...');
+                events.emit('log', 'Attempting to install application...');
                 oldArch = process.env.PROCESSOR_ARCHITECTURE;
                 if (package.arch === 'x64') {
                     process.env.PROCESSOR_ARCHITECTURE = 'AMD64';
                 }
-                return spawn('powershell', ['-ExecutionPolicy', 
'RemoteSigned', 'Import-Module "' + appStoreUtils + '"; Install-App', 
utils.quote(package.script)]);
+                return spawn('powershell', ['-ExecutionPolicy', 'RemoteSigned',
+                    'Import-Module "' + appStoreUtils + '"; Install-App', 
utils.quote(package.script)],
+                    { stdio: 'inherit' });
             }).then(function() {
                 process.env.PROCESSOR_ARCHITECTURE = oldArch;
-                console.log('Starting application...');
-                return spawn('powershell', ['-ExecutionPolicy', 
'RemoteSigned', 'Import-Module "' + appStoreUtils + '"; Start-Locally', 
pkgname]);
+                events.emit('log', 'Starting application...');
+                return spawn('powershell', ['-ExecutionPolicy', 'RemoteSigned',
+                    'Import-Module "' + appStoreUtils + '"; Start-Locally', 
pkgname],
+                    { stdio: 'inherit' });
             }, function (error) {
                 process.env.PROCESSOR_ARCHITECTURE = oldArch;
                 throw error;

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/58047a3d/template/cordova/lib/prepare.js
----------------------------------------------------------------------
diff --git a/template/cordova/lib/prepare.js b/template/cordova/lib/prepare.js
index b930f62..01b8798 100644
--- a/template/cordova/lib/prepare.js
+++ b/template/cordova/lib/prepare.js
@@ -17,61 +17,40 @@
        under the License.
 */
 
-var path            = require('path'),
-    fs              = require('fs'),
-    et              = require('elementtree'),
-    subElement      = et.SubElement,
-    shell           = require('shelljs'),
-    MSBuildTools    = require('./MSBuildTools'),
-    Version         = require('./Version'),
-    ConfigParser    = require('./ConfigParser');
-
-var ROOT = path.join(__dirname, '..', '..'),
-    PROJECT_WINDOWS10   = 'CordovaApp.Windows10.jsproj',
+var Q = require('q');
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var et = require('elementtree');
+var Version = require('./Version');
+var AppxManifest = require('./AppxManifest');
+var MSBuildTools = require('./MSBuildTools');
+var ConfigParser = require('./ConfigParser');
+var events = require('cordova-common').events;
+var xmlHelpers = require('cordova-common').xmlHelpers;
+
+var PROJECT_WINDOWS10   = 'CordovaApp.Windows10.jsproj',
     MANIFEST_WINDOWS8   = 'package.windows80.appxmanifest',
     MANIFEST_WINDOWS    = 'package.windows.appxmanifest',
     MANIFEST_PHONE      = 'package.phone.appxmanifest',
-    MANIFEST_WINDOWS10  = 'package.windows10.appxmanifest',
-    BASE_UAP_VERSION    = new Version(10, 0, 10240, 0),
-    UAP_RESTRICTED_CAPS = ['enterpriseAuthentication', 
'sharedUserCertificates',
-                           'documentsLibrary', 'musicLibrary', 
'picturesLibrary',
-                           'videosLibrary', 'removableStorage', 
'internetClientServer',
-                           'privateNetworkClientServer'],
-    // UAP namespace capabilities come from the XSD type ST_Capability_Uap 
from AppxManifestTypes.xsd
-    CAPS_NEEDING_UAPNS  = ['documentsLibrary', 'picturesLibrary', 
'videosLibrary',
-                           'musicLibrary', 'enterpriseAuthentication', 
'sharedUserCertificates',
-                           'removableStorage', 'appointments', 'contacts', 
'userAccountInformation',
-                           'phoneCall', 'blockedChatMessages', 'objects3D'];
+    MANIFEST_WINDOWS10  = 'package.windows10.appxmanifest';
 
 var TEMPLATE =
     '<?xml version="1.0" encoding="utf-8"?>\n' +
     '<!--\n    This file is automatically generated.\n' +
     '    Do not modify this file - YOUR CHANGES WILL BE ERASED!\n-->\n';
 
+/** Note: this is only for backward compatibility, since it is being called 
directly from windows_parser */
 module.exports.applyPlatformConfig = function() {
-    var config = new ConfigParser(path.join(ROOT, 'config.xml'));
-
-    // Apply appxmanifest changes
-    [{ fileName: MANIFEST_WINDOWS,   namespacePrefix: 'm2:' },
-     { fileName: MANIFEST_WINDOWS8,  namespacePrefix: '' },
-     { fileName: MANIFEST_WINDOWS10, namespacePrefix: 'uap:' },
-     { fileName: MANIFEST_PHONE,     namespacePrefix: 'm3:' }].forEach(
-        function(manifestFile) {
-            // Break out Windows 10-specific functionality because we also 
need to
-            // apply UAP versioning to Windows 10 appx-manifests.
-            var isTargetingWin10 = (manifestFile.fileName === 
MANIFEST_WINDOWS10);
-            updateManifestFile(config, path.join(ROOT, manifestFile.fileName), 
manifestFile.namespacePrefix, isTargetingWin10);
-    });
-
-    if (process.platform === 'win32') {
-        applyUAPVersionToProject(path.join(ROOT, PROJECT_WINDOWS10), 
getUAPVersions());
-    }
-
-    copyImages(config);
+    var projectRoot = path.join(__dirname, '../..');
+    var appConfig = new ConfigParser(path.join(projectRoot, 
'../../config.xml'));
+    updateProjectAccordingTo(appConfig);
+    copyImages(appConfig, projectRoot);
 };
 
 module.exports.updateBuildConfig = function(buildConfig) {
-    var config = new ConfigParser(path.join(ROOT, 'config.xml'));
+    var projectRoot = path.join(__dirname, '../..');
+    var config = new ConfigParser(path.join(projectRoot, 'config.xml'));
 
     // if no buildConfig is provided dont do anything
     buildConfig = buildConfig || {};
@@ -96,7 +75,7 @@ module.exports.updateBuildConfig = function(buildConfig) {
 
     if (config.packageCertificateKeyFile) {
         // Convert packageCertificateKeyFile from absolute to relative path
-        packageCertificateKeyFile = path.relative(ROOT, 
packageCertificateKeyFile);
+        packageCertificateKeyFile = path.relative(projectRoot, 
packageCertificateKeyFile);
     }
 
     var certificatePropertyElement = new 
et.Element('PackageCertificateKeyFile');
@@ -120,88 +99,78 @@ module.exports.updateBuildConfig = function(buildConfig) {
     propertyGroup.append(defaultLocaleElement);
 
     var buildConfigFileName = buildConfig.buildType === 'release' ?
-        path.join(ROOT, 'CordovaAppRelease.projitems') :
-        path.join(ROOT, 'CordovaAppDebug.projitems');
+        path.join(projectRoot, 'CordovaAppRelease.projitems') :
+        path.join(projectRoot, 'CordovaAppDebug.projitems');
 
     fs.writeFileSync(buildConfigFileName, TEMPLATE + 
buildConfigXML.write({indent: 2, xml_declaration: false}), 'utf-8');
 };
 
-function updateManifestFile (config, manifestPath, namespacePrefix, 
isTargetingWin10) {
-    var contents = fs.readFileSync(manifestPath, 'utf-8');
-    if(contents) {
-        //Windows is the BOM. Skip the Byte Order Mark.
-        contents = contents.substring(contents.indexOf('<'));
-    }
+function updateManifestFile (config, manifestPath) {
+    var manifest = AppxManifest.get(manifestPath);
+    // Break out Windows 10-specific functionality because we also need to
+    // apply UAP versioning to Windows 10 appx-manifests.
+    var isTargetingWin10 = manifest.prefix === 'uap:';
 
-    var manifest =  new et.ElementTree(et.XML(contents));
+    applyCoreProperties(config, manifest);
+    applyStartPage(config, manifest, isTargetingWin10);
 
-    applyCoreProperties(config, manifest, manifestPath, namespacePrefix, 
isTargetingWin10);
-    // sort Capability elements as per CB-5350 Windows8 build fails due to 
invalid 'Capabilities' definition
-    sortCapabilities(manifest);
-    applyAccessRules(config, manifest, isTargetingWin10);
-    applyBackgroundColor(config, manifest, namespacePrefix);
-    applyToastCapability(config, manifest, namespacePrefix);
+    if (isTargetingWin10) {
+        applyNavigationWhitelist(config, manifest);
+    } else {
+        applyAccessRules(config, manifest);
+    }
+
+    // Apply background color, splashscreen background color, etc.
+    manifest.getVisualElements()
+        .trySetBackgroundColor(config.getPreference('BackgroundColor'))
+        
.setSplashBackgroundColor(config.getPreference('SplashScreenBackgroundColor'))
+        .setToastCapable(config.getPreference('WindowsToastCapable'))
+        .setOrientation(config.getPreference('Orientation'));
 
     if (isTargetingWin10) {
-        applyTargetPlatformVersion(config, manifest);
-        checkForRestrictedCapabilities(config, manifest);
-        ensureUapPrefixedCapabilities(manifest.find('.//Capabilities'));
+        manifest.setDependencies(config.getAllMinMaxUAPVersions());
+
+        var badCaps = manifest.getRestrictedCapabilities();
+        if (config.hasRemoteUris() && badCaps) {
+            events.emit('warn', 'The following Capabilities were declared and 
are restricted:' +
+                '\n\t' + badCaps.map(function(a){return a.name;}).join(', ') +
+                '\nYou will be unable to on-board your app to the public 
Windows Store with these ' +
+                'capabilities and access rules permitting access to remote 
URIs.');
+        }
     }
 
     //Write out manifest
-    fs.writeFileSync(manifestPath, manifest.write({indent: 4}), 'utf-8');
+    manifest.write();
 }
 
-function applyCoreProperties(config, manifest, manifestPath, xmlnsPrefix, 
targetWin10) {
-    var version = fixConfigVersion(config.windows_packageVersion() || 
config.version());
-    var name = config.name();
-    // CB-9450: iOS/Android and Windows Store have an incompatibility here; 
Windows Store assigns the 
+function applyCoreProperties(config, manifest) {
+    // CB-9450: iOS/Android and Windows Store have an incompatibility here; 
Windows Store assigns the
     // package name that should be used for upload to the store.  However, 
this can't be set for typical
     // Cordova apps.  So, we have to create a Windows-specific preference here.
     var pkgName = config.getPreference('WindowsStoreIdentityName') || 
config.packageName();
-    var author = config.author();
-
-    var identityNode = manifest.find('.//Identity');
-    if(!identityNode) {
-        throw new Error('Invalid manifest file (no <Identity> node): ' + 
manifestPath);
-    }
-    // Update identity name and version
     if (pkgName) {
-        (identityNode.attrib.Name = pkgName);
+        manifest.getIdentity().setName(pkgName);
     }
+
+    var version = config.windows_packageVersion() || config.version();
     if (version) {
-        (identityNode.attrib.Version = version);
+        manifest.getIdentity().setVersion(version);
     }
 
     // Update publisher id (identity)
-    if (config.publisherId && identityNode.attrib.Publisher !== 
config.publisherId) {
-        identityNode.attrib.Publisher = config.publisherId;
+    if (config.publisherId) {
+        manifest.getIdentity().setPublisher(config.publisherId);
     }
 
     // Update name (windows8 has it in the Application[@Id] and 
Application.VisualElements[@DisplayName])
-    var app = manifest.find('.//Application');
-    if(!app) {
-        throw new Error('Invalid manifest file (no <Application> node): ' + 
manifestPath);
-    }
-
     var baselinePackageName = config.packageName();
     if (baselinePackageName) {
-        // 64 symbols restriction goes from manifest schema definition
-        // http://msdn.microsoft.com/en-us/library/windows/apps/br211415.aspx
-        var appId = baselinePackageName.length <= 64 ? baselinePackageName : 
baselinePackageName.substr(0, 64);
-        app.attrib.Id = appId;
+        manifest.getApplication().setId(baselinePackageName);
     }
 
-    applyStartPage(app, config, targetWin10);
-
-    var visualElementsName = './/' + xmlnsPrefix + 'VisualElements';
-    var visualElems = manifest.find(visualElementsName);
-
-    if(!visualElems) {
-        throw new Error('Invalid manifest file (no <' + xmlnsPrefix + 
'VisualElements> node): ' + manifestPath);
-    }
+    var name = config.name();
     if (name) {
-        (visualElems.attrib.DisplayName = name);
+        manifest.getVisualElements().setDisplayName(name);
     }
 
     // CB-9410: Get a display name and publisher display name.  In the Windows 
Store, certain
@@ -209,76 +178,18 @@ function applyCoreProperties(config, manifest, 
manifestPath, xmlnsPrefix, target
     // Here, we check for Windows-specific preferences, and if we find it, 
prefer that over
     // the Cordova <widget> areas.
     var displayName = config.getPreference('WindowsStoreDisplayName') || name;
-    var publisherName = config.getPreference('WindowsStorePublisherName') || 
author;
+    var publisherName = config.getPreference('WindowsStorePublisherName') || 
config.author();
 
     // Update properties
-    var properties = manifest.find('.//Properties');
-    if (properties && properties.find) {
-        var displayNameElement = properties.find('.//DisplayName');
-        if (displayNameElement && displayName) {
-            displayNameElement.text = displayName;
-        }
-
-        var publisherNameElement = properties.find('.//PublisherDisplayName');
-        if (publisherNameElement && publisherName) {
-            publisherNameElement.text = publisherName;
-        }
-    }
-
-    // Supported orientations
-    var rotationPreferenceName = xmlnsPrefix + 'Rotation';
-    var rotationPreferenceRootName = xmlnsPrefix + 'InitialRotationPreference';
-
-    var orientation = config.getPreference('Orientation');
-    var rotationPreferenceRoot;
-    if (orientation) {
-        rotationPreferenceRoot = manifest.find('.//' + 
rotationPreferenceRootName);
-        if(rotationPreferenceRoot === null) {
-            visualElems.append(et.Element(rotationPreferenceRootName));
-            rotationPreferenceRoot = manifest.find('.//' + 
rotationPreferenceRootName);
-        }
-
-        rotationPreferenceRoot.clear();
-
-        var applyOrientations = function(orientationsArr) {
-            orientationsArr.forEach(function(orientationValue) {
-                var el = et.Element(rotationPreferenceName);
-                el.attrib.Preference = orientationValue;
-                rotationPreferenceRoot.append(el);
-            });
-        };
-
-        // Updates supported orientations
-        //<InitialRotationPreference>
-        //    <Rotation Preference = "portrait" | "landscape" | 
"portraitFlipped" | "landscapeFlipped" /> {1,4}
-        //</InitialRotationPreference>
-        if(orientation === 'default') {
-            // This means landscape and portrait
-            applyOrientations(['portrait', 'landscape', 'landscapeFlipped']);
-        } else if(orientation === 'portrait') {
-            applyOrientations(['portrait']);
-        } else if(orientation === 'landscape') {
-            applyOrientations(['landscape', 'landscapeFlipped']);
-        } else { // Platform-specific setting like 
"portrait,landscape,portraitFlipped"
-            applyOrientations(orientation.split(','));
-        }
-    } else {
-        // Remove InitialRotationPreference root element to revert to defaults
-        rotationPreferenceRoot = visualElems.find('.//' + 
rotationPreferenceRootName);
-        if(rotationPreferenceRoot !== null) {
-            visualElems.remove(null, rotationPreferenceRoot);
-        }
-    }
+    manifest.getProperties()
+        .setDisplayName(displayName)
+        .setPublisherDisplayName(publisherName);
 }
 
-function applyStartPage(appNode, config, targetingWin10) {
-    var startPage = config.startPage();
-
-    if (!startPage) {
-        // If not specified, set default value
-        // 
http://cordova.apache.org/docs/en/edge/config_ref_index.md.html#The%20config.xml%20File
-        startPage = 'index.html';
-    }
+function applyStartPage(config, manifest, targetingWin10) {
+    // If not specified, set default value
+    // 
http://cordova.apache.org/docs/en/edge/config_ref_index.md.html#The%20config.xml%20File
+    var startPage = config.startPage() || 'index.html';
 
     var uriPrefix = '';
     if (targetingWin10) {
@@ -308,41 +219,19 @@ function applyStartPage(appNode, config, targetingWin10) {
         uriPrefix += '/'; // add a 3rd trailing forward slash for correct area 
resolution
     }
 
-    appNode.attrib.StartPage = uriPrefix + startPagePrefix + startPage;
+    manifest.getApplication().setStartPage(uriPrefix + startPagePrefix + 
startPage);
 }
 
-// Adjust version number as per CB-5337 Windows8 build fails due to invalid 
app version
-function fixConfigVersion (version) {
-    if(version && version.match(/\.\d/g)) {
-        var numVersionComponents = version.match(/\.\d/g).length + 1;
-        while (numVersionComponents++ < 4) {
-            version += '.0';
-        }
-    }
-    return version;
-}
-
-function applyAccessRules (config, manifest, isTargetingWin10) {
-    // Updates WhiteListing rules
-    //<ApplicationContentUriRules>
-    //    <Rule Match="https://www.example.com"; Type="include"/>
-    //</ApplicationContentUriRules>
-
-    var AppContentUriRulesElementName = 'ApplicationContentUriRules',
-        RuleElementName = 'Rule';
-
-    if (isTargetingWin10) {
-        return applyNavigationWhitelist(config, manifest);
-    }
-
-    var accessRules = config.getAccessRules().filter(function(rule) {
+function applyAccessRules (config, manifest) {
+    var accessRules = config.getAccesses()
+    .filter(function(rule) {
         // https:// rules are always good, * rules are always good
-        if (rule.indexOf('https://') === 0 || rule === '*') {
-            return true;
-        } else {
-            console.warn('Access rules must begin with "https://";, the 
following rule will be ignored: ' + rule);
-        }
+        if (rule.origin.indexOf('https://') === 0 || rule.origin === '*') 
return true;
+
+        events.emit('warn', 'Access rules must begin with "https://";, the 
following rule will be ignored: ' + rule.origin);
         return false;
+    }).map(function (rule) {
+        return rule.origin;
     });
 
     // If * is specified, emit no access rules.
@@ -350,7 +239,7 @@ function applyAccessRules (config, manifest, 
isTargetingWin10) {
         accessRules = [];
     }
 
-    createApplicationContentUriRules(manifest, AppContentUriRulesElementName, 
RuleElementName, accessRules, { Type: 'include' });
+    manifest.getApplication().setAccessRules(accessRules);
 }
 
 /**
@@ -358,17 +247,23 @@ function applyAccessRules (config, manifest, 
isTargetingWin10) {
  * Allows WinRT access to origins specified by <allow-navigation href="origin" 
/> elements.
  */
 function applyNavigationWhitelist(config, manifest) {
-    var AppContentUriRulesElementName = 'uap:ApplicationContentUriRules';
-    var RuleElementName = 'uap:Rule';
+
+    if (manifest.prefix !== 'uap:') {
+        // This never should happen, but to be sure let's check
+        throw new Error('AllowNavigation whitelist rules must be applied to 
Windows 10 appxmanifest only.');
+    }
+
     var UriSchemeTest = /^(?:https?|ms-appx-web):\/\//i;
 
-    var whitelistRules = 
config.getNavigationWhitelistRules().filter(function(rule) {
-        if (UriSchemeTest.test(rule)) {
-            return true;
-        } else {
-            console.warn('The following navigation rule had an invalid URI 
scheme and is ignored: "' + rule + '".');
-        }
+    var whitelistRules = config.getAllowNavigations()
+    .filter(function(rule) {
+        if (UriSchemeTest.test(rule.href)) return true;
+
+        events.emit('warn', 'The following navigation rule had an invalid URI 
scheme and is ignored: "' + rule.href + '".');
         return false;
+    })
+    .map(function (rule) {
+        return rule.href;
     });
 
     var defaultPrefix = config.getPreference('WindowsDefaultUriPrefix');
@@ -381,96 +276,17 @@ function applyNavigationWhitelist(config, manifest) {
         }
     }
 
-    createApplicationContentUriRules(manifest, AppContentUriRulesElementName, 
RuleElementName, whitelistRules, {
-        Type: 'include',
-        WindowsRuntimeAccess: 'all'
-    });
-}
-
-/**
- * Private function used by applyNavigationWhitelist and applyAccessRules
- * which creates the corresponding section in the app manifest.
- * @param manifest {et.ElementTree} The manifest document.
- * @param acurElementName {string} The name of the AccessContentUriRules 
element, including prefix if applicable.
- * @param ruleElementName {string} The name of the Rule element, including 
prefix if applicable.
- * @param rulesOrigins {string[]} The origins that will be permitted.
- * @param commonAttributes {Object} Property bag of additional attributes that 
should be applied to every rule.
- */
-function createApplicationContentUriRules(manifest, acurElementName, 
ruleElementName, rulesOrigins, commonAttributes) {
-    var appUriRulesRoot = manifest.find('.//Application'),
-        appUriRules = appUriRulesRoot.find(acurElementName);
-
-    if (appUriRules !== null) {
-        appUriRulesRoot.remove(null, appUriRules);
-    }
-
-    // No rules defined
-    if (rulesOrigins.length === 0) {
-        return;
-    }
-
-    appUriRules = et.Element(acurElementName);
-    appUriRulesRoot.append(appUriRules);
-
-    rulesOrigins.forEach(function(rule) {
-        var el = et.Element(ruleElementName);
-        el.attrib.Match = rule;
-
-        var attributes = Object.keys(commonAttributes);
-        attributes.forEach(function(attributeName) {
-            el.attrib[attributeName] = commonAttributes[attributeName];
-        });
-        appUriRules.append(el);
-    });
-}
-
-function sortCapabilities(manifest) {
-
-    // removes namespace prefix (m3:Capability -> Capability)
-    // this is required since elementtree returns qualified name with namespace
-    function extractLocalName(tag) {
-        return tag.split(':').pop(); // takes last part of string after ':'
-    }
-
-    var capabilitiesRoot = manifest.find('.//Capabilities'),
-        capabilities = capabilitiesRoot._children || [];
-    // to sort elements we remove them and then add again in the appropriate 
order
-    capabilities.forEach(function(elem) { // no .clear() method
-        capabilitiesRoot.remove(0, elem);
-        // CB-7601 we need local name w/o namespace prefix to sort 
capabilities correctly
-        elem.localName = extractLocalName(elem.tag);
-    });
-    capabilities.sort(function(a, b) {
-        return (a.localName > b.localName) ? 1: -1;
-    });
-    capabilities.forEach(function(elem) {
-        capabilitiesRoot.append(elem);
-    });
+    manifest.getApplication().setAccessRules(whitelistRules);
 }
 
-function checkForRestrictedCapabilities(config, manifest) {
-    var hasRemoteUris = checkForRemoteModeUris(config);
-    if (hasRemoteUris) {
-        var capabilitiesRoot = manifest.find('.//Capabilities');
-        var badCaps = 
checkForRestrictedRemoteCapabilityDeclarations(capabilitiesRoot);
-        if (badCaps) {
-            console.warn('The following Capabilities were declared and are 
restricted:');
-            console.warn('   ' + badCaps.join(','));
-            console.warn('You will be unable to on-board your app to the 
public Windows Store with');
-            console.warn(' these capabilities and access rules permitting 
access to remote URIs.');
-        }
-    }
-}
+function copyImages(config, platformRoot) {
 
-function copyImages(config) {
-    var platformRoot = ROOT;
-    // TODO find the way to detect whether command was triggered by CLI or not
-    var appRoot = path.join(platformRoot, '..', '..');
+    var appRoot = path.dirname(config.path);
 
     function copyImage(src, dest) {
         src = path.join(appRoot, src);
         dest = path.join(platformRoot, 'images', dest);
-        //console.log('Copying image from ' + src + ' to ' + dest);
+        events.emit('verbose', 'Copying image from ' + src + ' to ' + dest);
         shell.cp('-f', src, dest);
     }
 
@@ -488,7 +304,7 @@ function copyImages(config) {
         });
         // warn if no images found
         if (images.length === 0) {
-            console.log('No images found for target: ' + destFileName);
+            events.emit('warn', 'No images found for target: ' + destFileName);
             return;
         }
         // copy images with new name but keeping scale suffix
@@ -550,44 +366,12 @@ function copyImages(config) {
             if (targetImg) {
                 copyImage(img.src, targetImg.dest);
             } else {
-                console.log('The following image is skipped due to unsupported 
size: ' + img.src);
+                events.emit('warn', 'The following image is skipped due to 
unsupported size: ' + img.src);
             }
         }
     });
 }
 
-function applyBackgroundColor (config, manifest, xmlnsPrefix) {
-    var visualElems =null;
-
-    function refineColor(color) {
-        // return three-byte hexadecimal number preceded by "#" (required for 
Windows)
-        color = color.replace('0x', '').replace('#', '');
-        if (color.length == 3) {
-            color = color[0] + color[0] + color[1] + color[1] + color[2] + 
color[2];
-        }
-        // alpha is not supported, so we remove it
-        if (color.length == 8) { // AArrggbb
-            color = color.slice(2);
-        }
-        return '#' + color;
-    }
-    // background color
-    var bgColor = config.getPreference('BackgroundColor');
-    if (bgColor) {
-        var visualElementsName = './/' + xmlnsPrefix + 'VisualElements';
-        visualElems = manifest.find(visualElementsName);
-        visualElems.attrib.BackgroundColor = refineColor(bgColor);
-    }
-
-    // Splash Screen background color
-    bgColor = config.getPreference('SplashScreenBackgroundColor');
-    if (bgColor) {
-        var splashScreenElementsName = './/' + xmlnsPrefix + 'SplashScreen';
-        visualElems = manifest.find(splashScreenElementsName);
-        visualElems.attrib.BackgroundColor = refineColor(bgColor);
-    }
-}
-
 function applyUAPVersionToProject(projectFilePath, uapVersionInfo) {
     // No uapVersionInfo means that there is no UAP SDKs installed and there 
is nothing to do for us
     if (!uapVersionInfo) return;
@@ -603,25 +387,6 @@ function applyUAPVersionToProject(projectFilePath, 
uapVersionInfo) {
     fs.writeFileSync(projectFilePath, xml.write({ indent: 4 }), {});
 }
 
-function applyTargetPlatformVersion(config, manifest) {
-    var dependencies = manifest.find('./Dependencies');
-    while (dependencies.len() > 0) {
-        dependencies.delItem(0);
-    }
-
-    var uapVersionSet = getAllMinMaxUAPVersions(config);
-    var platformNames = Object.keys(uapVersionSet);
-    for (var i = 0; i < platformNames.length; i++) {
-        var curTargetPlatformName = platformNames[i];
-        var curTargetPlatformInfo = uapVersionSet[curTargetPlatformName];
-
-        var elem = subElement(dependencies, 'TargetDeviceFamily');
-        elem.set('Name', curTargetPlatformName);
-        elem.set('MinVersion', curTargetPlatformInfo.MinVersion.toString());
-        elem.set('MaxVersionTested', 
curTargetPlatformInfo.MaxVersionTested.toString());
-    }
-}
-
 // returns {minUAPVersion: Version, targetUAPVersion: Version} | false
 function getUAPVersions() {
     var baselineVersions = MSBuildTools.getAvailableUAPVersions();
@@ -637,149 +402,153 @@ function getUAPVersions() {
     };
 }
 
+module.exports.prepare = function (cordovaProject) {
+    var self = this;
+
+    this._config = updateConfigFilesFrom(cordovaProject.projectConfig,
+        this._munger, this.locations);
+
+    // Update own www dir with project's www assets and plugins' assets and 
js-files
+    return Q.when(updateWwwFrom(cordovaProject, this.locations))
+    .then(function () {
+        // update project according to config.xml changes.
+        return updateProjectAccordingTo(self._config, self.locations);
+    })
+    .then(function () {
+        copyImages(cordovaProject.projectConfig, self.root);
+        // CB-5421 Add BOM to all html, js, css files to ensure app can pass 
Windows Store Certification
+        addBOMSignature(self.locations.www);
+    })
+    .then(function () {
+        self.events.emit('verbose', 'Updated project successfully');
+    });
+};
+
 /**
- * Gets min/max UAP versions from the configuration.  If no version 
preferences are
- * in the configuration file, this will provide Windows.Universal at 
BASE_UAP_VERSION for both min and max.
- * This will always return a rational object or will fail; for example, if a 
platform expects
- * a higher min-version than max-version, it will raise the max version to the 
min version.
+ * Adds BOM signature at the beginning of all js|html|css|json files in
+ *   specified folder and all subfolders. This is required for application to
+ *   pass Windows store certification successfully.
  *
- * @param config {ConfigParser} The configuration parser
- * @return An object in the shape of: { 'Windows.Mobile': {'MinVersion': 
Version, 'MaxVersion': Version } } (where Version is a Version object)
- * @exception {RangeError} Thrown if a Version string is badly formed.
+ * @param  {String}  directory  Directory where we need to update files
  */
-function getAllMinMaxUAPVersions(config) {
-    var uapVersionPreferenceTest = 
/(Microsoft.+?|Windows.+?)\-(MinVersion|MaxVersionTested)/i;
-    var platformBag = Object.create(null);
-    var preferenceList = 
config.getMatchingPreferences(uapVersionPreferenceTest);
-    preferenceList.forEach(function(verPref) {
-        var matches = uapVersionPreferenceTest.exec(verPref.name);
-        // 'matches' should look like: ['Windows.Universal-MinVersion', 
'Windows.Universal', 'MinVersion']
-        var platformName = matches[1];
-        var versionPropertyName = matches[2];
-
-        var platformVersionSet = platformBag[platformName];
-        if (typeof platformVersionSet === 'undefined') {
-            platformVersionSet = { };
-            platformBag[platformName] = platformVersionSet;
+function addBOMSignature(directory) {
+    shell.ls('-R', directory)
+    .forEach(function (file) {
+        if (!file.match(/\.(js|html|css|json)$/i)) {
+            return;
         }
 
-        var versionTest = Version.tryParse(verPref.value);
-        if (!versionTest) {
-            throw new RangeError('Could not comprehend a valid version from 
the string "' + verPref.value + '" of platform-boundary "' + verPref.name + 
'".');
+        var filePath = path.join(directory, file);
+        // skip if this is a folder
+        if (!fs.lstatSync(filePath).isFile()) {
+            return;
         }
 
-        platformVersionSet[versionPropertyName] = versionTest;
-    });
-
-    for (var platformName in platformBag) {
-        // Go through each and make sure there are min/max set
-        var versionPref = platformBag[platformName];
-        if (!versionPref.MaxVersionTested && !!versionPref.MinVersion) { // 
min is set, but max is not
-            versionPref.MaxVersionTested = versionPref.MinVersion;
+        var content = fs.readFileSync(filePath);
+        if (content[0] !== 0xEF && content[1] !== 0xBE && content[2] !== 0xBB) 
{
+            fs.writeFileSync(filePath, '\ufeff' + content);
         }
-        else if (!versionPref.MinVersion && !!versionPref.MaxVersionTested) { 
// max is set, min is not
-            versionPref.MinVersion = versionPref.MaxVersionTested;
-        }
-        else if (!versionPref.MinVersion && !versionPref.MaxVersionTested) { 
// neither are set
-            versionPref.MinVersion = BASE_UAP_VERSION;
-            versionPref.MaxVersionTested = BASE_UAP_VERSION;
-        }
-        else { // both are set
-            if (versionPref.MinVersion.gt(versionPref.MaxVersionTested)) {
-                versionPref.MaxVersionTested = versionPref.MinVersion;
-            }
-        }
-    }
-
-    if (Object.keys(platformBag).length === 0) {
-        platformBag['Windows.Universal'] = { MinVersion: BASE_UAP_VERSION, 
MaxVersionTested: BASE_UAP_VERSION };
-    }
-
-    return platformBag;
-}
-
-/**
- * Checks to see whether access rules or
- * @param config {ConfigParser} The configuration parser
- * @return {boolean} True if the config specifies remote URIs for access or 
start; false otherwise.
- */
-function checkForRemoteModeUris(config) {
-    var accessRules = config.getNavigationWhitelistRules();
-    var startPage = config.startPage();
-    var test = /(https?|ms-appx-web):\/\//i;
-
-    var hasRemoteUri = test.test(startPage);
-    hasRemoteUri = hasRemoteUri || accessRules.some(function(rule) {
-        return test.test(rule);
     });
-
-    return hasRemoteUri;
 }
 
 /**
- * Checks for capabilities which are Restricted in Windows 10 UAP.
- * @param appxManifestCapabilitiesElement {ElementTree.Element} The appx 
manifest element for <capabilities>
- * @return {string[]|false} An array of restricted capability names, or false.
+ * 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 
checkForRestrictedRemoteCapabilityDeclarations(appxManifestCapabilitiesElement) 
{
-    if (!appxManifestCapabilitiesElement)
-        return false;
-
-    var hasRestrictedCapabilities = false;
-    var foundRestrictedCapabilities = [];
+function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
+
+    events.emit('verbose', 'Generating config.xml from defaults for platform 
"windows"');
+
+    // First cleanup current config and merge project's one into own
+    var defaultConfig = locations.defaultConfigXml;
+    var ownConfig = locations.configXml;
+    var sourceCfg = sourceConfig.path;
+    // If defaults.xml is present, overwrite platform config.xml with it.
+    // Otherwise save whatever is there as defaults so it can be
+    // restored or copy project config into platform if none exists.
+    if (fs.existsSync(defaultConfig)) {
+        events.emit('verbose', 'Generating config.xml from defaults for 
platform "' + this.platform + '"');
+        shell.cp('-f', defaultConfig, ownConfig);
+    } else if (fs.existsSync(ownConfig)) {
+        shell.cp('-f', ownConfig, defaultConfig);
+    } else {
+        shell.cp('-f', sourceCfg, ownConfig);
+    }
 
-    var children = appxManifestCapabilitiesElement.getchildren();
-    var declaredCapabilities = children.map(function(el) {
-        return el.attrib.Name;
-    });
+    // Then apply config changes from global munge to all config files
+    // in project (including project's config)
+    configMunger.reapply_global_munge().save_all();
 
-    UAP_RESTRICTED_CAPS.forEach(function(cap) {
-        if (declaredCapabilities.indexOf(cap) > -1) {
-            hasRestrictedCapabilities = true;
-            foundRestrictedCapabilities.push(cap);
-        }
-    });
+    // Merge changes from app's config.xml into platform's one
+    var config = new ConfigParser(ownConfig);
+    xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
+        config.doc.getroot(), 'windows', /*clobber=*/true);
+    // CB-6976 Windows Universal Apps. For smooth transition and to prevent 
mass api failures
+    // we allow using windows8 tag for new windows platform
+    xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
+        config.doc.getroot(), 'windows8', /*clobber=*/true);
 
-    return hasRestrictedCapabilities ? foundRestrictedCapabilities : 
hasRestrictedCapabilities;
+    config.write();
+    return config;
 }
 
 /**
- * Checks for capabilities which require the uap: prefix in Windows 10.
- * @param appxManifestCapabilitiesElement {ElementTree.Element} The appx 
manifest element for <capabilities>
+ * 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 ensureUapPrefixedCapabilities(appxManifestCapabilitiesElement) {
-    var children = appxManifestCapabilitiesElement.getchildren();
-    var declaredCapabilities = children.map(function(el) {
-        return { name: el.attrib.Name, element: el, elementName: el.tag };
-    });
-
-    declaredCapabilities.forEach(function(cap) {
-        if (CAPS_NEEDING_UAPNS.indexOf(cap.name) > -1) {
-            if (cap.elementName.indexOf('uap:') === -1) {
-                cap.elementName = 'uap:' + cap.elementName;
-                cap.element.tag = cap.elementName;
-            }
-        }
+function updateWwwFrom(cordovaProject, destinations) {
+
+    shell.rm('-rf', destinations.www);
+    shell.mkdir('-p', destinations.www);
+    // Copy source files from project's www directory
+    shell.cp('-rf', path.join(cordovaProject.locations.www, '*'), 
destinations.www);
+    // Override www sources by files in 'platform_www' directory
+    shell.cp('-rf', path.join(destinations.platformWww, '*'), 
destinations.www);
+
+    // If project contains 'merges' for our platform, use them as another 
overrides
+    // CB-6976 Windows Universal Apps. For smooth transition from 'windows8' 
platform
+    // we allow using 'windows8' merges for new 'windows' platform
+    ['windows8', 'windows'].forEach(function (platform) {
+        var mergesPath = path.join(cordovaProject.root, 'merges', platform);
+        // if no 'merges' directory found, no further actions needed
+        if (!fs.existsSync(mergesPath)) return;
+
+        events.emit('verbose', 'Found "merges" for ' + platform + ' platform. 
Copying over existing "www" files.');
+        var overrides = path.join(mergesPath, '*');
+        shell.cp('-rf', overrides, destinations.www);
     });
 }
 
 /**
- * Applies the ToastCapable attribute to the VisualElements tag
- * @param config {ConfigParser} The configuration reader
- * @param manifest {et.ElementTree} The manifest file
- * @namespacePrefix {String} The XML namespace for the VisualElements tag, in 
the form 'm2:'
+ * Updates project structure and AppxManifest according to project's 
configuration.
+ *
+ * @param   {ConfigParser}  projectConfig  A project's configuration that will
+ *   be used to update project
+ * @param   {Object}  locations       A map of locations for this platform
  */
-function applyToastCapability(config, manifest, namespacePrefix) {
-    var isToastCapable = config.getPreference('WindowsToastCapable');
-    isToastCapable = (isToastCapable && 
isToastCapable.toString().toLowerCase() === 'true');
-
-    var visualElementsName = './/' + namespacePrefix + 'VisualElements';
-    var visualElems = manifest.find(visualElementsName);
+function updateProjectAccordingTo(projectConfig, locations) {
+    // Apply appxmanifest changes
+    [MANIFEST_WINDOWS, MANIFEST_WINDOWS8, MANIFEST_WINDOWS10, MANIFEST_PHONE]
+    .forEach(function(manifestFile) {
+        updateManifestFile(projectConfig, path.join(locations.root, 
manifestFile));
+    });
 
-    if (isToastCapable) {
-        visualElems.attrib.ToastCapable = 'true';
-    }
-    else {
-        delete visualElems.attrib.ToastCapable;
+    if (process.platform === 'win32') {
+        applyUAPVersionToProject(path.join(locations.root, PROJECT_WINDOWS10), 
getUAPVersions());
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to