You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ka...@apache.org on 2014/04/15 02:33:01 UTC

[1/8] CB-6421: Move tests from e2e to spec

Repository: cordova-cli
Updated Branches:
  refs/heads/master de2500bf8 -> 38db7a2db


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/platform.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform.spec.js b/spec/platform.spec.js
new file mode 100644
index 0000000..e16d51d
--- /dev/null
+++ b/spec/platform.spec.js
@@ -0,0 +1,108 @@
+
+var helpers = require('./helpers'),
+    path = require('path'),
+    fs = require('fs'),
+    shell = require('shelljs'),
+    platforms = require('../platforms'),
+    superspawn = require('../src/superspawn'),
+    config = require('../src/config'),
+    Q = require('q'),
+    events = require('../src/events'),
+    cordova = require('../cordova');
+
+var tmpDir = helpers.tmpDir('platform_test');
+var project = path.join(tmpDir, 'project');
+
+var platformParser = platforms[helpers.testPlatform].parser;
+
+describe('platform end-to-end', function() {
+    var results;
+
+    beforeEach(function() {
+        shell.rm('-rf', tmpDir);
+    });
+    afterEach(function() {
+        process.chdir(path.join(__dirname, '..'));  // Needed to rm the dir on Windows.
+        shell.rm('-rf', tmpDir);
+    });
+
+    // Factoring out some repeated checks.
+    function emptyPlatformList() {
+        return cordova.raw.platform('list').then(function() {
+            var installed = results.match(/Installed platforms: (.*)/);
+            expect(installed).toBeDefined();
+            expect(installed[1].indexOf(helpers.testPlatform)).toBe(-1);
+        });
+    }
+
+    function fullPlatformList() {
+        return cordova.raw.platform('list').then(function() {
+            var installed = results.match(/Installed platforms: (.*)/);
+            expect(installed).toBeDefined();
+            expect(installed[1].indexOf(helpers.testPlatform)).toBeGreaterThan(-1);
+        });
+    }
+
+    // The flows we want to test are add, rm, list, and upgrade.
+    // They should run the appropriate hooks.
+    // They should fail when not inside a Cordova project.
+    // These tests deliberately have no beforeEach and afterEach that are cleaning things up.
+    it('should successfully run', function(done) {
+        // cp then mv because we need to copy everything, but that means it'll copy the whole directory.
+        // Using /* doesn't work because of hidden files.
+        shell.cp('-R', path.join(__dirname, 'fixtures', 'base'), tmpDir);
+        shell.mv(path.join(tmpDir, 'base'), project);
+        process.chdir(project);
+
+        // Now we load the config.json in the newly created project and edit the target platform's lib entry
+        // to point at the fixture version. This is necessary so that cordova.prepare can find cordova.js there.
+        var c = config.read(project);
+        c.lib[helpers.testPlatform].uri = path.join(__dirname, 'fixtures', 'platforms', helpers.testPlatform + '-lib');
+        config.write(project, c);
+
+        // The config.json in the fixture project points at fake "local" paths.
+        // Since it's not a URL, the lazy-loader will just return the junk path.
+        spyOn(superspawn, 'spawn').andCallFake(function(cmd, args) {
+            if (cmd.match(/create\b/)) {
+                // This is a call to the bin/create script, so do the copy ourselves.
+                shell.cp('-R', path.join(__dirname, 'fixtures', 'platforms', 'android'), path.join(project, 'platforms'));
+            } else if(cmd.match(/version\b/)) {
+                return Q('3.3.0');
+            } else if(cmd.match(/update\b/)) {
+                fs.writeFileSync(path.join(project, 'platforms', helpers.testPlatform, 'updated'), 'I was updated!', 'utf-8');
+            }
+            return Q();
+        });
+
+        events.on('results', function(res) { results = res; });
+
+        // Check there are no platforms yet.
+        emptyPlatformList().then(function() {
+            // Add the testing platform.
+            return cordova.raw.platform('add', [helpers.testPlatform]);
+        }).then(function() {
+            // Check the platform add was successful.
+            expect(path.join(project, 'platforms', helpers.testPlatform)).toExist();
+            expect(path.join(project, 'merges', helpers.testPlatform)).toExist();
+            expect(path.join(project, 'platforms', helpers.testPlatform, 'cordova')).toExist();
+        }).then(fullPlatformList) // Check for it in platform ls.
+        .then(function() {
+            // Try to update the platform.
+            return cordova.raw.platform('update', [helpers.testPlatform]);
+        }).then(function() {
+            // Our fake update script in the exec mock above creates this dummy file.
+            expect(path.join(project, 'platforms', helpers.testPlatform, 'updated')).toExist();
+        }).then(fullPlatformList) // Platform should still be in platform ls.
+        .then(function() {
+            // And now remove it.
+            return cordova.raw.platform('rm', [helpers.testPlatform]);
+        }).then(function() {
+            // It should be gone.
+            expect(path.join(project, 'platforms', helpers.testPlatform)).not.toExist();
+        }).then(emptyPlatformList) // platform ls should be empty too.
+        .fail(function(err) {
+            expect(err).toBeUndefined();
+        }).fin(done);
+    });
+});
+

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/plugin.spec.js
----------------------------------------------------------------------
diff --git a/spec/plugin.spec.js b/spec/plugin.spec.js
new file mode 100644
index 0000000..2ad7b08
--- /dev/null
+++ b/spec/plugin.spec.js
@@ -0,0 +1,68 @@
+
+var helpers = require('./helpers'),
+    path = require('path'),
+    fs = require('fs'),
+    shell = require('shelljs'),
+    Q = require('q'),
+    events = require('../src/events'),
+    cordova = require('../cordova');
+
+var tmpDir = helpers.tmpDir('plugin_test');
+var project = path.join(tmpDir, 'project');
+var pluginsDir = path.join(__dirname, 'fixtures', 'plugins');
+var pluginId = 'org.apache.cordova.fakeplugin1';
+
+describe('plugin end-to-end', function() {
+    var results;
+
+    beforeEach(function() {
+        shell.rm('-rf', project);
+    });
+    afterEach(function() {
+        process.chdir(path.join(__dirname, '..'));  // Needed to rm the dir on Windows.
+        shell.rm('-rf', tmpDir);
+    });
+
+    // The flow tested is: ls, add, ls, rm, ls.
+    // Plugin dependencies are not tested as that should be corvered in plugman tests.
+    // TODO (kamrik): Test the 'plugin search' command.
+    it('should successfully run', function(done) {
+        // cp then mv because we need to copy everything, but that means it'll copy the whole directory.
+        // Using /* doesn't work because of hidden files.
+        shell.cp('-R', path.join(__dirname, 'fixtures', 'base'), tmpDir);
+        shell.mv(path.join(tmpDir, 'base'), project);
+        // Copy some platform to avoid working on a project with no platforms.
+        shell.cp('-R', path.join(__dirname, 'fixtures', 'platforms', helpers.testPlatform), path.join(project, 'platforms'));
+        process.chdir(project);
+
+        events.on('results', function(res) { results = res; });
+
+        // Check there are no plugins yet.
+        cordova.raw.plugin('list').then(function() {
+            expect(results).toMatch(/No plugins added/gi);
+        }).then(function() {
+            // Add a fake plugin from fixtures.
+            return cordova.raw.plugin('add', path.join(pluginsDir, 'fake1'));
+        }).then(function() {
+           expect(path.join(project, 'plugins', pluginId, 'plugin.xml')).toExist();
+        }).then(function() {
+            return cordova.raw.plugin('ls');
+        }).then(function() {
+            expect(results).toContain(pluginId);
+            expect(results.length).toEqual(1);
+        }).then(function() {
+            // And now remove it.
+            return cordova.raw.plugin('rm', pluginId);
+        }).then(function() {
+            // The whole dir should be gone.
+            expect(path.join(project, 'plugins', pluginId)).not.toExist();
+        }).then(function() {
+            return cordova.raw.plugin('ls');
+        }).then(function() {
+            expect(results).toMatch(/No plugins added/gi);
+        }).fail(function(err) {
+            console.log(err);
+            expect(err).toBeUndefined();
+        }).fin(done);
+    });
+});


[2/8] CB-6421: Move tests from e2e to spec

Posted by ka...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/build.xml
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/build.xml b/spec/fixtures/platforms/android/build.xml
new file mode 100644
index 0000000..9674edf
--- /dev/null
+++ b/spec/fixtures/platforms/android/build.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="TestBase" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- if sdk.dir was not set from one of the property file, then
+         get it from the ANDROID_HOME env var.
+         This must be done before we load project.properties since
+         the proguard config can use sdk.dir -->
+    <property environment="env" />
+    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+        <isset property="env.ANDROID_HOME" />
+    </condition>
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+            unless="sdk.dir"
+    />
+
+    <!--
+        Import per project custom build rules if present at the root of the project.
+        This is the place to put custom intermediary targets such as:
+            -pre-build
+            -pre-compile
+            -post-compile (This is typically used for code obfuscation.
+                           Compiled code location: ${out.classes.absolute.dir}
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
+            -post-package
+            -post-build
+            -pre-clean
+    -->
+    <import file="custom_rules.xml" optional="true" />
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/build
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/build b/spec/fixtures/platforms/android/cordova/build
new file mode 100755
index 0000000..7028eb8
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/build
@@ -0,0 +1,35 @@
+#!/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 build = require('./lib/build'),
+    reqs  = require('./lib/check_reqs'),
+    args  = process.argv;
+
+// Support basic help commands
+if(args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
+                    args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {
+    build.help();
+} else if(reqs.run()) {
+    build.run(args[2]);
+    process.exit(0);
+} else {
+    process.exit(2);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/check_reqs
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/check_reqs b/spec/fixtures/platforms/android/cordova/check_reqs
new file mode 100755
index 0000000..4a8abee
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/check_reqs
@@ -0,0 +1,27 @@
+#!/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 check_reqs = require('./lib/check_reqs');
+
+if(!check_reqs.run()) {
+      process.exit(2);
+}
+

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/clean
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/clean b/spec/fixtures/platforms/android/cordova/clean
new file mode 100755
index 0000000..70c4ca8
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/clean
@@ -0,0 +1,34 @@
+#!/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 clean = require('./lib/clean'),
+    reqs  = require('./lib/check_reqs'),
+    args  = process.argv;
+
+// Usage support for when args are given
+if(args.length > 2) {
+    clean.help();
+} else if(reqs.run()) {
+    clean.run();
+    process.exit(0);
+} else {
+    process.exit(2);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/defaults.xml
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/defaults.xml b/spec/fixtures/platforms/android/cordova/defaults.xml
new file mode 100644
index 0000000..24e5725
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/defaults.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<widget xmlns     = "http://www.w3.org/ns/widgets"
+        id        = "io.cordova.helloCordova"
+        version   = "2.0.0">
+    <name>Hello Cordova</name>
+
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+
+    <author href="http://cordova.io" email="dev@cordova.apache.org">
+        Apache Cordova Team
+    </author>
+
+    <access origin="*"/>
+
+    <!-- <content src="http://mysite.com/myapp.html" /> for external pages -->
+    <content src="index.html" />
+
+    <preference name="loglevel" value="DEBUG" />
+    <!--
+      <preference name="splashscreen" value="resourceName" />
+      <preference name="backgroundColor" value="0xFFF" />
+      <preference name="loadUrlTimeoutValue" value="20000" />
+      <preference name="InAppBrowserStorageEnabled" value="true" />
+      <preference name="disallowOverscroll" value="true" />
+    -->
+    <!-- This is required for native Android hooks -->
+    <feature name="App">
+        <param name="android-package" value="org.apache.cordova.App" />
+    </feature>
+</widget>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/appinfo.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/appinfo.js b/spec/fixtures/platforms/android/cordova/lib/appinfo.js
new file mode 100755
index 0000000..1f8ebe2
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/appinfo.js
@@ -0,0 +1,41 @@
+#!/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 path = require('path');
+var fs = require('fs');
+var cachedAppInfo = null;
+
+function readAppInfoFromManifest() {
+    var manifestPath = path.join(__dirname, '..', '..', 'AndroidManifest.xml');
+    var manifestData = fs.readFileSync(manifestPath, {encoding:'utf8'});
+    var packageName = /\bpackage\s*=\s*"(.+?)"/.exec(manifestData);
+    if (!packageName) throw new Error('Could not find package name within ' + manifestPath);
+    var activityTag = /<activity\b[\s\S]*<\/activity>/.exec(manifestData);
+    if (!activityTag) throw new Error('Could not find <activity> within ' + manifestPath);
+    var activityName = /\bandroid:name\s*=\s*"(.+?)"/.exec(activityTag);
+    if (!activityName) throw new Error('Could not find android:name within ' + manifestPath);
+
+    return packageName[1] + '/.' + activityName[1];
+}
+
+exports.getActivityName = function() {
+    return cachedAppInfo = cachedAppInfo || readAppInfoFromManifest();
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/build.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/build.js b/spec/fixtures/platforms/android/cordova/lib/build.js
new file mode 100755
index 0000000..7bc33ca
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/build.js
@@ -0,0 +1,89 @@
+#!/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 shell   = require('shelljs'),
+    clean   = require('./clean'),
+    path    = require('path'),
+    fs      = require('fs'),
+    ROOT    = path.join(__dirname, '..', '..');
+
+/*
+ * Builds the project with ant.
+ */
+module.exports.run = function(build_type) {
+    //default build type
+    build_type = typeof build_type !== 'undefined' ? build_type : "--debug";
+    var cmd;
+    switch(build_type) {
+        case '--debug' :
+            clean.run();
+            cmd = 'ant debug -f ' + path.join(ROOT, 'build.xml');
+            break;
+        case '--release' :
+            clean.run();
+            cmd = 'ant release -f ' + path.join(ROOT, 'build.xml');
+            break;
+        case '--nobuild' :
+            console.log('Skipping build...');
+            break;
+        default :
+           console.error('Build option \'' + build_type + '\' not recognized.');
+           process.exit(2);
+           break;
+    }
+    if(cmd) {
+        var result = shell.exec(cmd, {silent:false, async:false});
+        if(result.code > 0) {
+            console.error('ERROR: Failed to build android project.');
+            console.error(result.output);
+            process.exit(2);
+        }
+    }
+}
+
+/*
+ * Gets the path to the apk file, if not such file exists then
+ * the script will error out. (should we error or just return undefined?)
+ */
+module.exports.get_apk = function() {
+    if(fs.existsSync(path.join(ROOT, 'bin'))) {
+        var bin_files = fs.readdirSync(path.join(ROOT, 'bin'));
+        for (file in bin_files) {
+            if(path.extname(bin_files[file]) == '.apk') {
+                return path.join(ROOT, 'bin', bin_files[file]);
+            }
+        }
+        console.error('ERROR : No .apk found in \'bin\' folder');
+        process.exit(2);
+    } else {
+        console.error('ERROR : unable to find project bin folder, could not locate .apk');
+        process.exit(2);
+    }
+}
+
+module.exports.help = function() {
+    console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'build')) + ' [build_type]');
+    console.log('Build Types : ');
+    console.log('    \'--debug\': Default build, will build project in using ant debug');
+    console.log('    \'--release\': will build project using ant release');
+    console.log('    \'--nobuild\': will skip build process (can be used with run command)');
+    process.exit(0);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/check_reqs.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/check_reqs.js b/spec/fixtures/platforms/android/cordova/lib/check_reqs.js
new file mode 100755
index 0000000..c064499
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/check_reqs.js
@@ -0,0 +1,78 @@
+#!/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 shell = require('shelljs'),
+    path  = require('path'),
+    fs    = require('fs'),
+    ROOT  = path.join(__dirname, '..', '..');
+
+// Get valid target from framework/project.properties
+module.exports.get_target = function() {
+    if(fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
+        var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'framework', 'project.properties'));
+        return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
+    } else if (fs.existsSync(path.join(ROOT, 'project.properties'))) {
+        // if no target found, we're probably in a project and project.properties is in ROOT.
+        var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties'));
+        return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
+    }
+}
+
+module.exports.check_ant = function() {
+    var test = shell.exec('ant -version', {silent:true, async:false});
+    if(test.code > 0) {
+        console.error('ERROR : executing command \'ant\', make sure you have ant installed and added to your path.');
+        return false;
+    }
+    return true;
+}
+
+module.exports.check_java = function() {
+    if(process.env.JAVA_HOME) {
+        var test = shell.exec('java', {silent:true, async:false});
+        if(test.code > 0) {
+            console.error('ERROR : executing command \'java\', make sure you java environment is set up. Including your JDK and JRE.');
+            return false;
+        }
+        return true;
+    } else {
+        console.error('ERROR : Make sure JAVA_HOME is set, as well as paths to your JDK and JRE for java.');
+        return false;
+    }
+}
+
+module.exports.check_android = function() {
+    var valid_target = this.get_target();
+    var targets = shell.exec('android list targets', {silent:true, async:false});
+
+    if(targets.code > 0 && targets.output.match(/command\snot\sfound/)) {
+        console.error('The command \"android\" failed. Make sure you have the latest Android SDK installed, and the \"android\" command (inside the tools/ folder) is added to your path.');
+        return false;
+    } else if(!targets.output.match(valid_target)) {
+        console.error('Please install Android target ' + valid_target.split('-')[1] + ' (the Android newest SDK). Make sure you have the latest Android tools installed as well. Run \"android\" from your command-line to install/update any missing SDKs or tools.');
+        return false;
+    }
+    return true;
+}
+
+module.exports.run = function() {
+    return this.check_ant() && this.check_java && this.check_android();
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/clean.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/clean.js b/spec/fixtures/platforms/android/cordova/lib/clean.js
new file mode 100755
index 0000000..8f14015
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/clean.js
@@ -0,0 +1,43 @@
+#!/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 shell = require('shelljs'),
+    path  = require('path'),
+    ROOT = path.join(__dirname, '..', '..');
+
+/*
+ * Cleans the project using ant
+ */
+module.exports.run = function() {
+    var cmd = 'ant clean -f ' + path.join(ROOT, 'build.xml');
+    var result = shell.exec(cmd, {silent:false, async:false});
+    if (result.code > 0) {
+        console.error('ERROR: Failed to clean android project.');
+        console.error(result.output);
+        process.exit(2);
+    }
+}
+
+module.exports.help = function() {
+    console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'clean')));
+    console.log('Cleans the project directory.');
+    process.exit(0);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/device.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/device.js b/spec/fixtures/platforms/android/cordova/lib/device.js
new file mode 100755
index 0000000..363dc2b
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/device.js
@@ -0,0 +1,95 @@
+#!/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 shell = require('shelljs'),
+    path  = require('path'),
+    build = require('./build'),
+    appinfo = require('./appinfo'),
+    exec  = require('child_process').exec,
+    ROOT = path.join(__dirname, '..', '..');
+
+/**
+ * Returns a list of the device ID's found
+ */
+module.exports.list = function() {
+    var cmd = 'adb devices';
+    var result = shell.exec(cmd, {silent:true, async:false});
+    if (result.code > 0) {
+        console.error('Failed to execute android command \'' + cmd + '\'.');
+        process.exit(2);
+    } else {
+        var response = result.output.split('\n');
+        var device_list = [];
+        for (var i = 1; i < response.length; i++) {
+            if (response[i].match(/\w+\tdevice/) && !response[i].match(/emulator/)) {
+                device_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
+            }
+        }
+        return device_list;
+    }
+}
+
+/*
+ * Installs a previously built application on the device
+ * and launches it.
+ */
+module.exports.install = function(target) {
+    var device_list = this.list();
+    if (device_list.length > 0) {
+        // default device
+        target = typeof target !== 'undefined' ? target : device_list[0];
+        if (device_list.indexOf(target) > -1) {
+            var apk_path = build.get_apk();
+            var launchName = appinfo.getActivityName();
+            console.log('Installing app on device...');
+            cmd = 'adb -s ' + target + ' install -r ' + apk_path;
+            var install = shell.exec(cmd, {silent:false, async:false});
+            if (install.error || install.output.match(/Failure/)) {
+                console.error('ERROR : Failed to install apk to device : ');
+                console.error(install.output);
+                process.exit(2);
+            }
+
+            //unlock screen
+            cmd = 'adb -s ' + target + ' shell input keyevent 82';
+            shell.exec(cmd, {silent:true, async:false});
+
+            // launch the application
+            console.log('Launching application...');
+            cmd = 'adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
+            var launch = shell.exec(cmd, {silent:true, async:false});
+            if(launch.code > 0) {
+                console.error('ERROR : Failed to launch application on emulator : ' + launch.error);
+                console.error(launch.output);
+                process.exit(2);
+            } else {
+                console.log('LAUNCH SUCCESS');
+            }
+        } else {
+            console.error('ERROR : Unable to find target \'' + target + '\'.');
+            console.error('Failed to deploy to device.');
+            process.exit(2);
+        }
+    } else {
+        console.error('ERROR : Failed to deploy to device, no devices found.');
+        process.exit(2);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/emulator.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/emulator.js b/spec/fixtures/platforms/android/cordova/lib/emulator.js
new file mode 100755
index 0000000..cc658a9
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/emulator.js
@@ -0,0 +1,337 @@
+#!/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 shell = require('shelljs'),
+    path  = require('path'),
+    appinfo = require('./appinfo'),
+    build = require('./build'),
+    ROOT  = path.join(__dirname, '..', '..'),
+    new_emulator = 'cordova_emulator';
+
+/**
+ * Returns a list of emulator images in the form of objects
+ * {
+       name   : <emulator_name>,
+       path   : <path_to_emulator_image>,
+       target : <api_target>,
+       abi    : <cpu>,
+       skin   : <skin>
+   }
+ */
+module.exports.list_images = function() {
+    var cmd = 'android list avds';
+    var result = shell.exec(cmd, {silent:true, async:false});
+    if (result.code > 0) {
+        console.error('Failed to execute android command \'' + cmd + '\'.');
+        process.exit(2);
+    } else {
+        var response = result.output.split('\n');
+        var emulator_list = [];
+        for (var i = 1; i < response.length; i++) {
+            // To return more detailed information use img_obj
+            var img_obj = {};
+            if (response[i].match(/Name:\s/)) {
+                img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
+                if (response[i + 1].match(/Path:\s/)) {
+                    i++;
+                    img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
+                }
+                if (response[i + 1].match(/\(API\slevel\s/)) {
+                    i++;
+                    img_obj['target'] = response[i].replace('\r', '');
+                }
+                if (response[i + 1].match(/ABI:\s/)) {
+                    i++;
+                    img_obj['abi'] = response[i].split('ABI: ')[1].replace('\r', '');
+                }
+                if (response[i + 1].match(/Skin:\s/)) {
+                    i++;
+                    img_obj['skin'] = response[i].split('Skin: ')[1].replace('\r', '');
+                }
+
+                emulator_list.push(img_obj);
+            }
+            /* To just return a list of names use this
+            if (response[i].match(/Name:\s/)) {
+                emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
+            }*/
+
+        }
+        return emulator_list;
+    }
+}
+
+/**
+ * Will return the closest avd to the projects target
+ * or undefined if no avds exist.
+ */
+module.exports.best_image = function() {
+    var project_target = this.get_target().replace('android-', '');
+    var images = this.list_images();
+    var closest = 9999;
+    var best = images[0];
+    for (i in images) {
+        var target = images[i].target;
+        if(target) {
+            var num = target.split('(API level ')[1].replace(')', '');
+            if (num == project_target) {
+                return images[i];
+            } else if (project_target - num < closest && project_target > num) {
+                var closest = project_target - num;
+                best = images[i];
+            }
+        }
+    }
+    return best;
+}
+
+module.exports.list_started = function() {
+    var cmd = 'adb devices';
+    var result = shell.exec(cmd, {silent:true, async:false});
+    if (result.code > 0) {
+        console.error('Failed to execute android command \'' + cmd + '\'.');
+        process.exit(2);
+    } else {
+        var response = result.output.split('\n');
+        var started_emulator_list = [];
+        for (var i = 1; i < response.length; i++) {
+            if (response[i].match(/device/) && response[i].match(/emulator/)) {
+                started_emulator_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
+            }
+        }
+        return started_emulator_list;
+    }
+}
+
+module.exports.get_target = function() {
+    var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties'));
+    return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
+}
+
+module.exports.list_targets = function() {
+    var target_out = shell.exec('android list targets', {silent:true, async:false}).output.split('\n');
+    var targets = [];
+    for (var i = target_out.length; i >= 0; i--) {
+        if(target_out[i].match(/id:/)) {
+            targets.push(targets[i].split(' ')[1]);
+        }
+    }
+    return targets;
+}
+
+/*
+ * Starts an emulator with the given ID,
+ * and returns the started ID of that emulator.
+ * If no ID is given it will used the first image availible,
+ * if no image is availible it will error out (maybe create one?).
+ */
+module.exports.start = function(emulator_ID) {
+    var started_emulators = this.list_started();
+    var num_started = started_emulators.length;
+    if (typeof emulator_ID === 'undefined') {
+        var emulator_list = this.list_images();
+        if (emulator_list.length > 0) {
+            emulator_ID = this.best_image().name;
+            console.log('WARNING : no emulator specified, defaulting to ' + emulator_ID);
+        } else {
+            console.error('ERROR : No emulator images (avds) found, if you would like to create an');
+            console.error(' avd follow the instructions provided here : ');
+            console.error(' http://developer.android.com/tools/devices/index.html')
+            console.error(' Or run \'android create avd --name <name> --target <targetID>\' ');
+            console.error(' in on the command line.');
+            process.exit(2);
+            /*console.log('WARNING : no emulators availible, creating \'' + new_emulator + '\'.');
+            this.create_image(new_emulator, this.get_target());
+            emulator_ID = new_emulator;*/
+        }
+    }
+
+    var pipe_null = (process.platform == 'win32' || process.platform == 'win64'? '> NUL' : '> /dev/null');
+    var cmd = 'emulator -avd ' + emulator_ID + ' ' + pipe_null + ' &';
+    if(process.platform == 'win32' || process.platform == 'win64') {
+        cmd = '%comspec% /c start cmd /c ' + cmd;
+    }
+    var result = shell.exec(cmd, {silent:true, async:false}, function(code, output) {
+        if (code > 0) {
+            console.error('Failed to execute android command \'' + cmd + '\'.');
+            console.error(output);
+            process.exit(2);
+        }
+    });
+
+    // wait for emulator to start
+    console.log('Waiting for emulator...');
+    var new_started = this.wait_for_emulator(num_started);
+    var emulator_id;
+    if (new_started.length > 1) {
+        for (i in new_started) {
+            console.log(new_started[i]);
+            console.log(started_emulators.indexOf(new_started[i]));
+            if (started_emulators.indexOf(new_started[i]) < 0) {
+                emulator_id = new_started[i];
+            }
+        }
+    } else {
+        emulator_id = new_started[0];
+    }
+    if (!emulator_id) {
+        console.error('ERROR :  Failed to start emulator, could not find new emulator');
+        process.exit(2);
+    }
+
+    //wait for emulator to boot up
+    process.stdout.write('Booting up emulator (this may take a while)...');
+    this.wait_for_boot(emulator_id);
+    console.log('BOOT COMPLETE');
+
+    //unlock screen
+    cmd = 'adb -s ' + emulator_id + ' shell input keyevent 82';
+    shell.exec(cmd, {silent:false, async:false});
+
+    //return the new emulator id for the started emulators
+    return emulator_id;
+}
+
+/*
+ * Waits for the new emulator to apear on the started-emulator list.
+ */
+module.exports.wait_for_emulator = function(num_running) {
+    var new_started = this.list_started();
+    if (new_started.length > num_running) {
+        return new_started;
+    } else {
+        this.sleep(1);
+        return this.wait_for_emulator(num_running);
+    }
+}
+
+/*
+ * Waits for the boot animation property of the emulator to switch to 'stopped'
+ */
+module.exports.wait_for_boot = function(emulator_id) {
+    var cmd;
+    // ShellJS opens a lot of file handles, and the default on OS X is too small.
+    // TODO : This is not working, need to find a better way to increese the ulimit.
+    if(process.platform == 'win32' || process.platform == 'win64') {
+        cmd = 'adb -s ' + emulator_id + ' shell getprop init.svc.bootanim';
+    } else {
+        cmd = 'ulimit -S -n 4096; adb -s ' + emulator_id + ' shell getprop init.svc.bootanim';
+    }
+    var boot_anim = shell.exec(cmd, {silent:true, async:false});
+    if (boot_anim.output.match(/stopped/)) {
+        return;
+    } else {
+        process.stdout.write('.');
+        this.sleep(3);
+        return this.wait_for_boot(emulator_id);
+    }
+}
+
+/*
+ * TODO : find a better way to wait for the emulator (maybe using async methods?)
+ */
+module.exports.sleep = function(time_sec) {
+    if (process.platform == 'win32' || process.platform == 'win64') {
+        shell.exec('ping 127.0.0.1 -n ' + time_sec, {silent:true, async:false});
+    } else {
+        shell.exec('sleep ' + time_sec, {silent:true, async:false});
+    }
+}
+
+/*
+ * Create avd
+ * TODO : Enter the stdin input required to complete the creation of an avd.
+ */
+module.exports.create_image = function(name, target) {
+    console.log('Creating avd named ' + name);
+    if (target) {
+        var cmd = 'android create avd --name ' + name + ' --target ' + target;
+        var create = shell.exec(cmd, {sient:false, async:false});
+        if (create.error) {
+            console.error('ERROR : Failed to create emulator image : ');
+            console.error(' Do you have the latest android targets including ' + target + '?');
+            console.error(create.output);
+            process.exit(2);
+        }
+    } else {
+        console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
+        var cmd = 'android create avd --name ' + name + ' --target ' + this.list_targets()[0];
+        var create = shell.exec(cmd, {sient:false, async:false});
+        if (create.error) {
+            console.error('ERROR : Failed to create emulator image : ');
+            console.error(create.output);
+            process.exit(2);
+        }
+        console.error('ERROR : Unable to create an avd emulator, no targets found.');
+        console.error('Please insure you have targets availible by runing the "android" command').
+        process.exit(2);
+    }
+}
+
+/*
+ * Installs a previously built application on the emulator and launches it.
+ * If no target is specified, then it picks one.
+ * If no started emulators are found, error out.
+ */
+module.exports.install = function(target) {
+    var emulator_list = this.list_started();
+    if (emulator_list.length < 1) {
+        console.error('ERROR : No started emulators found, please start an emultor before deploying your project.');
+        process.exit(2);
+        /*console.log('WARNING : No started emulators found, attemting to start an avd...');
+        this.start(this.best_image().name);*/
+    }
+    // default emulator
+    target = typeof target !== 'undefined' ? target : emulator_list[0];
+    if (emulator_list.indexOf(target) > -1) {
+        console.log('Installing app on emulator...');
+        var apk_path = build.get_apk();
+        var cmd = 'adb -s ' + target + ' install -r ' + apk_path;
+        var install = shell.exec(cmd, {sient:false, async:false});
+        if (install.error || install.output.match(/Failure/)) {
+            console.error('ERROR : Failed to install apk to emulator : ');
+            console.error(install.output);
+            process.exit(2);
+        }
+
+        //unlock screen
+        cmd = 'adb -s ' + target + ' shell input keyevent 82';
+        shell.exec(cmd, {silent:true, async:false});
+
+        // launch the application
+        console.log('Launching application...');
+        var launchName = appinfo.getActivityName();
+        cmd = 'adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
+        console.log(cmd);
+        var launch = shell.exec(cmd, {silent:false, async:false});
+        if(launch.code > 0) {
+            console.error('ERROR : Failed to launch application on emulator : ' + launch.error);
+            console.error(launch.output);
+            process.exit(2);
+        } else {
+            console.log('LAUNCH SUCCESS');
+        }
+    } else {
+        console.error('ERROR : Unable to find target \'' + target + '\'.');
+        console.error('Failed to deploy to emulator.');
+        process.exit(2);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/install-device
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/install-device b/spec/fixtures/platforms/android/cordova/lib/install-device
new file mode 100755
index 0000000..679efbf
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/install-device
@@ -0,0 +1,38 @@
+#!/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 device = require('./device'),
+    args   = process.argv;
+
+if(args.length > 2) {
+    var install_target;
+    if (args[2].substring(0, 9) == '--target=') {
+        install_target = args[2].substring(9, args[2].length);
+        device.install(install_target);
+        process.exit(0);
+     } else {
+        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+        process.exit(2);
+     }
+} else {
+    device.install();
+    process.exit(0);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/install-emulator
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/install-emulator b/spec/fixtures/platforms/android/cordova/lib/install-emulator
new file mode 100755
index 0000000..c006eb2
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/install-emulator
@@ -0,0 +1,38 @@
+#!/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;
+
+if(args.length > 2) {
+    var install_target;
+    if (args[2].substring(0, 9) == '--target=') {
+        install_target = args[2].substring(9, args[2].length);
+        emulator.install(install_target);
+        process.exit(0);
+     } else {
+        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+        process.exit(2);
+     }
+} else {
+    emulator.install();
+    process.exit(0);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/list-devices
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/list-devices b/spec/fixtures/platforms/android/cordova/lib/list-devices
new file mode 100755
index 0000000..3ef4efa
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/list-devices
@@ -0,0 +1,28 @@
+#!/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 devices = require('./device');
+
+// Usage support for when args are given
+var device_list = devices.list();
+for(device in device_list) {
+    console.log(device_list[device]);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/list-emulator-images
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/list-emulator-images b/spec/fixtures/platforms/android/cordova/lib/list-emulator-images
new file mode 100755
index 0000000..3230537
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/list-emulator-images
@@ -0,0 +1,29 @@
+#!/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 emulators = require('./emulator');
+
+// Usage support for when args are given
+var emulator_list = emulators.list_images();
+for(emulator in emulator_list) {
+    console.log(emulator_list[emulator].name);
+    process.exit(0);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/list-started-emulators
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/list-started-emulators b/spec/fixtures/platforms/android/cordova/lib/list-started-emulators
new file mode 100755
index 0000000..525a64c
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/list-started-emulators
@@ -0,0 +1,29 @@
+#!/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 emulators = require('./emulator');
+
+// Usage support for when args are given
+var emulator_list = emulators.list_started();
+for(emulator in emulator_list) {
+    console.log(emulator_list[emulator]);
+    process.exit(0);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/log.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/log.js b/spec/fixtures/platforms/android/cordova/lib/log.js
new file mode 100755
index 0000000..b85cf60
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/log.js
@@ -0,0 +1,43 @@
+#!/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 shell = require('shelljs'),
+    path  = require('path'),
+    ROOT = path.join(__dirname, '..', '..');
+
+/*
+ * Starts running logcat in the shell.
+ */
+module.exports.run = function() {
+    var cmd = 'adb logcat | grep -v nativeGetEnabledTags';
+    var result = shell.exec(cmd, {silent:false, async:false});
+    if (result.code > 0) {
+        console.error('ERROR: Failed to run logcat command.');
+        console.error(result.output);
+        process.exit(2);
+    }
+}
+
+module.exports.help = function() {
+    console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'log')));
+    console.log('Gives the logcat output on the command line.');
+    process.exit(0);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/run.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/run.js b/spec/fixtures/platforms/android/cordova/lib/run.js
new file mode 100755
index 0000000..787d123
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/run.js
@@ -0,0 +1,124 @@
+#!/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 path  = require('path'),
+    build = require('./build'),
+    emulator = require('./emulator'),
+    device   = require('./device'),
+    ROOT = path.join(__dirname, '..', '..');
+
+/*
+ * Runs the application on a device if availible.
+ * If not 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.
+ */
+ module.exports.run = function(args) {
+    var build_type;
+    var install_target;
+
+    for (var i=2; i<args.length; i++) {
+        if (args[i] == '--debug') {
+            build_type = '--debug';
+        } else if (args[i] == '--release') {
+            build_type = '--release';
+        } else if (args[i] == '--nobuild') {
+            build_type = '--nobuild';
+        } else if (args[i] == '--device') {
+            install_target = '--device';
+        } else if (args[i] == '--emulator') {
+            install_target = '--emulator';
+        } else if (args[i].substring(0, 9) == '--target=') {
+            install_target = args[i].substring(9, args[i].length);
+        } else {
+            console.error('ERROR : Run option \'' + args[i] + '\' not recognized.');
+            process.exit(2);
+        }
+    }
+    build.run(build_type);
+    if (install_target == '--device') {
+        device.install();
+    } else if (install_target == '--emulator') {
+        if (emulator.list_started() == 0) {
+            emulator.start();
+        }
+        emulator.install();
+    } else if (install_target) {
+        var devices = device.list();
+        var started_emulators = emulator.list_started();
+        var avds = emulator.list_images();
+        if (devices.indexOf(install_target) > -1) {
+            device.install(install_target);
+        } else if (started_emulators.indexOf(install_target) > -1) {
+            emulator.install(install_target);
+        } else {
+            // if target emulator isn't started, then start it.
+            var emulator_ID;
+            for(avd in avds) {
+                if(avds[avd].name == install_target) {
+                    emulator_ID = emulator.start(install_target);
+                    emulator.install(emulator_ID);
+                    break;
+                }
+            }
+            if(!emulator_ID) {
+                console.error('ERROR : Target \'' + install_target + '\' not found, unalbe to run project');
+                process.exit(2);
+            }
+        }
+    } else {
+        // no target given, deploy to device if availible, otherwise use the emulator.
+        var device_list = device.list();
+        if (device_list.length > 0) {
+            console.log('WARNING : No target specified, deploying to device \'' + device_list[0] + '\'.');
+            device.install(device_list[0])
+        } else {
+            var emulator_list = emulator.list_started();
+            if (emulator_list.length > 0) {
+                console.log('WARNING : No target specified, deploying to emulator \'' + emulator_list[0] + '\'.');
+                emulator.install(emulator_list[0]);
+            } else {
+                console.log('WARNING : No started emulators found, starting an emulator.');
+                var best_avd = emulator.best_image();
+                if(best_avd) {
+                    var emulator_ID = emulator.start(best_avd.name);
+                    console.log('WARNING : No target specified, deploying to emulator \'' + emulator_ID + '\'.');
+                    emulator.install(emulator_ID);
+                } else {
+                    emulator.start();
+                }
+            }
+        }
+    }
+}
+
+module.exports.help = function() {
+    console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'run')) + ' [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-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/lib/start-emulator
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/lib/start-emulator b/spec/fixtures/platforms/android/cordova/lib/start-emulator
new file mode 100755
index 0000000..5d6c4dd
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/lib/start-emulator
@@ -0,0 +1,38 @@
+#!/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;
+
+if(args.length > 2) {
+    var install_target;
+    if (args[2].substring(0, 9) == '--target=') {
+        install_target = args[2].substring(9, args[2].length);
+        emulator.start(install_target);
+        process.exit(0);
+     } else {
+        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
+        process.exit(2);
+     }
+} else {
+    emulator.start();
+    process.exit(0);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/log
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/log b/spec/fixtures/platforms/android/cordova/log
new file mode 100755
index 0000000..087325f
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/log
@@ -0,0 +1,33 @@
+#!/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 if(reqs.run()) {
+    log.run();
+} else {
+    process.exit(2);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/run
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/run b/spec/fixtures/platforms/android/cordova/run
new file mode 100755
index 0000000..57d7345
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/run
@@ -0,0 +1,35 @@
+#!/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 run  = require('./lib/run'),
+    reqs = require('./lib/check_reqs'),
+    args = process.argv;
+
+// Support basic help commands
+if (args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
+                    args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {
+    run.help();
+} else if(reqs.run()) {
+    run.run(args);
+    process.exit(0);
+} else {
+    process.exit(2);
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/cordova/version
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/cordova/version b/spec/fixtures/platforms/android/cordova/version
new file mode 100755
index 0000000..de1a76d
--- /dev/null
+++ b/spec/fixtures/platforms/android/cordova/version
@@ -0,0 +1,25 @@
+#!/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.
+*/
+
+// Coho updates this line:
+var VERSION = "3.1.0";
+
+console.log(VERSION);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/local.properties
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/local.properties b/spec/fixtures/platforms/android/local.properties
new file mode 100644
index 0000000..d3f5072
--- /dev/null
+++ b/spec/fixtures/platforms/android/local.properties
@@ -0,0 +1,10 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+
+# location of the SDK. This is only used by Ant
+# For customization when using a Version Control System, please read the
+# header note.
+sdk.dir=/Users/braden/cordova/android/android-sdk-macosx

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/proguard-project.txt
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/proguard-project.txt b/spec/fixtures/platforms/android/proguard-project.txt
new file mode 100644
index 0000000..f2fe155
--- /dev/null
+++ b/spec/fixtures/platforms/android/proguard-project.txt
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/project.properties
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/project.properties b/spec/fixtures/platforms/android/project.properties
new file mode 100644
index 0000000..a3ee5ab
--- /dev/null
+++ b/spec/fixtures/platforms/android/project.properties
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-17

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/res/drawable-hdpi/icon.png
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/res/drawable-hdpi/icon.png b/spec/fixtures/platforms/android/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..4d27634
Binary files /dev/null and b/spec/fixtures/platforms/android/res/drawable-hdpi/icon.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/res/drawable-ldpi/icon.png
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/res/drawable-ldpi/icon.png b/spec/fixtures/platforms/android/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000..cd5032a
Binary files /dev/null and b/spec/fixtures/platforms/android/res/drawable-ldpi/icon.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/res/drawable-mdpi/icon.png
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/res/drawable-mdpi/icon.png b/spec/fixtures/platforms/android/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..e79c606
Binary files /dev/null and b/spec/fixtures/platforms/android/res/drawable-mdpi/icon.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/res/drawable-xhdpi/icon.png
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/res/drawable-xhdpi/icon.png b/spec/fixtures/platforms/android/res/drawable-xhdpi/icon.png
new file mode 100644
index 0000000..ec7ffbf
Binary files /dev/null and b/spec/fixtures/platforms/android/res/drawable-xhdpi/icon.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/res/drawable/icon.png
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/res/drawable/icon.png b/spec/fixtures/platforms/android/res/drawable/icon.png
new file mode 100644
index 0000000..ec7ffbf
Binary files /dev/null and b/spec/fixtures/platforms/android/res/drawable/icon.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/res/values/strings.xml
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/res/values/strings.xml b/spec/fixtures/platforms/android/res/values/strings.xml
new file mode 100644
index 0000000..1e706b3
--- /dev/null
+++ b/spec/fixtures/platforms/android/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+    <string name="app_name">TestBase</string>
+</resources>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/res/xml/config.xml
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/res/xml/config.xml b/spec/fixtures/platforms/android/res/xml/config.xml
new file mode 100644
index 0000000..17ca237
--- /dev/null
+++ b/spec/fixtures/platforms/android/res/xml/config.xml
@@ -0,0 +1,18 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="org.testing" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>Hello Cordova</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <access origin="*" />
+    <preference name="loglevel" value="DEBUG" />
+    <feature name="App">
+        <param name="android-package" value="org.apache.cordova.App" />
+    </feature>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <preference name="fullscreen" value="true" />
+    <preference name="webviewbounce" value="true" />
+</widget>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/src/org/testing/TestBase.java
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/src/org/testing/TestBase.java b/spec/fixtures/platforms/android/src/org/testing/TestBase.java
new file mode 100644
index 0000000..928e074
--- /dev/null
+++ b/spec/fixtures/platforms/android/src/org/testing/TestBase.java
@@ -0,0 +1,37 @@
+/*
+       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.
+ */
+
+package org.testing;
+
+import android.os.Bundle;
+import org.apache.cordova.*;
+
+public class TestBase extends CordovaActivity 
+{
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+        super.init();
+        // Set by <content src="index.html" /> in config.xml
+        super.loadUrl(Config.getStartUrl());
+        //super.loadUrl("file:///android_asset/www/index.html")
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/plugins/fake1/plugin.xml
----------------------------------------------------------------------
diff --git a/spec/fixtures/plugins/fake1/plugin.xml b/spec/fixtures/plugins/fake1/plugin.xml
new file mode 100644
index 0000000..ffdc650
--- /dev/null
+++ b/spec/fixtures/plugins/fake1/plugin.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+           id="org.apache.cordova.fakeplugin1"
+      version="0.1.0-dev">
+    <name>Fake1</name>
+    <description>Cordova fake plugin for tests</description>
+    <license>Apache 2.0</license>
+    <keywords>cordova,cli,test</keywords>
+</plugin>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/helpers.js
----------------------------------------------------------------------
diff --git a/spec/helpers.js b/spec/helpers.js
new file mode 100644
index 0000000..3236516
--- /dev/null
+++ b/spec/helpers.js
@@ -0,0 +1,46 @@
+
+var path = require('path'),
+    fs = require('fs'),
+    shell = require('shelljs'),
+    os = require('os');
+
+module.exports.tmpDir = function(subdir) {
+    var dir = path.join(os.tmpdir(), 'e2e-test');
+    if (subdir) {
+        dir = path.join(dir, subdir);
+    }
+    shell.mkdir('-p', dir);
+    return dir;
+};
+
+// Returns the platform that should be used for testing on this host platform.
+/*
+var host = os.platform();
+if (host.match(/win/)) {
+    module.exports.testPlatform = 'wp8';
+} else if (host.match(/darwin/)) {
+    module.exports.testPlatform = 'ios';
+} else {
+    module.exports.testPlatform = 'android';
+}
+*/
+
+// Just use Android everywhere; we're mocking out any calls to the `android` binary.
+module.exports.testPlatform = 'android';
+
+// Add the toExist matcher.
+beforeEach(function() {
+    this.addMatchers({
+        'toExist': function() {
+            var notText = this.isNot ? ' not' : '';
+            var self = this;
+
+            this.message = function() {
+                return 'Expected file ' + self.actual + notText + ' to exist.';
+            };
+
+            return fs.existsSync(this.actual);
+        }
+    });
+});
+

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/hooker.spec.js
----------------------------------------------------------------------
diff --git a/spec/hooker.spec.js b/spec/hooker.spec.js
new file mode 100644
index 0000000..c85cc59
--- /dev/null
+++ b/spec/hooker.spec.js
@@ -0,0 +1,261 @@
+ /**
+    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 cordova = require('../cordova'),
+    hooker = require('../src/hooker'),
+    shell  = require('shelljs'),
+    path   = require('path'),
+    fs     = require('fs'),
+    os     = require('os'),
+    Q      = require('q'),
+    child_process = require('child_process'),
+    helpers = require('./helpers');
+
+var platform = os.platform();
+var tmpDir = helpers.tmpDir('hooks_test');
+var project = path.join(tmpDir, 'project');
+var dotCordova = path.join(project, '.cordova');
+var hooksDir = path.join(project, '.cordova', 'hooks');
+var ext = platform.match(/(win32|win64)/)?'bat':'sh';
+
+
+// copy fixture
+shell.rm('-rf', project);
+shell.mkdir('-p', project);
+shell.cp('-R', path.join(__dirname, 'fixtures', 'base', '*'), project);
+shell.mkdir('-p', dotCordova);
+shell.cp('-R', path.join(__dirname, 'fixtures', 'hooks_' + ext), dotCordova);
+shell.mv(path.join(dotCordova, 'hooks_' + ext), hooksDir);
+shell.chmod('-R', 'ug+x', hooksDir);
+
+
+describe('hooker', function() {
+    it('should throw if provided directory is not a cordova project', function() {
+        expect(function() {
+            new hooker(tmpDir);
+        }).toThrow();
+    });
+});
+
+describe('global (static) fire method', function() {
+    it('should execute listeners serially', function(done) {
+        var test_event = 'foo';
+        var h1_fired = false;
+        var h1 = function() {
+            expect(h2_fired).toBe(false);
+            // Delay 100 ms here to check that h2 is not executed until after
+            // the promise returned by h1 is resolved.
+            var q = Q.delay(100).then(function() {
+                h1_fired = true;
+            });
+            return q;
+        };
+        var h2_fired = false;
+        var h2 = function() {
+            h2_fired = true;
+            expect(h1_fired).toBe(true);
+            return Q();
+        };
+
+        cordova.on(test_event, h1);
+        cordova.on(test_event, h2);
+        hooker.fire(test_event).then(function() {
+            expect(h1_fired).toBe(true);
+            expect(h2_fired).toBe(true);
+            done();
+        });
+    });
+});
+
+describe('module-level hooks', function() {
+    var handler = jasmine.createSpy().andReturn(Q());
+    var test_event = 'before_build';
+    var h;
+
+    beforeEach(function() {
+        h = new hooker(project);
+    });
+
+    afterEach(function() {
+        cordova.removeAllListeners(test_event);
+        handler.reset();
+    });
+
+    it('should fire handlers using cordova.on', function(done) {
+        cordova.on(test_event, handler);
+        h.fire(test_event)
+        .then(function() {
+            expect(handler).toHaveBeenCalled();
+        })
+        .fail(function(err) {
+            expect(err).not.toBeDefined();
+        })
+        .fin(done);
+    });
+
+    it('should pass the project root folder as parameter into the module-level handlers', function(done) {
+        cordova.on(test_event, handler);
+        h.fire(test_event)
+        .then(function() {
+            expect(handler).toHaveBeenCalledWith({root:project});
+        })
+        .fail(function(err) {
+            console.log(err);
+            expect(err).not.toBeDefined();
+        })
+        .fin(done);
+    });
+
+    it('should be able to stop listening to events using cordova.off', function(done) {
+        cordova.on(test_event, handler);
+        cordova.off(test_event, handler);
+        h.fire(test_event)
+        .then(function() {
+            expect(handler).not.toHaveBeenCalled();
+        })
+        .fail(function(err) {
+            console.log(err);
+            expect(err).toBeUndefined();
+        })
+        .fin(done);
+    });
+
+    it('should allow for hook to opt into asynchronous execution and block further hooks from firing using the done callback', function(done) {
+        var h1_fired = false;
+        var h1 = function() {
+            h1_fired = true;
+            expect(h2_fired).toBe(false);
+            return Q();
+        };
+        var h2_fired = false;
+        var h2 = function() {
+            h2_fired = true;
+            expect(h1_fired).toBe(true);
+            return Q();
+        };
+
+        cordova.on(test_event, h1);
+        cordova.on(test_event, h2);
+        h.fire(test_event).then(function() {
+            expect(h1_fired).toBe(true);
+            expect(h2_fired).toBe(true);
+            done();
+        });
+    });
+
+    it('should pass data object that fire calls into async handlers', function(done) {
+        var data = {
+            "hi":"ho",
+            "offtowork":"wego"
+        };
+        var async = function(opts) {
+            data.root = tmpDir;
+            expect(opts).toEqual(data);
+            return Q();
+        };
+        cordova.on(test_event, async);
+        h.fire(test_event, data).then(done);
+    });
+
+    it('should pass data object that fire calls into sync handlers', function(done) {
+        var data = {
+            "hi":"ho",
+            "offtowork":"wego"
+        };
+        var async = function(opts) {
+            data.root = tmpDir;
+            expect(opts).toEqual(data);
+        };
+        cordova.on(test_event, async);
+        h.fire(test_event, data).then(done);
+    });
+});
+
+
+describe('hooks', function() {
+    var h;
+    beforeEach(function() {
+        h = new hooker(project);
+    });
+
+
+    it('should not error if the hook is unrecognized', function(done) {
+        h.fire('CLEAN YOUR SHORTS GODDAMNIT LIKE A BIG BOY!')
+        .fail(function (err) {
+            expect('Call with unrecogized hook ').toBe('successful.\n' + err);
+        })
+        .fin(done);
+    });
+
+    it('should error if any script exits with non-zero code', function(done) {
+        h.fire('fail').then(function() {
+            expect('the call').toBe('a failure');
+        }, function(err) {
+            expect(err).toBeDefined();
+        })
+        .fin(done);
+    });
+
+    it('should execute all scripts in order', function(done) {
+        h.fire('test')
+        .then(function() {
+            var hooksOrderFile = path.join(project, 'hooks_order.txt');
+            var hooksEnvFile = path.join(project, 'hooks_env.json');
+            var hooksParamsFile = path.join(project, 'hooks_params.txt');
+            expect(hooksOrderFile).toExist();
+            expect(hooksEnvFile).toExist();
+            expect(hooksParamsFile).toExist();
+            expect(path.join(project, 'dotted_hook_should_not_fire.txt')).not.toExist();
+
+            var order = fs.readFileSync(hooksOrderFile, 'ascii').replace(/\W/gm, '');
+            expect(order).toBe('ab');
+
+            var params = fs.readFileSync(hooksParamsFile, 'ascii').trim().trim('"');
+            expect(params).toMatch(project.replace(/\\/g, '\\\\'));
+
+            var env = JSON.parse(fs.readFileSync(hooksEnvFile, 'ascii'));
+            expect(env.CORDOVA_VERSION).toEqual(require('../package').version);
+        })
+        .fail(function(err) {
+            console.log(err);
+            expect('Test hook call').toBe('successful');
+        })
+        .fin(done);
+
+    });
+
+    // Cleanup. Must be the last spec. Is there a better place for final cleanup in Jasmine?
+    it('should not fail during cleanup', function() {
+        process.chdir(path.join(__dirname, '..'));  // Non e2e tests assume CWD is repo root.
+        if(ext == 'sh') {
+            //shell.rm('-rf', tmpDir);
+        } else { // Windows:
+            // For some mysterious reason, both shell.rm and RMDIR /S /Q won't
+            // delete the dir on Windows, but they do remove the files leaving
+            // only folders. But the dir is removed just fine by
+            // shell.rm('-rf', tmpDir) at the top of this file with the next
+            // invocation of this test. The benefit of RMDIR /S /Q is that it
+            // doesn't print warnings like shell.rmdir() that look like this:
+            // rm: could not remove directory (code ENOTEMPTY): C:\Users\...
+            var cmd =  'RMDIR /S /Q ' + tmpDir;
+            child_process.exec(cmd);
+        }
+    });
+});


[5/8] CB-6421: Move tests from e2e to spec

Posted by ka...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/assets/www/cordova.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/assets/www/cordova.js b/e2e/fixtures/platforms/android/assets/www/cordova.js
deleted file mode 100644
index 07e3feb..0000000
--- a/e2e/fixtures/platforms/android/assets/www/cordova.js
+++ /dev/null
@@ -1,1712 +0,0 @@
-// Platform: android
-// 3.1.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.
-*/
-;(function() {
-var CORDOVA_JS_BUILD_LABEL = '3.1.0';
-// file: lib/scripts/require.js
-
-var require,
-    define;
-
-(function () {
-    var modules = {},
-    // Stack of moduleIds currently being built.
-        requireStack = [],
-    // Map of module ID -> index into requireStack of modules currently being built.
-        inProgressModules = {},
-        SEPERATOR = ".";
-
-
-
-    function build(module) {
-        var factory = module.factory,
-            localRequire = function (id) {
-                var resultantId = id;
-                //Its a relative path, so lop off the last portion and add the id (minus "./")
-                if (id.charAt(0) === ".") {
-                    resultantId = module.id.slice(0, module.id.lastIndexOf(SEPERATOR)) + SEPERATOR + id.slice(2);
-                }
-                return require(resultantId);
-            };
-        module.exports = {};
-        delete module.factory;
-        factory(localRequire, module.exports, module);
-        return module.exports;
-    }
-
-    require = function (id) {
-        if (!modules[id]) {
-            throw "module " + id + " not found";
-        } else if (id in inProgressModules) {
-            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
-            throw "Cycle in require graph: " + cycle;
-        }
-        if (modules[id].factory) {
-            try {
-                inProgressModules[id] = requireStack.length;
-                requireStack.push(id);
-                return build(modules[id]);
-            } finally {
-                delete inProgressModules[id];
-                requireStack.pop();
-            }
-        }
-        return modules[id].exports;
-    };
-
-    define = function (id, factory) {
-        if (modules[id]) {
-            throw "module " + id + " already defined";
-        }
-
-        modules[id] = {
-            id: id,
-            factory: factory
-        };
-    };
-
-    define.remove = function (id) {
-        delete modules[id];
-    };
-
-    define.moduleMap = modules;
-})();
-
-//Export for use in node
-if (typeof module === "object" && typeof require === "function") {
-    module.exports.require = require;
-    module.exports.define = define;
-}
-
-// file: lib/cordova.js
-define("cordova", function(require, exports, module) {
-
-
-var channel = require('cordova/channel');
-var platform = require('cordova/platform');
-
-/**
- * Intercept calls to addEventListener + removeEventListener and handle deviceready,
- * resume, and pause events.
- */
-var m_document_addEventListener = document.addEventListener;
-var m_document_removeEventListener = document.removeEventListener;
-var m_window_addEventListener = window.addEventListener;
-var m_window_removeEventListener = window.removeEventListener;
-
-/**
- * Houses custom event handlers to intercept on document + window event listeners.
- */
-var documentEventHandlers = {},
-    windowEventHandlers = {};
-
-document.addEventListener = function(evt, handler, capture) {
-    var e = evt.toLowerCase();
-    if (typeof documentEventHandlers[e] != 'undefined') {
-        documentEventHandlers[e].subscribe(handler);
-    } else {
-        m_document_addEventListener.call(document, evt, handler, capture);
-    }
-};
-
-window.addEventListener = function(evt, handler, capture) {
-    var e = evt.toLowerCase();
-    if (typeof windowEventHandlers[e] != 'undefined') {
-        windowEventHandlers[e].subscribe(handler);
-    } else {
-        m_window_addEventListener.call(window, evt, handler, capture);
-    }
-};
-
-document.removeEventListener = function(evt, handler, capture) {
-    var e = evt.toLowerCase();
-    // If unsubscribing from an event that is handled by a plugin
-    if (typeof documentEventHandlers[e] != "undefined") {
-        documentEventHandlers[e].unsubscribe(handler);
-    } else {
-        m_document_removeEventListener.call(document, evt, handler, capture);
-    }
-};
-
-window.removeEventListener = function(evt, handler, capture) {
-    var e = evt.toLowerCase();
-    // If unsubscribing from an event that is handled by a plugin
-    if (typeof windowEventHandlers[e] != "undefined") {
-        windowEventHandlers[e].unsubscribe(handler);
-    } else {
-        m_window_removeEventListener.call(window, evt, handler, capture);
-    }
-};
-
-function createEvent(type, data) {
-    var event = document.createEvent('Events');
-    event.initEvent(type, false, false);
-    if (data) {
-        for (var i in data) {
-            if (data.hasOwnProperty(i)) {
-                event[i] = data[i];
-            }
-        }
-    }
-    return event;
-}
-
-
-var cordova = {
-    define:define,
-    require:require,
-    version:CORDOVA_JS_BUILD_LABEL,
-    platformId:platform.id,
-    /**
-     * Methods to add/remove your own addEventListener hijacking on document + window.
-     */
-    addWindowEventHandler:function(event) {
-        return (windowEventHandlers[event] = channel.create(event));
-    },
-    addStickyDocumentEventHandler:function(event) {
-        return (documentEventHandlers[event] = channel.createSticky(event));
-    },
-    addDocumentEventHandler:function(event) {
-        return (documentEventHandlers[event] = channel.create(event));
-    },
-    removeWindowEventHandler:function(event) {
-        delete windowEventHandlers[event];
-    },
-    removeDocumentEventHandler:function(event) {
-        delete documentEventHandlers[event];
-    },
-    /**
-     * Retrieve original event handlers that were replaced by Cordova
-     *
-     * @return object
-     */
-    getOriginalHandlers: function() {
-        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
-        'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
-    },
-    /**
-     * Method to fire event from native code
-     * bNoDetach is required for events which cause an exception which needs to be caught in native code
-     */
-    fireDocumentEvent: function(type, data, bNoDetach) {
-        var evt = createEvent(type, data);
-        if (typeof documentEventHandlers[type] != 'undefined') {
-            if( bNoDetach ) {
-                documentEventHandlers[type].fire(evt);
-            }
-            else {
-                setTimeout(function() {
-                    // Fire deviceready on listeners that were registered before cordova.js was loaded.
-                    if (type == 'deviceready') {
-                        document.dispatchEvent(evt);
-                    }
-                    documentEventHandlers[type].fire(evt);
-                }, 0);
-            }
-        } else {
-            document.dispatchEvent(evt);
-        }
-    },
-    fireWindowEvent: function(type, data) {
-        var evt = createEvent(type,data);
-        if (typeof windowEventHandlers[type] != 'undefined') {
-            setTimeout(function() {
-                windowEventHandlers[type].fire(evt);
-            }, 0);
-        } else {
-            window.dispatchEvent(evt);
-        }
-    },
-
-    /**
-     * Plugin callback mechanism.
-     */
-    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
-    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
-    callbackId: Math.floor(Math.random() * 2000000000),
-    callbacks:  {},
-    callbackStatus: {
-        NO_RESULT: 0,
-        OK: 1,
-        CLASS_NOT_FOUND_EXCEPTION: 2,
-        ILLEGAL_ACCESS_EXCEPTION: 3,
-        INSTANTIATION_EXCEPTION: 4,
-        MALFORMED_URL_EXCEPTION: 5,
-        IO_EXCEPTION: 6,
-        INVALID_ACTION: 7,
-        JSON_EXCEPTION: 8,
-        ERROR: 9
-    },
-
-    /**
-     * Called by native code when returning successful result from an action.
-     */
-    callbackSuccess: function(callbackId, args) {
-        try {
-            cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
-        } catch (e) {
-            console.log("Error in error callback: " + callbackId + " = "+e);
-        }
-    },
-
-    /**
-     * Called by native code when returning error result from an action.
-     */
-    callbackError: function(callbackId, args) {
-        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
-        // Derive success from status.
-        try {
-            cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
-        } catch (e) {
-            console.log("Error in error callback: " + callbackId + " = "+e);
-        }
-    },
-
-    /**
-     * Called by native code when returning the result from an action.
-     */
-    callbackFromNative: function(callbackId, success, status, args, keepCallback) {
-        var callback = cordova.callbacks[callbackId];
-        if (callback) {
-            if (success && status == cordova.callbackStatus.OK) {
-                callback.success && callback.success.apply(null, args);
-            } else if (!success) {
-                callback.fail && callback.fail.apply(null, args);
-            }
-
-            // Clear callback if not expecting any more results
-            if (!keepCallback) {
-                delete cordova.callbacks[callbackId];
-            }
-        }
-    },
-    addConstructor: function(func) {
-        channel.onCordovaReady.subscribe(function() {
-            try {
-                func();
-            } catch(e) {
-                console.log("Failed to run constructor: " + e);
-            }
-        });
-    }
-};
-
-
-module.exports = cordova;
-
-});
-
-// file: lib/android/android/nativeapiprovider.js
-define("cordova/android/nativeapiprovider", function(require, exports, module) {
-
-/**
- * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.
- */
-
-var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');
-var currentApi = nativeApi;
-
-module.exports = {
-    get: function() { return currentApi; },
-    setPreferPrompt: function(value) {
-        currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;
-    },
-    // Used only by tests.
-    set: function(value) {
-        currentApi = value;
-    }
-};
-
-});
-
-// file: lib/android/android/promptbasednativeapi.js
-define("cordova/android/promptbasednativeapi", function(require, exports, module) {
-
-/**
- * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.
- * This is used only on the 2.3 simulator, where addJavascriptInterface() is broken.
- */
-
-module.exports = {
-    exec: function(service, action, callbackId, argsJson) {
-        return prompt(argsJson, 'gap:'+JSON.stringify([service, action, callbackId]));
-    },
-    setNativeToJsBridgeMode: function(value) {
-        prompt(value, 'gap_bridge_mode:');
-    },
-    retrieveJsMessages: function(fromOnlineEvent) {
-        return prompt(+fromOnlineEvent, 'gap_poll:');
-    }
-};
-
-});
-
-// file: lib/common/argscheck.js
-define("cordova/argscheck", function(require, exports, module) {
-
-var exec = require('cordova/exec');
-var utils = require('cordova/utils');
-
-var moduleExports = module.exports;
-
-var typeMap = {
-    'A': 'Array',
-    'D': 'Date',
-    'N': 'Number',
-    'S': 'String',
-    'F': 'Function',
-    'O': 'Object'
-};
-
-function extractParamName(callee, argIndex) {
-    return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
-}
-
-function checkArgs(spec, functionName, args, opt_callee) {
-    if (!moduleExports.enableChecks) {
-        return;
-    }
-    var errMsg = null;
-    var typeName;
-    for (var i = 0; i < spec.length; ++i) {
-        var c = spec.charAt(i),
-            cUpper = c.toUpperCase(),
-            arg = args[i];
-        // Asterix means allow anything.
-        if (c == '*') {
-            continue;
-        }
-        typeName = utils.typeName(arg);
-        if ((arg === null || arg === undefined) && c == cUpper) {
-            continue;
-        }
-        if (typeName != typeMap[cUpper]) {
-            errMsg = 'Expected ' + typeMap[cUpper];
-            break;
-        }
-    }
-    if (errMsg) {
-        errMsg += ', but got ' + typeName + '.';
-        errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
-        // Don't log when running unit tests.
-        if (typeof jasmine == 'undefined') {
-            console.error(errMsg);
-        }
-        throw TypeError(errMsg);
-    }
-}
-
-function getValue(value, defaultValue) {
-    return value === undefined ? defaultValue : value;
-}
-
-moduleExports.checkArgs = checkArgs;
-moduleExports.getValue = getValue;
-moduleExports.enableChecks = true;
-
-
-});
-
-// file: lib/common/base64.js
-define("cordova/base64", function(require, exports, module) {
-
-var base64 = exports;
-
-base64.fromArrayBuffer = function(arrayBuffer) {
-    var array = new Uint8Array(arrayBuffer);
-    return uint8ToBase64(array);
-};
-
-//------------------------------------------------------------------------------
-
-/* This code is based on the performance tests at http://jsperf.com/b64tests
- * This 12-bit-at-a-time algorithm was the best performing version on all
- * platforms tested.
- */
-
-var b64_6bit = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-var b64_12bit;
-
-var b64_12bitTable = function() {
-    b64_12bit = [];
-    for (var i=0; i<64; i++) {
-        for (var j=0; j<64; j++) {
-            b64_12bit[i*64+j] = b64_6bit[i] + b64_6bit[j];
-        }
-    }
-    b64_12bitTable = function() { return b64_12bit; };
-    return b64_12bit;
-};
-
-function uint8ToBase64(rawData) {
-    var numBytes = rawData.byteLength;
-    var output="";
-    var segment;
-    var table = b64_12bitTable();
-    for (var i=0;i<numBytes-2;i+=3) {
-        segment = (rawData[i] << 16) + (rawData[i+1] << 8) + rawData[i+2];
-        output += table[segment >> 12];
-        output += table[segment & 0xfff];
-    }
-    if (numBytes - i == 2) {
-        segment = (rawData[i] << 16) + (rawData[i+1] << 8);
-        output += table[segment >> 12];
-        output += b64_6bit[(segment & 0xfff) >> 6];
-        output += '=';
-    } else if (numBytes - i == 1) {
-        segment = (rawData[i] << 16);
-        output += table[segment >> 12];
-        output += '==';
-    }
-    return output;
-}
-
-});
-
-// file: lib/common/builder.js
-define("cordova/builder", function(require, exports, module) {
-
-var utils = require('cordova/utils');
-
-function each(objects, func, context) {
-    for (var prop in objects) {
-        if (objects.hasOwnProperty(prop)) {
-            func.apply(context, [objects[prop], prop]);
-        }
-    }
-}
-
-function clobber(obj, key, value) {
-    exports.replaceHookForTesting(obj, key);
-    obj[key] = value;
-    // Getters can only be overridden by getters.
-    if (obj[key] !== value) {
-        utils.defineGetter(obj, key, function() {
-            return value;
-        });
-    }
-}
-
-function assignOrWrapInDeprecateGetter(obj, key, value, message) {
-    if (message) {
-        utils.defineGetter(obj, key, function() {
-            console.log(message);
-            delete obj[key];
-            clobber(obj, key, value);
-            return value;
-        });
-    } else {
-        clobber(obj, key, value);
-    }
-}
-
-function include(parent, objects, clobber, merge) {
-    each(objects, function (obj, key) {
-        try {
-            var result = obj.path ? require(obj.path) : {};
-
-            if (clobber) {
-                // Clobber if it doesn't exist.
-                if (typeof parent[key] === 'undefined') {
-                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
-                } else if (typeof obj.path !== 'undefined') {
-                    // If merging, merge properties onto parent, otherwise, clobber.
-                    if (merge) {
-                        recursiveMerge(parent[key], result);
-                    } else {
-                        assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
-                    }
-                }
-                result = parent[key];
-            } else {
-                // Overwrite if not currently defined.
-                if (typeof parent[key] == 'undefined') {
-                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
-                } else {
-                    // Set result to what already exists, so we can build children into it if they exist.
-                    result = parent[key];
-                }
-            }
-
-            if (obj.children) {
-                include(result, obj.children, clobber, merge);
-            }
-        } catch(e) {
-            utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
-        }
-    });
-}
-
-/**
- * Merge properties from one object onto another recursively.  Properties from
- * the src object will overwrite existing target property.
- *
- * @param target Object to merge properties into.
- * @param src Object to merge properties from.
- */
-function recursiveMerge(target, src) {
-    for (var prop in src) {
-        if (src.hasOwnProperty(prop)) {
-            if (target.prototype && target.prototype.constructor === target) {
-                // If the target object is a constructor override off prototype.
-                clobber(target.prototype, prop, src[prop]);
-            } else {
-                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
-                    recursiveMerge(target[prop], src[prop]);
-                } else {
-                    clobber(target, prop, src[prop]);
-                }
-            }
-        }
-    }
-}
-
-exports.buildIntoButDoNotClobber = function(objects, target) {
-    include(target, objects, false, false);
-};
-exports.buildIntoAndClobber = function(objects, target) {
-    include(target, objects, true, false);
-};
-exports.buildIntoAndMerge = function(objects, target) {
-    include(target, objects, true, true);
-};
-exports.recursiveMerge = recursiveMerge;
-exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
-exports.replaceHookForTesting = function() {};
-
-});
-
-// file: lib/common/channel.js
-define("cordova/channel", function(require, exports, module) {
-
-var utils = require('cordova/utils'),
-    nextGuid = 1;
-
-/**
- * Custom pub-sub "channel" that can have functions subscribed to it
- * This object is used to define and control firing of events for
- * cordova initialization, as well as for custom events thereafter.
- *
- * The order of events during page load and Cordova startup is as follows:
- *
- * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
- * onNativeReady*              Internal event that indicates the Cordova native side is ready.
- * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
- * onDeviceReady*              User event fired to indicate that Cordova is ready
- * onResume                    User event fired to indicate a start/resume lifecycle event
- * onPause                     User event fired to indicate a pause lifecycle event
- * onDestroy*                  Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
- *
- * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
- * All listeners that subscribe after the event is fired will be executed right away.
- *
- * The only Cordova events that user code should register for are:
- *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
- *      pause                 App has moved to background
- *      resume                App has returned to foreground
- *
- * Listeners can be registered as:
- *      document.addEventListener("deviceready", myDeviceReadyListener, false);
- *      document.addEventListener("resume", myResumeListener, false);
- *      document.addEventListener("pause", myPauseListener, false);
- *
- * The DOM lifecycle events should be used for saving and restoring state
- *      window.onload
- *      window.onunload
- *
- */
-
-/**
- * Channel
- * @constructor
- * @param type  String the channel name
- */
-var Channel = function(type, sticky) {
-    this.type = type;
-    // Map of guid -> function.
-    this.handlers = {};
-    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
-    this.state = sticky ? 1 : 0;
-    // Used in sticky mode to remember args passed to fire().
-    this.fireArgs = null;
-    // Used by onHasSubscribersChange to know if there are any listeners.
-    this.numHandlers = 0;
-    // Function that is called when the first listener is subscribed, or when
-    // the last listener is unsubscribed.
-    this.onHasSubscribersChange = null;
-},
-    channel = {
-        /**
-         * Calls the provided function only after all of the channels specified
-         * have been fired. All channels must be sticky channels.
-         */
-        join: function(h, c) {
-            var len = c.length,
-                i = len,
-                f = function() {
-                    if (!(--i)) h();
-                };
-            for (var j=0; j<len; j++) {
-                if (c[j].state === 0) {
-                    throw Error('Can only use join with sticky channels.');
-                }
-                c[j].subscribe(f);
-            }
-            if (!len) h();
-        },
-        create: function(type) {
-            return channel[type] = new Channel(type, false);
-        },
-        createSticky: function(type) {
-            return channel[type] = new Channel(type, true);
-        },
-
-        /**
-         * cordova Channels that must fire before "deviceready" is fired.
-         */
-        deviceReadyChannelsArray: [],
-        deviceReadyChannelsMap: {},
-
-        /**
-         * Indicate that a feature needs to be initialized before it is ready to be used.
-         * This holds up Cordova's "deviceready" event until the feature has been initialized
-         * and Cordova.initComplete(feature) is called.
-         *
-         * @param feature {String}     The unique feature name
-         */
-        waitForInitialization: function(feature) {
-            if (feature) {
-                var c = channel[feature] || this.createSticky(feature);
-                this.deviceReadyChannelsMap[feature] = c;
-                this.deviceReadyChannelsArray.push(c);
-            }
-        },
-
-        /**
-         * Indicate that initialization code has completed and the feature is ready to be used.
-         *
-         * @param feature {String}     The unique feature name
-         */
-        initializationComplete: function(feature) {
-            var c = this.deviceReadyChannelsMap[feature];
-            if (c) {
-                c.fire();
-            }
-        }
-    };
-
-function forceFunction(f) {
-    if (typeof f != 'function') throw "Function required as first argument!";
-}
-
-/**
- * Subscribes the given function to the channel. Any time that
- * Channel.fire is called so too will the function.
- * Optionally specify an execution context for the function
- * and a guid that can be used to stop subscribing to the channel.
- * Returns the guid.
- */
-Channel.prototype.subscribe = function(f, c) {
-    // need a function to call
-    forceFunction(f);
-    if (this.state == 2) {
-        f.apply(c || this, this.fireArgs);
-        return;
-    }
-
-    var func = f,
-        guid = f.observer_guid;
-    if (typeof c == "object") { func = utils.close(c, f); }
-
-    if (!guid) {
-        // first time any channel has seen this subscriber
-        guid = '' + nextGuid++;
-    }
-    func.observer_guid = guid;
-    f.observer_guid = guid;
-
-    // Don't add the same handler more than once.
-    if (!this.handlers[guid]) {
-        this.handlers[guid] = func;
-        this.numHandlers++;
-        if (this.numHandlers == 1) {
-            this.onHasSubscribersChange && this.onHasSubscribersChange();
-        }
-    }
-};
-
-/**
- * Unsubscribes the function with the given guid from the channel.
- */
-Channel.prototype.unsubscribe = function(f) {
-    // need a function to unsubscribe
-    forceFunction(f);
-
-    var guid = f.observer_guid,
-        handler = this.handlers[guid];
-    if (handler) {
-        delete this.handlers[guid];
-        this.numHandlers--;
-        if (this.numHandlers === 0) {
-            this.onHasSubscribersChange && this.onHasSubscribersChange();
-        }
-    }
-};
-
-/**
- * Calls all functions subscribed to this channel.
- */
-Channel.prototype.fire = function(e) {
-    var fail = false,
-        fireArgs = Array.prototype.slice.call(arguments);
-    // Apply stickiness.
-    if (this.state == 1) {
-        this.state = 2;
-        this.fireArgs = fireArgs;
-    }
-    if (this.numHandlers) {
-        // Copy the values first so that it is safe to modify it from within
-        // callbacks.
-        var toCall = [];
-        for (var item in this.handlers) {
-            toCall.push(this.handlers[item]);
-        }
-        for (var i = 0; i < toCall.length; ++i) {
-            toCall[i].apply(this, fireArgs);
-        }
-        if (this.state == 2 && this.numHandlers) {
-            this.numHandlers = 0;
-            this.handlers = {};
-            this.onHasSubscribersChange && this.onHasSubscribersChange();
-        }
-    }
-};
-
-
-// defining them here so they are ready super fast!
-// DOM event that is received when the web page is loaded and parsed.
-channel.createSticky('onDOMContentLoaded');
-
-// Event to indicate the Cordova native side is ready.
-channel.createSticky('onNativeReady');
-
-// Event to indicate that all Cordova JavaScript objects have been created
-// and it's time to run plugin constructors.
-channel.createSticky('onCordovaReady');
-
-// Event to indicate that all automatically loaded JS plugins are loaded and ready.
-channel.createSticky('onPluginsReady');
-
-// Event to indicate that Cordova is ready
-channel.createSticky('onDeviceReady');
-
-// Event to indicate a resume lifecycle event
-channel.create('onResume');
-
-// Event to indicate a pause lifecycle event
-channel.create('onPause');
-
-// Event to indicate a destroy lifecycle event
-channel.createSticky('onDestroy');
-
-// Channels that must fire before "deviceready" is fired.
-channel.waitForInitialization('onCordovaReady');
-channel.waitForInitialization('onDOMContentLoaded');
-
-module.exports = channel;
-
-});
-
-// file: lib/android/exec.js
-define("cordova/exec", function(require, exports, module) {
-
-/**
- * Execute a cordova command.  It is up to the native side whether this action
- * is synchronous or asynchronous.  The native side can return:
- *      Synchronous: PluginResult object as a JSON string
- *      Asynchronous: Empty string ""
- * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
- * depending upon the result of the action.
- *
- * @param {Function} success    The success callback
- * @param {Function} fail       The fail callback
- * @param {String} service      The name of the service to use
- * @param {String} action       Action to be run in cordova
- * @param {String[]} [args]     Zero or more arguments to pass to the method
- */
-var cordova = require('cordova'),
-    nativeApiProvider = require('cordova/android/nativeapiprovider'),
-    utils = require('cordova/utils'),
-    base64 = require('cordova/base64'),
-    jsToNativeModes = {
-        PROMPT: 0,
-        JS_OBJECT: 1,
-        // This mode is currently for benchmarking purposes only. It must be enabled
-        // on the native side through the ENABLE_LOCATION_CHANGE_EXEC_MODE
-        // constant within CordovaWebViewClient.java before it will work.
-        LOCATION_CHANGE: 2
-    },
-    nativeToJsModes = {
-        // Polls for messages using the JS->Native bridge.
-        POLLING: 0,
-        // For LOAD_URL to be viable, it would need to have a work-around for
-        // the bug where the soft-keyboard gets dismissed when a message is sent.
-        LOAD_URL: 1,
-        // For the ONLINE_EVENT to be viable, it would need to intercept all event
-        // listeners (both through addEventListener and window.ononline) as well
-        // as set the navigator property itself.
-        ONLINE_EVENT: 2,
-        // Uses reflection to access private APIs of the WebView that can send JS
-        // to be executed.
-        // Requires Android 3.2.4 or above.
-        PRIVATE_API: 3
-    },
-    jsToNativeBridgeMode,  // Set lazily.
-    nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT,
-    pollEnabled = false,
-    messagesFromNative = [];
-
-function androidExec(success, fail, service, action, args) {
-    // Set default bridge modes if they have not already been set.
-    // By default, we use the failsafe, since addJavascriptInterface breaks too often
-    if (jsToNativeBridgeMode === undefined) {
-        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
-    }
-
-    // Process any ArrayBuffers in the args into a string.
-    for (var i = 0; i < args.length; i++) {
-        if (utils.typeName(args[i]) == 'ArrayBuffer') {
-            args[i] = base64.fromArrayBuffer(args[i]);
-        }
-    }
-
-    var callbackId = service + cordova.callbackId++,
-        argsJson = JSON.stringify(args);
-
-    if (success || fail) {
-        cordova.callbacks[callbackId] = {success:success, fail:fail};
-    }
-
-    if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) {
-        window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson;
-    } else {
-        var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson);
-        // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
-        // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.
-        if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && messages === "@Null arguments.") {
-            androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
-            androidExec(success, fail, service, action, args);
-            androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
-            return;
-        } else {
-            androidExec.processMessages(messages);
-        }
-    }
-}
-
-function pollOnceFromOnlineEvent() {
-    pollOnce(true);
-}
-
-function pollOnce(opt_fromOnlineEvent) {
-    var msg = nativeApiProvider.get().retrieveJsMessages(!!opt_fromOnlineEvent);
-    androidExec.processMessages(msg);
-}
-
-function pollingTimerFunc() {
-    if (pollEnabled) {
-        pollOnce();
-        setTimeout(pollingTimerFunc, 50);
-    }
-}
-
-function hookOnlineApis() {
-    function proxyEvent(e) {
-        cordova.fireWindowEvent(e.type);
-    }
-    // The network module takes care of firing online and offline events.
-    // It currently fires them only on document though, so we bridge them
-    // to window here (while first listening for exec()-releated online/offline
-    // events).
-    window.addEventListener('online', pollOnceFromOnlineEvent, false);
-    window.addEventListener('offline', pollOnceFromOnlineEvent, false);
-    cordova.addWindowEventHandler('online');
-    cordova.addWindowEventHandler('offline');
-    document.addEventListener('online', proxyEvent, false);
-    document.addEventListener('offline', proxyEvent, false);
-}
-
-hookOnlineApis();
-
-androidExec.jsToNativeModes = jsToNativeModes;
-androidExec.nativeToJsModes = nativeToJsModes;
-
-androidExec.setJsToNativeBridgeMode = function(mode) {
-    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
-        console.log('Falling back on PROMPT mode since _cordovaNative is missing. Expected for Android 3.2 and lower only.');
-        mode = jsToNativeModes.PROMPT;
-    }
-    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
-    jsToNativeBridgeMode = mode;
-};
-
-androidExec.setNativeToJsBridgeMode = function(mode) {
-    if (mode == nativeToJsBridgeMode) {
-        return;
-    }
-    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
-        pollEnabled = false;
-    }
-
-    nativeToJsBridgeMode = mode;
-    // Tell the native side to switch modes.
-    nativeApiProvider.get().setNativeToJsBridgeMode(mode);
-
-    if (mode == nativeToJsModes.POLLING) {
-        pollEnabled = true;
-        setTimeout(pollingTimerFunc, 1);
-    }
-};
-
-// Processes a single message, as encoded by NativeToJsMessageQueue.java.
-function processMessage(message) {
-    try {
-        var firstChar = message.charAt(0);
-        if (firstChar == 'J') {
-            eval(message.slice(1));
-        } else if (firstChar == 'S' || firstChar == 'F') {
-            var success = firstChar == 'S';
-            var keepCallback = message.charAt(1) == '1';
-            var spaceIdx = message.indexOf(' ', 2);
-            var status = +message.slice(2, spaceIdx);
-            var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
-            var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
-            var payloadKind = message.charAt(nextSpaceIdx + 1);
-            var payload;
-            if (payloadKind == 's') {
-                payload = message.slice(nextSpaceIdx + 2);
-            } else if (payloadKind == 't') {
-                payload = true;
-            } else if (payloadKind == 'f') {
-                payload = false;
-            } else if (payloadKind == 'N') {
-                payload = null;
-            } else if (payloadKind == 'n') {
-                payload = +message.slice(nextSpaceIdx + 2);
-            } else if (payloadKind == 'A') {
-                var data = message.slice(nextSpaceIdx + 2);
-                var bytes = window.atob(data);
-                var arraybuffer = new Uint8Array(bytes.length);
-                for (var i = 0; i < bytes.length; i++) {
-                    arraybuffer[i] = bytes.charCodeAt(i);
-                }
-                payload = arraybuffer.buffer;
-            } else if (payloadKind == 'S') {
-                payload = window.atob(message.slice(nextSpaceIdx + 2));
-            } else {
-                payload = JSON.parse(message.slice(nextSpaceIdx + 1));
-            }
-            cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
-        } else {
-            console.log("processMessage failed: invalid message:" + message);
-        }
-    } catch (e) {
-        console.log("processMessage failed: Message: " + message);
-        console.log("processMessage failed: Error: " + e);
-        console.log("processMessage failed: Stack: " + e.stack);
-    }
-}
-
-// This is called from the NativeToJsMessageQueue.java.
-androidExec.processMessages = function(messages) {
-    if (messages) {
-        messagesFromNative.push(messages);
-        // Check for the reentrant case, and enqueue the message if that's the case.
-        if (messagesFromNative.length > 1) {
-            return;
-        }
-        while (messagesFromNative.length) {
-            // Don't unshift until the end so that reentrancy can be detected.
-            messages = messagesFromNative[0];
-            // The Java side can send a * message to indicate that it
-            // still has messages waiting to be retrieved.
-            if (messages == '*') {
-                messagesFromNative.shift();
-                window.setTimeout(pollOnce, 0);
-                return;
-            }
-
-            var spaceIdx = messages.indexOf(' ');
-            var msgLen = +messages.slice(0, spaceIdx);
-            var message = messages.substr(spaceIdx + 1, msgLen);
-            messages = messages.slice(spaceIdx + msgLen + 1);
-            processMessage(message);
-            if (messages) {
-                messagesFromNative[0] = messages;
-            } else {
-                messagesFromNative.shift();
-            }
-        }
-    }
-};
-
-module.exports = androidExec;
-
-});
-
-// file: lib/common/init.js
-define("cordova/init", function(require, exports, module) {
-
-var channel = require('cordova/channel');
-var cordova = require('cordova');
-var modulemapper = require('cordova/modulemapper');
-var platform = require('cordova/platform');
-var pluginloader = require('cordova/pluginloader');
-
-var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];
-
-function logUnfiredChannels(arr) {
-    for (var i = 0; i < arr.length; ++i) {
-        if (arr[i].state != 2) {
-            console.log('Channel not fired: ' + arr[i].type);
-        }
-    }
-}
-
-window.setTimeout(function() {
-    if (channel.onDeviceReady.state != 2) {
-        console.log('deviceready has not fired after 5 seconds.');
-        logUnfiredChannels(platformInitChannelsArray);
-        logUnfiredChannels(channel.deviceReadyChannelsArray);
-    }
-}, 5000);
-
-// Replace navigator before any modules are required(), to ensure it happens as soon as possible.
-// We replace it so that properties that can't be clobbered can instead be overridden.
-function replaceNavigator(origNavigator) {
-    var CordovaNavigator = function() {};
-    CordovaNavigator.prototype = origNavigator;
-    var newNavigator = new CordovaNavigator();
-    // This work-around really only applies to new APIs that are newer than Function.bind.
-    // Without it, APIs such as getGamepads() break.
-    if (CordovaNavigator.bind) {
-        for (var key in origNavigator) {
-            if (typeof origNavigator[key] == 'function') {
-                newNavigator[key] = origNavigator[key].bind(origNavigator);
-            }
-        }
-    }
-    return newNavigator;
-}
-if (window.navigator) {
-    window.navigator = replaceNavigator(window.navigator);
-}
-
-if (!window.console) {
-    window.console = {
-        log: function(){}
-    };
-}
-if (!window.console.warn) {
-    window.console.warn = function(msg) {
-        this.log("warn: " + msg);
-    };
-}
-
-// Register pause, resume and deviceready channels as events on document.
-channel.onPause = cordova.addDocumentEventHandler('pause');
-channel.onResume = cordova.addDocumentEventHandler('resume');
-channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
-
-// Listen for DOMContentLoaded and notify our channel subscribers.
-if (document.readyState == 'complete' || document.readyState == 'interactive') {
-    channel.onDOMContentLoaded.fire();
-} else {
-    document.addEventListener('DOMContentLoaded', function() {
-        channel.onDOMContentLoaded.fire();
-    }, false);
-}
-
-// _nativeReady is global variable that the native side can set
-// to signify that the native code is ready. It is a global since
-// it may be called before any cordova JS is ready.
-if (window._nativeReady) {
-    channel.onNativeReady.fire();
-}
-
-modulemapper.clobbers('cordova', 'cordova');
-modulemapper.clobbers('cordova/exec', 'cordova.exec');
-modulemapper.clobbers('cordova/exec', 'Cordova.exec');
-
-// Call the platform-specific initialization.
-platform.bootstrap && platform.bootstrap();
-
-pluginloader.load(function() {
-    channel.onPluginsReady.fire();
-});
-
-/**
- * Create all cordova objects once native side is ready.
- */
-channel.join(function() {
-    modulemapper.mapModules(window);
-
-    platform.initialize && platform.initialize();
-
-    // Fire event to notify that all objects are created
-    channel.onCordovaReady.fire();
-
-    // Fire onDeviceReady event once page has fully loaded, all
-    // constructors have run and cordova info has been received from native
-    // side.
-    channel.join(function() {
-        require('cordova').fireDocumentEvent('deviceready');
-    }, channel.deviceReadyChannelsArray);
-
-}, platformInitChannelsArray);
-
-
-});
-
-// file: lib/common/modulemapper.js
-define("cordova/modulemapper", function(require, exports, module) {
-
-var builder = require('cordova/builder'),
-    moduleMap = define.moduleMap,
-    symbolList,
-    deprecationMap;
-
-exports.reset = function() {
-    symbolList = [];
-    deprecationMap = {};
-};
-
-function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
-    if (!(moduleName in moduleMap)) {
-        throw new Error('Module ' + moduleName + ' does not exist.');
-    }
-    symbolList.push(strategy, moduleName, symbolPath);
-    if (opt_deprecationMessage) {
-        deprecationMap[symbolPath] = opt_deprecationMessage;
-    }
-}
-
-// Note: Android 2.3 does have Function.bind().
-exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
-    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
-};
-
-exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
-    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
-};
-
-exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
-    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
-};
-
-exports.runs = function(moduleName) {
-    addEntry('r', moduleName, null);
-};
-
-function prepareNamespace(symbolPath, context) {
-    if (!symbolPath) {
-        return context;
-    }
-    var parts = symbolPath.split('.');
-    var cur = context;
-    for (var i = 0, part; part = parts[i]; ++i) {
-        cur = cur[part] = cur[part] || {};
-    }
-    return cur;
-}
-
-exports.mapModules = function(context) {
-    var origSymbols = {};
-    context.CDV_origSymbols = origSymbols;
-    for (var i = 0, len = symbolList.length; i < len; i += 3) {
-        var strategy = symbolList[i];
-        var moduleName = symbolList[i + 1];
-        var module = require(moduleName);
-        // <runs/>
-        if (strategy == 'r') {
-            continue;
-        }
-        var symbolPath = symbolList[i + 2];
-        var lastDot = symbolPath.lastIndexOf('.');
-        var namespace = symbolPath.substr(0, lastDot);
-        var lastName = symbolPath.substr(lastDot + 1);
-
-        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
-        var parentObj = prepareNamespace(namespace, context);
-        var target = parentObj[lastName];
-
-        if (strategy == 'm' && target) {
-            builder.recursiveMerge(target, module);
-        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
-            if (!(symbolPath in origSymbols)) {
-                origSymbols[symbolPath] = target;
-            }
-            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
-        }
-    }
-};
-
-exports.getOriginalSymbol = function(context, symbolPath) {
-    var origSymbols = context.CDV_origSymbols;
-    if (origSymbols && (symbolPath in origSymbols)) {
-        return origSymbols[symbolPath];
-    }
-    var parts = symbolPath.split('.');
-    var obj = context;
-    for (var i = 0; i < parts.length; ++i) {
-        obj = obj && obj[parts[i]];
-    }
-    return obj;
-};
-
-exports.reset();
-
-
-});
-
-// file: lib/android/platform.js
-define("cordova/platform", function(require, exports, module) {
-
-module.exports = {
-    id: 'android',
-    bootstrap: function() {
-        var channel = require('cordova/channel'),
-            cordova = require('cordova'),
-            exec = require('cordova/exec'),
-            modulemapper = require('cordova/modulemapper');
-
-        // Tell the native code that a page change has occurred.
-        exec(null, null, 'PluginManager', 'startup', []);
-        // Tell the JS that the native side is ready.
-        channel.onNativeReady.fire();
-
-        // TODO: Extract this as a proper plugin.
-        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
-
-        // Inject a listener for the backbutton on the document.
-        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
-        backButtonChannel.onHasSubscribersChange = function() {
-            // If we just attached the first handler or detached the last handler,
-            // let native know we need to override the back button.
-            exec(null, null, "App", "overrideBackbutton", [this.numHandlers == 1]);
-        };
-
-        // Add hardware MENU and SEARCH button handlers
-        cordova.addDocumentEventHandler('menubutton');
-        cordova.addDocumentEventHandler('searchbutton');
-
-        // Let native code know we are all done on the JS side.
-        // Native code will then un-hide the WebView.
-        channel.onCordovaReady.subscribe(function() {
-            exec(null, null, "App", "show", []);
-        });
-    }
-};
-
-});
-
-// file: lib/android/plugin/android/app.js
-define("cordova/plugin/android/app", function(require, exports, module) {
-
-var exec = require('cordova/exec');
-
-module.exports = {
-    /**
-    * Clear the resource cache.
-    */
-    clearCache:function() {
-        exec(null, null, "App", "clearCache", []);
-    },
-
-    /**
-    * Load the url into the webview or into new browser instance.
-    *
-    * @param url           The URL to load
-    * @param props         Properties that can be passed in to the activity:
-    *      wait: int                           => wait msec before loading URL
-    *      loadingDialog: "Title,Message"      => display a native loading dialog
-    *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error
-    *      clearHistory: boolean              => clear webview history (default=false)
-    *      openExternal: boolean              => open in a new browser (default=false)
-    *
-    * Example:
-    *      navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
-    */
-    loadUrl:function(url, props) {
-        exec(null, null, "App", "loadUrl", [url, props]);
-    },
-
-    /**
-    * Cancel loadUrl that is waiting to be loaded.
-    */
-    cancelLoadUrl:function() {
-        exec(null, null, "App", "cancelLoadUrl", []);
-    },
-
-    /**
-    * Clear web history in this web view.
-    * Instead of BACK button loading the previous web page, it will exit the app.
-    */
-    clearHistory:function() {
-        exec(null, null, "App", "clearHistory", []);
-    },
-
-    /**
-    * Go to previous page displayed.
-    * This is the same as pressing the backbutton on Android device.
-    */
-    backHistory:function() {
-        exec(null, null, "App", "backHistory", []);
-    },
-
-    /**
-    * Override the default behavior of the Android back button.
-    * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
-    *
-    * Note: The user should not have to call this method.  Instead, when the user
-    *       registers for the "backbutton" event, this is automatically done.
-    *
-    * @param override        T=override, F=cancel override
-    */
-    overrideBackbutton:function(override) {
-        exec(null, null, "App", "overrideBackbutton", [override]);
-    },
-
-    /**
-    * Exit and terminate the application.
-    */
-    exitApp:function() {
-        return exec(null, null, "App", "exitApp", []);
-    }
-};
-
-});
-
-// file: lib/common/pluginloader.js
-define("cordova/pluginloader", function(require, exports, module) {
-
-var modulemapper = require('cordova/modulemapper');
-
-// Helper function to inject a <script> tag.
-function injectScript(url, onload, onerror) {
-    var script = document.createElement("script");
-    // onload fires even when script fails loads with an error.
-    script.onload = onload;
-    script.onerror = onerror || onload;
-    script.src = url;
-    document.head.appendChild(script);
-}
-
-function onScriptLoadingComplete(moduleList, finishPluginLoading) {
-    // Loop through all the plugins and then through their clobbers and merges.
-    for (var i = 0, module; module = moduleList[i]; i++) {
-        if (module) {
-            try {
-                if (module.clobbers && module.clobbers.length) {
-                    for (var j = 0; j < module.clobbers.length; j++) {
-                        modulemapper.clobbers(module.id, module.clobbers[j]);
-                    }
-                }
-
-                if (module.merges && module.merges.length) {
-                    for (var k = 0; k < module.merges.length; k++) {
-                        modulemapper.merges(module.id, module.merges[k]);
-                    }
-                }
-
-                // Finally, if runs is truthy we want to simply require() the module.
-                // This can be skipped if it had any merges or clobbers, though,
-                // since the mapper will already have required the module.
-                if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) {
-                    modulemapper.runs(module.id);
-                }
-            }
-            catch(err) {
-                // error with module, most likely clobbers, should we continue?
-            }
-        }
-    }
-
-    finishPluginLoading();
-}
-
-// Handler for the cordova_plugins.js content.
-// See plugman's plugin_loader.js for the details of this object.
-// This function is only called if the really is a plugins array that isn't empty.
-// Otherwise the onerror response handler will just call finishPluginLoading().
-function handlePluginsObject(path, moduleList, finishPluginLoading) {
-    // Now inject the scripts.
-    var scriptCounter = moduleList.length;
-
-    if (!scriptCounter) {
-        finishPluginLoading();
-        return;
-    }
-    function scriptLoadedCallback() {
-        if (!--scriptCounter) {
-            onScriptLoadingComplete(moduleList, finishPluginLoading);
-        }
-    }
-
-    for (var i = 0; i < moduleList.length; i++) {
-        injectScript(path + moduleList[i].file, scriptLoadedCallback);
-    }
-}
-
-function injectPluginScript(pathPrefix, finishPluginLoading) {
-    injectScript(pathPrefix + 'cordova_plugins.js', function(){
-        try {
-            var moduleList = require("cordova/plugin_list");
-            handlePluginsObject(pathPrefix, moduleList, finishPluginLoading);
-        } catch (e) {
-            // Error loading cordova_plugins.js, file not found or something
-            // this is an acceptable error, pre-3.0.0, so we just move on.
-            finishPluginLoading();
-        }
-    }, finishPluginLoading); // also, add script load error handler for file not found
-}
-
-function findCordovaPath() {
-    var path = null;
-    var scripts = document.getElementsByTagName('script');
-    var term = 'cordova.js';
-    for (var n = scripts.length-1; n>-1; n--) {
-        var src = scripts[n].src;
-        if (src.indexOf(term) == (src.length - term.length)) {
-            path = src.substring(0, src.length - term.length);
-            break;
-        }
-    }
-    return path;
-}
-
-// Tries to load all plugins' js-modules.
-// This is an async process, but onDeviceReady is blocked on onPluginsReady.
-// onPluginsReady is fired when there are no plugins to load, or they are all done.
-exports.load = function(callback) {
-    var pathPrefix = findCordovaPath();
-    if (pathPrefix === null) {
-        console.log('Could not find cordova.js script tag. Plugin loading may fail.');
-        pathPrefix = '';
-    }
-    injectPluginScript(pathPrefix, callback);
-};
-
-
-});
-
-// file: lib/common/urlutil.js
-define("cordova/urlutil", function(require, exports, module) {
-
-var urlutil = exports;
-var anchorEl = document.createElement('a');
-
-/**
- * For already absolute URLs, returns what is passed in.
- * For relative URLs, converts them to absolute ones.
- */
-urlutil.makeAbsolute = function(url) {
-  anchorEl.href = url;
-  return anchorEl.href;
-};
-
-});
-
-// file: lib/common/utils.js
-define("cordova/utils", function(require, exports, module) {
-
-var utils = exports;
-
-/**
- * Defines a property getter / setter for obj[key].
- */
-utils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) {
-    if (Object.defineProperty) {
-        var desc = {
-            get: getFunc,
-            configurable: true
-        };
-        if (opt_setFunc) {
-            desc.set = opt_setFunc;
-        }
-        Object.defineProperty(obj, key, desc);
-    } else {
-        obj.__defineGetter__(key, getFunc);
-        if (opt_setFunc) {
-            obj.__defineSetter__(key, opt_setFunc);
-        }
-    }
-};
-
-/**
- * Defines a property getter for obj[key].
- */
-utils.defineGetter = utils.defineGetterSetter;
-
-utils.arrayIndexOf = function(a, item) {
-    if (a.indexOf) {
-        return a.indexOf(item);
-    }
-    var len = a.length;
-    for (var i = 0; i < len; ++i) {
-        if (a[i] == item) {
-            return i;
-        }
-    }
-    return -1;
-};
-
-/**
- * Returns whether the item was found in the array.
- */
-utils.arrayRemove = function(a, item) {
-    var index = utils.arrayIndexOf(a, item);
-    if (index != -1) {
-        a.splice(index, 1);
-    }
-    return index != -1;
-};
-
-utils.typeName = function(val) {
-    return Object.prototype.toString.call(val).slice(8, -1);
-};
-
-/**
- * Returns an indication of whether the argument is an array or not
- */
-utils.isArray = function(a) {
-    return utils.typeName(a) == 'Array';
-};
-
-/**
- * Returns an indication of whether the argument is a Date or not
- */
-utils.isDate = function(d) {
-    return utils.typeName(d) == 'Date';
-};
-
-/**
- * Does a deep clone of the object.
- */
-utils.clone = function(obj) {
-    if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') {
-        return obj;
-    }
-
-    var retVal, i;
-
-    if(utils.isArray(obj)){
-        retVal = [];
-        for(i = 0; i < obj.length; ++i){
-            retVal.push(utils.clone(obj[i]));
-        }
-        return retVal;
-    }
-
-    retVal = {};
-    for(i in obj){
-        if(!(i in retVal) || retVal[i] != obj[i]) {
-            retVal[i] = utils.clone(obj[i]);
-        }
-    }
-    return retVal;
-};
-
-/**
- * Returns a wrapped version of the function
- */
-utils.close = function(context, func, params) {
-    if (typeof params == 'undefined') {
-        return function() {
-            return func.apply(context, arguments);
-        };
-    } else {
-        return function() {
-            return func.apply(context, params);
-        };
-    }
-};
-
-/**
- * Create a UUID
- */
-utils.createUUID = function() {
-    return UUIDcreatePart(4) + '-' +
-        UUIDcreatePart(2) + '-' +
-        UUIDcreatePart(2) + '-' +
-        UUIDcreatePart(2) + '-' +
-        UUIDcreatePart(6);
-};
-
-/**
- * Extends a child object from a parent object using classical inheritance
- * pattern.
- */
-utils.extend = (function() {
-    // proxy used to establish prototype chain
-    var F = function() {};
-    // extend Child from Parent
-    return function(Child, Parent) {
-        F.prototype = Parent.prototype;
-        Child.prototype = new F();
-        Child.__super__ = Parent.prototype;
-        Child.prototype.constructor = Child;
-    };
-}());
-
-/**
- * Alerts a message in any available way: alert or console.log.
- */
-utils.alert = function(msg) {
-    if (window.alert) {
-        window.alert(msg);
-    } else if (console && console.log) {
-        console.log(msg);
-    }
-};
-
-
-//------------------------------------------------------------------------------
-function UUIDcreatePart(length) {
-    var uuidpart = "";
-    for (var i=0; i<length; i++) {
-        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);
-        if (uuidchar.length == 1) {
-            uuidchar = "0" + uuidchar;
-        }
-        uuidpart += uuidchar;
-    }
-    return uuidpart;
-}
-
-
-});
-
-window.cordova = require('cordova');
-// file: lib/scripts/bootstrap.js
-
-require('cordova/init');
-
-})();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/assets/www/cordova_plugins.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/assets/www/cordova_plugins.js b/e2e/fixtures/platforms/android/assets/www/cordova_plugins.js
deleted file mode 100644
index b58b5dd..0000000
--- a/e2e/fixtures/platforms/android/assets/www/cordova_plugins.js
+++ /dev/null
@@ -1,3 +0,0 @@
-cordova.define('cordova/plugin_list', function(require, exports, module) {
-module.exports = []
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/assets/www/css/index.css
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/assets/www/css/index.css b/e2e/fixtures/platforms/android/assets/www/css/index.css
deleted file mode 100644
index 51daa79..0000000
--- a/e2e/fixtures/platforms/android/assets/www/css/index.css
+++ /dev/null
@@ -1,115 +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.
- */
-* {
-    -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
-}
-
-body {
-    -webkit-touch-callout: none;                /* prevent callout to copy image, etc when tap to hold */
-    -webkit-text-size-adjust: none;             /* prevent webkit from resizing text to fit */
-    -webkit-user-select: none;                  /* prevent copy paste, to allow, change 'none' to 'text' */
-    background-color:#E4E4E4;
-    background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
-    background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
-    background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
-    background-image:-webkit-gradient(
-        linear,
-        left top,
-        left bottom,
-        color-stop(0, #A7A7A7),
-        color-stop(0.51, #E4E4E4)
-    );
-    background-attachment:fixed;
-    font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
-    font-size:12px;
-    height:100%;
-    margin:0px;
-    padding:0px;
-    text-transform:uppercase;
-    width:100%;
-}
-
-/* Portrait layout (default) */
-.app {
-    background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
-    position:absolute;             /* position in the center of the screen */
-    left:50%;
-    top:50%;
-    height:50px;                   /* text area height */
-    width:225px;                   /* text area width */
-    text-align:center;
-    padding:180px 0px 0px 0px;     /* image height is 200px (bottom 20px are overlapped with text) */
-    margin:-115px 0px 0px -112px;  /* offset vertical: half of image height and text area height */
-                                   /* offset horizontal: half of text area width */
-}
-
-/* Landscape layout (with min-width) */
-@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
-    .app {
-        background-position:left center;
-        padding:75px 0px 75px 170px;  /* padding-top + padding-bottom + text area = image height */
-        margin:-90px 0px 0px -198px;  /* offset vertical: half of image height */
-                                      /* offset horizontal: half of image width and text area width */
-    }
-}
-
-h1 {
-    font-size:24px;
-    font-weight:normal;
-    margin:0px;
-    overflow:visible;
-    padding:0px;
-    text-align:center;
-}
-
-.event {
-    border-radius:4px;
-    -webkit-border-radius:4px;
-    color:#FFFFFF;
-    font-size:12px;
-    margin:0px 30px;
-    padding:2px 0px;
-}
-
-.event.listening {
-    background-color:#333333;
-    display:block;
-}
-
-.event.received {
-    background-color:#4B946A;
-    display:none;
-}
-
-@keyframes fade {
-    from { opacity: 1.0; }
-    50% { opacity: 0.4; }
-    to { opacity: 1.0; }
-}
- 
-@-webkit-keyframes fade {
-    from { opacity: 1.0; }
-    50% { opacity: 0.4; }
-    to { opacity: 1.0; }
-}
- 
-.blink {
-    animation:fade 3000ms infinite;
-    -webkit-animation:fade 3000ms infinite;
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/assets/www/img/logo.png
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/assets/www/img/logo.png b/e2e/fixtures/platforms/android/assets/www/img/logo.png
deleted file mode 100644
index 9519e7d..0000000
Binary files a/e2e/fixtures/platforms/android/assets/www/img/logo.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/assets/www/index.html
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/assets/www/index.html b/e2e/fixtures/platforms/android/assets/www/index.html
deleted file mode 100644
index bde5741..0000000
--- a/e2e/fixtures/platforms/android/assets/www/index.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!DOCTYPE html>
-<!--
-    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.
--->
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <meta name="format-detection" content="telephone=no" />
-        <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
-        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
-        <link rel="stylesheet" type="text/css" href="css/index.css" />
-        <title>Hello World</title>
-    </head>
-    <body>
-        <div class="app">
-            <h1>Apache Cordova</h1>
-            <div id="deviceready" class="blink">
-                <p class="event listening">Connecting to Device</p>
-                <p class="event received">Device is Ready</p>
-            </div>
-        </div>
-        <script type="text/javascript" src="cordova.js"></script>
-        <script type="text/javascript" src="js/index.js"></script>
-        <script type="text/javascript">
-            app.initialize();
-        </script>
-    </body>
-</html>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/assets/www/js/index.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/assets/www/js/index.js b/e2e/fixtures/platforms/android/assets/www/js/index.js
deleted file mode 100644
index 31d9064..0000000
--- a/e2e/fixtures/platforms/android/assets/www/js/index.js
+++ /dev/null
@@ -1,49 +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 app = {
-    // Application Constructor
-    initialize: function() {
-        this.bindEvents();
-    },
-    // Bind Event Listeners
-    //
-    // Bind any events that are required on startup. Common events are:
-    // 'load', 'deviceready', 'offline', and 'online'.
-    bindEvents: function() {
-        document.addEventListener('deviceready', this.onDeviceReady, false);
-    },
-    // deviceready Event Handler
-    //
-    // The scope of 'this' is the event. In order to call the 'receivedEvent'
-    // function, we must explicity call 'app.receivedEvent(...);'
-    onDeviceReady: function() {
-        app.receivedEvent('deviceready');
-    },
-    // Update DOM on a Received Event
-    receivedEvent: function(id) {
-        var parentElement = document.getElementById(id);
-        var listeningElement = parentElement.querySelector('.listening');
-        var receivedElement = parentElement.querySelector('.received');
-
-        listeningElement.setAttribute('style', 'display:none;');
-        receivedElement.setAttribute('style', 'display:block;');
-
-        console.log('Received Event: ' + id);
-    }
-};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/assets/www/spec.html
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/assets/www/spec.html b/e2e/fixtures/platforms/android/assets/www/spec.html
deleted file mode 100644
index 71f00de..0000000
--- a/e2e/fixtures/platforms/android/assets/www/spec.html
+++ /dev/null
@@ -1,68 +0,0 @@
-<!DOCTYPE html>
-<!--
-    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.
--->
-<html>
-    <head>
-        <title>Jasmine Spec Runner</title>
-
-        <!-- jasmine source -->
-        <link rel="shortcut icon" type="image/png" href="spec/lib/jasmine-1.2.0/jasmine_favicon.png">
-        <link rel="stylesheet" type="text/css" href="spec/lib/jasmine-1.2.0/jasmine.css">
-        <script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine.js"></script>
-        <script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine-html.js"></script>
-
-        <!-- include source files here... -->
-        <script type="text/javascript" src="js/index.js"></script>
-
-        <!-- include spec files here... -->
-        <script type="text/javascript" src="spec/helper.js"></script>
-        <script type="text/javascript" src="spec/index.js"></script>
-
-        <script type="text/javascript">
-            (function() {
-                var jasmineEnv = jasmine.getEnv();
-                jasmineEnv.updateInterval = 1000;
-
-                var htmlReporter = new jasmine.HtmlReporter();
-
-                jasmineEnv.addReporter(htmlReporter);
-
-                jasmineEnv.specFilter = function(spec) {
-                    return htmlReporter.specFilter(spec);
-                };
-
-                var currentWindowOnload = window.onload;
-
-                window.onload = function() {
-                    if (currentWindowOnload) {
-                        currentWindowOnload();
-                    }
-                    execJasmine();
-                };
-
-                function execJasmine() {
-                    jasmineEnv.execute();
-                }
-            })();
-        </script>
-    </head>
-    <body>
-        <div id="stage" style="display:none;"></div>
-    </body>
-</html>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/build.xml
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/build.xml b/e2e/fixtures/platforms/android/build.xml
deleted file mode 100644
index 9674edf..0000000
--- a/e2e/fixtures/platforms/android/build.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="TestBase" default="help">
-
-    <!-- The local.properties file is created and updated by the 'android' tool.
-         It contains the path to the SDK. It should *NOT* be checked into
-         Version Control Systems. -->
-    <property file="local.properties" />
-
-    <!-- The ant.properties file can be created by you. It is only edited by the
-         'android' tool to add properties to it.
-         This is the place to change some Ant specific build properties.
-         Here are some properties you may want to change/update:
-
-         source.dir
-             The name of the source directory. Default is 'src'.
-         out.dir
-             The name of the output directory. Default is 'bin'.
-
-         For other overridable properties, look at the beginning of the rules
-         files in the SDK, at tools/ant/build.xml
-
-         Properties related to the SDK location or the project target should
-         be updated using the 'android' tool with the 'update' action.
-
-         This file is an integral part of the build system for your
-         application and should be checked into Version Control Systems.
-
-         -->
-    <property file="ant.properties" />
-
-    <!-- if sdk.dir was not set from one of the property file, then
-         get it from the ANDROID_HOME env var.
-         This must be done before we load project.properties since
-         the proguard config can use sdk.dir -->
-    <property environment="env" />
-    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
-        <isset property="env.ANDROID_HOME" />
-    </condition>
-
-    <!-- The project.properties file is created and updated by the 'android'
-         tool, as well as ADT.
-
-         This contains project specific properties such as project target, and library
-         dependencies. Lower level build properties are stored in ant.properties
-         (or in .classpath for Eclipse projects).
-
-         This file is an integral part of the build system for your
-         application and should be checked into Version Control Systems. -->
-    <loadproperties srcFile="project.properties" />
-
-    <!-- quick check on sdk.dir -->
-    <fail
-            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
-            unless="sdk.dir"
-    />
-
-    <!--
-        Import per project custom build rules if present at the root of the project.
-        This is the place to put custom intermediary targets such as:
-            -pre-build
-            -pre-compile
-            -post-compile (This is typically used for code obfuscation.
-                           Compiled code location: ${out.classes.absolute.dir}
-                           If this is not done in place, override ${out.dex.input.absolute.dir})
-            -post-package
-            -post-build
-            -pre-clean
-    -->
-    <import file="custom_rules.xml" optional="true" />
-
-    <!-- Import the actual build file.
-
-         To customize existing targets, there are two options:
-         - Customize only one target:
-             - copy/paste the target into this file, *before* the
-               <import> task.
-             - customize it to your needs.
-         - Customize the whole content of build.xml
-             - copy/paste the content of the rules files (minus the top node)
-               into this file, replacing the <import> task.
-             - customize to your needs.
-
-         ***********************
-         ****** IMPORTANT ******
-         ***********************
-         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
-         in order to avoid having your file be overridden by tools such as "android update project"
-    -->
-    <!-- version-tag: 1 -->
-    <import file="${sdk.dir}/tools/ant/build.xml" />
-
-</project>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/build
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/build b/e2e/fixtures/platforms/android/cordova/build
deleted file mode 100755
index 7028eb8..0000000
--- a/e2e/fixtures/platforms/android/cordova/build
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/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 build = require('./lib/build'),
-    reqs  = require('./lib/check_reqs'),
-    args  = process.argv;
-
-// Support basic help commands
-if(args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
-                    args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {
-    build.help();
-} else if(reqs.run()) {
-    build.run(args[2]);
-    process.exit(0);
-} else {
-    process.exit(2);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/check_reqs
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/check_reqs b/e2e/fixtures/platforms/android/cordova/check_reqs
deleted file mode 100755
index 4a8abee..0000000
--- a/e2e/fixtures/platforms/android/cordova/check_reqs
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/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 check_reqs = require('./lib/check_reqs');
-
-if(!check_reqs.run()) {
-      process.exit(2);
-}
-

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/clean
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/clean b/e2e/fixtures/platforms/android/cordova/clean
deleted file mode 100755
index 70c4ca8..0000000
--- a/e2e/fixtures/platforms/android/cordova/clean
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/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 clean = require('./lib/clean'),
-    reqs  = require('./lib/check_reqs'),
-    args  = process.argv;
-
-// Usage support for when args are given
-if(args.length > 2) {
-    clean.help();
-} else if(reqs.run()) {
-    clean.run();
-    process.exit(0);
-} else {
-    process.exit(2);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/defaults.xml
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/defaults.xml b/e2e/fixtures/platforms/android/cordova/defaults.xml
deleted file mode 100644
index 24e5725..0000000
--- a/e2e/fixtures/platforms/android/cordova/defaults.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- 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.
--->
-<widget xmlns     = "http://www.w3.org/ns/widgets"
-        id        = "io.cordova.helloCordova"
-        version   = "2.0.0">
-    <name>Hello Cordova</name>
-
-    <description>
-        A sample Apache Cordova application that responds to the deviceready event.
-    </description>
-
-    <author href="http://cordova.io" email="dev@cordova.apache.org">
-        Apache Cordova Team
-    </author>
-
-    <access origin="*"/>
-
-    <!-- <content src="http://mysite.com/myapp.html" /> for external pages -->
-    <content src="index.html" />
-
-    <preference name="loglevel" value="DEBUG" />
-    <!--
-      <preference name="splashscreen" value="resourceName" />
-      <preference name="backgroundColor" value="0xFFF" />
-      <preference name="loadUrlTimeoutValue" value="20000" />
-      <preference name="InAppBrowserStorageEnabled" value="true" />
-      <preference name="disallowOverscroll" value="true" />
-    -->
-    <!-- This is required for native Android hooks -->
-    <feature name="App">
-        <param name="android-package" value="org.apache.cordova.App" />
-    </feature>
-</widget>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/appinfo.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/appinfo.js b/e2e/fixtures/platforms/android/cordova/lib/appinfo.js
deleted file mode 100755
index 1f8ebe2..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/appinfo.js
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/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 path = require('path');
-var fs = require('fs');
-var cachedAppInfo = null;
-
-function readAppInfoFromManifest() {
-    var manifestPath = path.join(__dirname, '..', '..', 'AndroidManifest.xml');
-    var manifestData = fs.readFileSync(manifestPath, {encoding:'utf8'});
-    var packageName = /\bpackage\s*=\s*"(.+?)"/.exec(manifestData);
-    if (!packageName) throw new Error('Could not find package name within ' + manifestPath);
-    var activityTag = /<activity\b[\s\S]*<\/activity>/.exec(manifestData);
-    if (!activityTag) throw new Error('Could not find <activity> within ' + manifestPath);
-    var activityName = /\bandroid:name\s*=\s*"(.+?)"/.exec(activityTag);
-    if (!activityName) throw new Error('Could not find android:name within ' + manifestPath);
-
-    return packageName[1] + '/.' + activityName[1];
-}
-
-exports.getActivityName = function() {
-    return cachedAppInfo = cachedAppInfo || readAppInfoFromManifest();
-};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/build.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/build.js b/e2e/fixtures/platforms/android/cordova/lib/build.js
deleted file mode 100755
index 7bc33ca..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/build.js
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/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 shell   = require('shelljs'),
-    clean   = require('./clean'),
-    path    = require('path'),
-    fs      = require('fs'),
-    ROOT    = path.join(__dirname, '..', '..');
-
-/*
- * Builds the project with ant.
- */
-module.exports.run = function(build_type) {
-    //default build type
-    build_type = typeof build_type !== 'undefined' ? build_type : "--debug";
-    var cmd;
-    switch(build_type) {
-        case '--debug' :
-            clean.run();
-            cmd = 'ant debug -f ' + path.join(ROOT, 'build.xml');
-            break;
-        case '--release' :
-            clean.run();
-            cmd = 'ant release -f ' + path.join(ROOT, 'build.xml');
-            break;
-        case '--nobuild' :
-            console.log('Skipping build...');
-            break;
-        default :
-           console.error('Build option \'' + build_type + '\' not recognized.');
-           process.exit(2);
-           break;
-    }
-    if(cmd) {
-        var result = shell.exec(cmd, {silent:false, async:false});
-        if(result.code > 0) {
-            console.error('ERROR: Failed to build android project.');
-            console.error(result.output);
-            process.exit(2);
-        }
-    }
-}
-
-/*
- * Gets the path to the apk file, if not such file exists then
- * the script will error out. (should we error or just return undefined?)
- */
-module.exports.get_apk = function() {
-    if(fs.existsSync(path.join(ROOT, 'bin'))) {
-        var bin_files = fs.readdirSync(path.join(ROOT, 'bin'));
-        for (file in bin_files) {
-            if(path.extname(bin_files[file]) == '.apk') {
-                return path.join(ROOT, 'bin', bin_files[file]);
-            }
-        }
-        console.error('ERROR : No .apk found in \'bin\' folder');
-        process.exit(2);
-    } else {
-        console.error('ERROR : unable to find project bin folder, could not locate .apk');
-        process.exit(2);
-    }
-}
-
-module.exports.help = function() {
-    console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'build')) + ' [build_type]');
-    console.log('Build Types : ');
-    console.log('    \'--debug\': Default build, will build project in using ant debug');
-    console.log('    \'--release\': will build project using ant release');
-    console.log('    \'--nobuild\': will skip build process (can be used with run command)');
-    process.exit(0);
-}


[7/8] git commit: CB-6421: Move tests from e2e to spec

Posted by ka...@apache.org.
CB-6421: Move tests from e2e to spec

Removing the duplicate tests first as a separate commit (for better history).


Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/fde755fe
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/fde755fe
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/fde755fe

Branch: refs/heads/master
Commit: fde755fe86b7c93b8505645567781646dc8fb572
Parents: de2500b
Author: Mark Koudritsky <ka...@gmail.com>
Authored: Tue Apr 8 17:50:44 2014 -0400
Committer: Mark Koudritsky <ka...@gmail.com>
Committed: Mon Apr 14 20:25:10 2014 -0400

----------------------------------------------------------------------
 spec/create.spec.js   | 152 --------------
 spec/platform.spec.js | 482 ---------------------------------------------
 spec/plugin.spec.js   | 288 ---------------------------
 3 files changed, 922 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/fde755fe/spec/create.spec.js
----------------------------------------------------------------------
diff --git a/spec/create.spec.js b/spec/create.spec.js
deleted file mode 100644
index a482f4d..0000000
--- a/spec/create.spec.js
+++ /dev/null
@@ -1,152 +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 cordova = require('../cordova'),
-    path    = require('path'),
-    shell   = require('shelljs'),
-    fs      = require('fs'),
-    et = require('elementtree'),
-    ConfigParser = require('../src/ConfigParser'),
-    util    = require('../src/util'),
-    config    = require('../src/config'),
-    lazy_load = require('../src/lazy_load'),
-    xmlHelpers = require('../src/xml-helpers'),
-    Q = require('q'),
-    tempDir = path.join(__dirname, '..', 'temp');
-
-var TEST_XML = '<?xml version="1.0" encoding="UTF-8"?>\n' +
-    '<widget xmlns     = "http://www.w3.org/ns/widgets"\n' +
-    '        xmlns:cdv = "http://cordova.apache.org/ns/1.0"\n' +
-    '        id        = "io.cordova.hellocordova"\n' +
-    '        version   = "0.0.1">\n' +
-    '    <name>Hello Cordova</name>\n' +
-    '    <description>\n' +
-    '        A sample Apache Cordova application that responds to the deviceready event.\n' +
-    '    </description>\n' +
-    '    <author href="http://cordova.io" email="dev@cordova.apache.org">\n' +
-    '        Apache Cordova Team\n' +
-    '    </author>\n' +
-    '    <content src="index.html" />\n' +
-    '    <access origin="*" />\n' +
-    '    <preference name="fullscreen" value="true" />\n' +
-    '    <preference name="webviewbounce" value="true" />\n' +
-    '</widget>\n';
-
-describe('create command', function () {
-    var mkdir, cp, config_spy, load_cordova, load_custom, exists, config_read, config_write;
-    beforeEach(function() {
-        shell.rm('-rf', tempDir);
-        mkdir = spyOn(shell, 'mkdir');
-        cp = spyOn(shell, 'cp');
-        config_spy = spyOn(cordova, 'config');
-        config_read = spyOn(config, 'read').andReturn({});
-        config_write = spyOn(config, 'write').andReturn({});
-        exists = spyOn(fs, 'existsSync').andCallFake(function(p) {
-            if (p == 'lib/dir') return true;
-            return false;
-        });
-        load_cordova = spyOn(lazy_load, 'cordova').andReturn(Q(path.join('lib','dir')));
-        load_custom = spyOn(lazy_load, 'custom').andReturn(Q(path.join('lib','dir')));
-        spyOn(ConfigParser.prototype, 'write');
-        spyOn(xmlHelpers, 'parseElementtreeSync').andCallFake(function() {
-            return new et.ElementTree(et.XML(TEST_XML));
-        });
-    });
-
-    describe('failure', function() {
-        it('should return a help message if incorrect number of parameters is used', function(done) {
-            this.after(function() {
-                cordova.removeAllListeners('results');
-            });
-            cordova.on('results', function(h) {
-                expect(h).toMatch(/synopsis/gi);
-                done();
-            });
-            cordova.raw.create();
-        });
-    });
-
-    describe('success', function() {
-        it('should create top-level directory structure appropriate for a cordova-cli project', function(done) {
-            cordova.raw.create(tempDir).then(function() {
-                expect(mkdir).toHaveBeenCalledWith(path.join(tempDir, 'platforms'));
-                expect(mkdir).toHaveBeenCalledWith(path.join(tempDir, 'merges'));
-                expect(mkdir).toHaveBeenCalledWith(path.join(tempDir, 'plugins'));
-                expect(mkdir).toHaveBeenCalledWith(path.join(tempDir, 'www'));
-                done();
-            });
-        });
-        it('should create hooks directory', function(done) {
-            var hooks_dir = path.join(tempDir, 'hooks');
-            cordova.raw.create(tempDir).then(function() {
-                expect(mkdir).toHaveBeenCalledWith(hooks_dir);
-                expect(cp).toHaveBeenCalledWith(
-                    path.resolve(__dirname, '..', 'templates', 'hooks-README.md'),
-                    jasmine.any(String)
-                );
-                done();
-            });
-        });
-        it('should by default use cordova-app-hello-world as www assets', function(done) {
-            cordova.raw.create(tempDir).then(function() {
-                expect(load_cordova).toHaveBeenCalledWith('www');
-                done();
-            });
-        });
-        it('should try to lazy load custom www location if specified', function(done) {
-            var fake_config = {
-                lib:{
-                    www:{
-                        id:'supercordova',
-                        uri:'/supacordoba',
-                        version:'1337'
-                    }
-                }
-            };
-            config_read.andReturn(fake_config);
-            config_write.andReturn(fake_config);
-            cordova.raw.create(tempDir, 'some.app.id', 'SomeAppName', fake_config).then(function() {
-                expect(load_custom).toHaveBeenCalledWith(fake_config.lib.www.uri, fake_config.lib.www.id, 'www', fake_config.lib.www.version);
-                done();
-            });
-        });
-        it('should add a missing www/config.xml', function(done) {
-            cordova.raw.create(tempDir).then(function() {
-                expect(shell.cp).toHaveBeenCalledWith(
-                    path.resolve(__dirname, '..', 'templates', 'config.xml'),
-                    jasmine.any(String)
-                );
-                done();
-            });
-        });
-        it('should not replace an existing www/config.xml', function(done) {
-            exists.andCallFake(function(p) {
-                if (p == 'lib/dir') return true;
-                if (p.indexOf('config.xml') > -1) return true;
-                return false;
-            });
-            cordova.raw.create(tempDir).then(function() {
-                expect(shell.cp).not.toHaveBeenCalledWith(
-                    path.resolve(__dirname, '..', 'templates', 'config.xml'),
-                    jasmine.any(String)
-                );
-                done();
-            });
-        });
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/fde755fe/spec/platform.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform.spec.js b/spec/platform.spec.js
deleted file mode 100644
index d4ad000..0000000
--- a/spec/platform.spec.js
+++ /dev/null
@@ -1,482 +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 cordova = require('../cordova'),
-    events = require('../src/events'),
-    path = require('path'),
-    shell = require('shelljs'),
-    superspawn = require('../src/superspawn'),
-    xmlHelpers = require('../src/xml-helpers'),
-    et = require('elementtree'),
-    plugman = require('plugman'),
-    fs = require('fs'),
-    util = require('../src/util'),
-    config = require('../src/config'),
-    hooker = require('../src/hooker'),
-    lazy_load = require('../src/lazy_load'),
-    Q = require('q'),
-    platform = require('../src/platform'),
-    platforms = require('../platforms');
-
-var cwd = process.cwd();
-var supported_platforms = Object.keys(platforms).filter(function(p) { return p != 'www'; });
-var project_dir = path.join('some', 'path');
-
-var TEST_XML = '<widget xmlns     = "http://www.w3.org/ns/widgets"\n' +
-    '        xmlns:cdv = "http://cordova.apache.org/ns/1.0"\n' +
-    '        id        = "io.cordova.hellocordova"\n' +
-    '        version   = "0.0.1">\n' +
-    '    <name>Hello Cordova</name>\n' +
-    '</widget>\n';
-
-function fail(e) {
-  expect('Got Error: ' + e).toBe('');
-}
-
-describe('platform command', function() {
-    var is_cordova,
-        cd_project_root,
-        cp,
-        list_platforms,
-        fire,
-        find_plugins,
-        config_read,
-        load,
-        load_custom,
-        rm,
-        mkdir,
-        existsSync,
-        supports,
-        spawn,
-        prep_spy,
-        plugman_install,
-        parsers = {};
-    beforeEach(function() {
-        supported_platforms.forEach(function(p) {
-            parsers[p] = spyOn(platforms[p], 'parser').andReturn({
-                staging_dir:function(){},
-                www_dir:function(){return 'pwww'}
-            });
-        });
-        is_cordova = spyOn(util, 'isCordova').andReturn(project_dir);
-        cd_project_root = spyOn(util, 'cdProjectRoot').andReturn(project_dir);
-        fire = spyOn(hooker.prototype, 'fire').andReturn(Q());
-        spyOn(xmlHelpers, 'parseElementtreeSync').andCallFake(function() {
-            return new et.ElementTree(et.XML(TEST_XML));
-        });
-        find_plugins = spyOn(util, 'findPlugins').andReturn([]);
-        list_platforms = spyOn(util, 'listPlatforms').andReturn(supported_platforms);
-        util.libDirectory = path.join('HOMEDIR', '.cordova', 'lib');
-        config_read = spyOn(config, 'read').andReturn({});
-
-        fakeLazyLoad = function(id, platform, version) {
-            if (platform == 'wp7' || platform == 'wp8') {
-                return Q(path.join('lib', 'wp', id, version, platform));
-            } else {
-                return Q(path.join('lib', platform, id, version, platforms[platform] && platforms[platform].subdirectory ? platforms[platform].subdirectory : ''));
-            }
-        };
-        lazyLoadVersion = '3.1.0';
-        load = spyOn(lazy_load, 'based_on_config').andCallFake(function(root, platform) {
-            return fakeLazyLoad('cordova', platform, lazyLoadVersion);
-        });
-        load_custom = spyOn(lazy_load, 'custom').andCallFake(function(url, id, platform, version) {
-            return fakeLazyLoad(id, platform, version);
-        });
-
-        rm = spyOn(shell, 'rm');
-        cp = spyOn(shell, 'cp');
-        mkdir = spyOn(shell, 'mkdir');
-        existsSync = spyOn(fs, 'existsSync').andReturn(false);
-        var origReadFile = fs.readFileSync;
-        spyOn(fs, 'readFileSync').andCallFake(function(path) {
-            if (/VERSION$/.test(path)) {
-                return '3.3.0';
-            }
-            return origReadFile.apply(this, arguments);
-        });
-        supports = spyOn(platform, 'supports').andReturn(Q());
-        spawn = spyOn(superspawn, 'spawn').andCallFake(function() { return Q('3.4.0') });
-        prep_spy = spyOn(cordova.raw, 'prepare').andReturn(Q());
-        plugman_install = spyOn(plugman, 'install').andReturn(Q());
-    });
-
-    describe('failure', function() {
-        function expectFailure(p, done, post) {
-            p.then(function() {
-                expect('this call').toBe('fail');
-            }, post).fin(done);
-        }
-
-        it('should not run outside of a Cordova-based project by calling util.isCordova', function(done) {
-            var msg = 'Dummy message about not being in a cordova dir.';
-            cd_project_root.andThrow(new Error(msg));
-            expectFailure(Q().then(cordova.raw.platform), done, function(err) {
-                expect(cd_project_root).toHaveBeenCalled();
-                expect(err.message).toEqual(msg);
-            });
-        });
-        it('should report back an error if used with `add` and no platform is specified', function(done) {
-            expectFailure(cordova.raw.platform('add'), done, function(err) {
-                expect(err).toEqual(new Error('You need to qualify `add` or `remove` with one or more platforms!'));
-            });
-        });
-        it('should report back an error if used with `rm` and no platform is specified', function(done) {
-            expectFailure(cordova.raw.platform('rm'), done, function(err) {
-                expect(err).toEqual(new Error('You need to qualify `add` or `remove` with one or more platforms!'));
-            });
-        });
-    });
-
-    describe('success', function() {
-        it('should run inside a Cordova-based project by calling util.isCordova', function(done) {
-            cordova.raw.platform().then(function() {
-                expect(is_cordova).toHaveBeenCalled();
-            }, fail).fin(done);
-        });
-
-        describe('`ls`', function() {
-            afterEach(function() {
-                cordova.removeAllListeners('results');
-            });
-            it('should list out no platforms for a fresh project', function(done) {
-                list_platforms.andReturn([]);
-                cordova.on('results', function(res) {
-                    expect(res).toMatch(/^Installed platforms:\s*Available platforms:.*$/);
-                    done();
-                });
-                cordova.raw.platform('list');
-
-            });
-            it('should list out added platforms in a project', function(done) {
-                cordova.on('results', function(res) {
-                    expect(res).toMatch(RegExp("^Installed platforms: "+supported_platforms.sort().join(", ")+"\\s*Available platforms:\\s*$"));
-                    done();
-                });
-                cordova.raw.platform('list');
-            });
-        });
-        describe('`add`', function() {
-            beforeEach(function() {
-                supported_platforms.forEach(function(p) {
-                    platforms[p].parser.check_requirements = function(){return Q();};
-                });
-            });
-
-            it('should shell out to specified platform\'s bin/create, using the version that is specified in platforms manifest', function(done) {
-                cordova.raw.platform('add', 'android').then(function() {
-                    expect(spawn.mostRecentCall.args.join()).toMatch(/lib.android.cordova.\d.\d.\d[\d\-\w]*.bin.create/gi);
-                    expect(spawn.mostRecentCall.args.join()).toContain(project_dir);
-                }).then(function() {
-                    return cordova.raw.platform('add', 'wp7');
-                }).then(function() {
-                    expect(spawn.mostRecentCall.args.join()).toMatch(/lib.wp.cordova.\d.\d.\d[\d\w\-]*.wp7.*.bin.create/gi);
-                    expect(spawn.mostRecentCall.args.join()).toContain(project_dir);
-                }).then(function() {
-                    return cordova.raw.platform('add', 'wp8');
-                }).then(function() {
-                    expect(spawn.mostRecentCall.args.join()).toMatch(/lib.wp.cordova.\d.\d.\d[\d\w\-]*.wp8.*.bin.create/gi);
-                    expect(spawn.mostRecentCall.args.join()).toContain(project_dir);
-                }).then(function(){
-                    return cordova.raw.platform('add', 'windows8');
-                }).then(function(){
-                    expect(spawn.mostRecentCall.args.join()).toMatch(/lib.windows8.cordova.\d.\d.\d[\d\w\-]*.windows8.*.bin.create/gi);
-                    expect(spawn.mostRecentCall.args.join()).toContain(project_dir);
-                }, fail).fin(done);
-            });
-            it('should call into lazy_load.custom if there is a user-specified configruation for consuming custom libraries', function(done) {
-                load.andCallThrough();
-                config_read.andReturn({
-                    lib:{
-                        'wp8':{
-                            uri:'haha',
-                            id:'phonegap',
-                            version:'bleeding edge'
-                        }
-                    }
-                });
-                cordova.raw.platform('add', 'wp8').then(function() {
-                    expect(load_custom).toHaveBeenCalledWith('haha', 'phonegap', 'wp8', 'bleeding edge');
-                    expect(spawn.mostRecentCall.args.join()).toMatch(/lib.wp.phonegap.bleeding edge.wp8.*.bin.create/gi);
-                    expect(spawn.mostRecentCall.args.join()).toContain(project_dir);
-                }, fail).fin(done);
-            });
-            it('should use a custom template directory if there is one specified in the configuration', function(done) {
-                var template_dir = "/tmp/custom-template"
-                load.andCallThrough();
-                config_read.andReturn({
-                    lib: {
-                        android: {
-                            uri: "https://git-wip-us.apache.org/repos/asf?p=cordova-android.git",
-                            version: "3.0.0",
-                            id: "cordova",
-                            template: template_dir
-                        }
-                    }
-                });
-                cordova.raw.platform('add', 'android').then(function() {
-                    expect(spawn.mostRecentCall.args.join()).toContain(project_dir);
-                    expect(spawn.mostRecentCall.args.join()).toContain(template_dir);
-                }, fail).fin(done);
-            });
-            it('should not use a custom template directory if there is not one specified in the configuration', function(done) {
-                load.andCallThrough();
-                config_read.andReturn({
-                    lib: {
-                        android: {
-                            uri: "https://git-wip-us.apache.org/repos/asf?p=cordova-android.git",
-                            version: "3.0.0",
-                            id: "cordova",
-                        }
-                    }
-                });
-                cordova.raw.platform('add', 'android').then(function() {
-                    expect(spawn.mostRecentCall.args.join()).toContain(project_dir);
-                }, fail).fin(done);
-            });
-            it('should not use a custom template directory if there is no user-defined configuration', function(done) {
-                cordova.raw.platform('add', 'android').then(function() {
-                    expect(spawn.mostRecentCall.args.join()).toContain(project_dir);
-                }, fail).fin(done);
-            });
-        });
-        describe('`remove`',function() {
-            it('should remove a supported and added platform', function(done) {
-                cordova.raw.platform('remove', 'android').then(function() {
-                    expect(rm).toHaveBeenCalledWith('-rf', path.join(project_dir, 'platforms', 'android'));
-                }, fail).fin(done);
-            });
-
-            it('should be able to remove multiple platforms', function(done) {
-                cordova.raw.platform('remove', ['android', 'blackberry10']).then(function() {
-                    expect(rm).toHaveBeenCalledWith('-rf', path.join(project_dir, 'platforms', 'android'));
-                    expect(rm).toHaveBeenCalledWith('-rf', path.join(project_dir, 'platforms', 'blackberry10'));
-                }, fail).fin(done);
-            });
-        });
-        describe('`update`', function() {
-            describe('failure', function() {
-                it('should fail if no platform is specified', function(done) {
-                    cordova.raw.platform('update', []).then(function() {
-                        expect('this call').toBe('fail');
-                    }, function(err) {
-                        expect(err).toEqual(new Error('No platform provided. Please specify a platform to update.'));
-                    }).fin(done);
-                });
-                it('should fail if more than one platform is specified', function(done) {
-                    cordova.raw.platform('update', ['android', 'ios']).then(function() {
-                        expect('this call').toBe('fail');
-                    }, function(err) {
-                        expect(err).toEqual(new Error('Platform update can only be executed on one platform at a time.'));
-                    }).fin(done);
-                });
-            });
-
-            // Don't run this test on windows ... iOS will fail always
-            if(!require('os').platform().match(/^win/)) {
-                describe('success', function() {
-                    it('should shell out to the platform update script', function(done) {
-                        var oldVersion = lazyLoadVersion;
-                        lazyLoadVersion = '1.0.0';
-                        cordova.raw.platform('update', ['ios']).then(function() {
-                            expect(exec).toHaveBeenCalledWith('"lib/ios/cordova/1.0.0/bin/update" "some/path/platforms/ios"', jasmine.any(Function));
-                        }, fail).fin(function() {
-                            lazyLoadVersion = oldVersion;
-                            done();
-                        });
-                    });
-                });
-            }
-        });
-        describe('`check`', function() {
-            var real_platforms_data = {},
-            synthetic_platforms_data = {
-                current: {
-                    uri: "https://localhost",
-                    version: "3.3.0",
-                    parser: function(){}
-                },
-                stale: {
-                    uri: "https://localhost",
-                    version: "3.3.0",
-                    parser: function(){}
-                },
-                newer: {
-                    uri: "https://localhost",
-                    version: "3.3.0",
-                    parser: function(){}
-                }
-            };
-            beforeEach(function() {
-                list_platforms.andReturn(['current', 'stale', 'newer']);
-                Object.keys(platforms).forEach(function (k) {
-                    real_platforms_data[k] = platforms[k];
-                    delete platforms[k];
-                });
-                Object.keys(synthetic_platforms_data).forEach(function (k) {
-                    platforms[k] = synthetic_platforms_data[k];
-                });
-            });
-            afterEach(function() {
-                list_platforms.andReturn(['current', 'stale', 'newer']);
-                Object.keys(platforms).forEach(function (k) {
-                    delete platforms[k];
-                });
-                Object.keys(real_platforms_data).forEach(function (k) {
-                    platforms[k] = real_platforms_data[k];
-                });
-            });
-            it('check platforms current, stale, newer', function() {
-                existsSync.andCallFake(function(dir) {
-                    if (/cordova-platform-check.*version/.test(dir)) {
-                        return true;
-                    }
-                    if (/cordova-platform-check/.test(dir)) {
-                        return false;
-                    }
-                    return true;
-                });
-                var create = spyOn(cordova.raw, 'create').andCallFake(function() { return Q() });
-
-                spawn.andCallFake(function(cmd) {
-                    var out;
-                    if (/cordova-platform-check/.test(cmd)) {
-                        out = '3.3.0';
-                    } else if (/current/.test(cmd)) {
-                        out = '3.3.0';
-                    } else if (/stale/.test(cmd)) {
-                        out = '3.2.0';
-                    } else {
-                        out = '3.4.0';
-                    }
-                    return Q(out);
-                });
-                var results;
-                events.on('results', function(res) { results = res; });
-
-                cordova.raw.platform('check');
-                waitsFor(function() {
-                    return results;
-                }, 'promise never resolved', 500);
-                runs(function() {
-                    expect(results).toEqual("stale @ 3.2.0 could be updated to: 3.3.0");
-                });
-            });
-        });
-    });
-    describe('hooks', function() {
-        describe('list (ls) hooks', function(done) {
-            it('should fire before hooks through the hooker module', function() {
-                cordova.raw.platform().then(function() {
-                    expect(fire).toHaveBeenCalledWith('before_platform_ls');
-                }, fail).fin(done);
-            });
-            it('should fire after hooks through the hooker module', function(done) {
-                cordova.raw.platform().then(function() {
-                    expect(fire).toHaveBeenCalledWith('after_platform_ls');
-                }, fail).fin(done);
-            });
-        });
-        describe('remove (rm) hooks', function() {
-            it('should fire before hooks through the hooker module', function(done) {
-                cordova.raw.platform('rm', 'android').then(function() {
-                    expect(fire).toHaveBeenCalledWith('before_platform_rm', {platforms:['android']});
-                }, fail).fin(done);
-            });
-            it('should fire after hooks through the hooker module', function(done) {
-                cordova.raw.platform('rm', 'android').then(function() {
-                    expect(fire).toHaveBeenCalledWith('after_platform_rm', {platforms:['android']});
-                }, fail).fin(done);
-            });
-        });
-        describe('add hooks', function() {
-            beforeEach(function() {
-                supported_platforms.forEach(function(p) {
-                    platforms[p].parser.check_requirements = function(){return Q();};
-                });
-            });
-
-            it('should fire before and after hooks through the hooker module', function(done) {
-                cordova.raw.platform('add', 'android').then(function() {
-                    expect(fire).toHaveBeenCalledWith('before_platform_add', {platforms:['android']});
-                    expect(fire).toHaveBeenCalledWith('after_platform_add', {platforms:['android']});
-                }, fail).fin(done);
-            });
-        });
-    });
-});
-
-describe('platform.supports(name)', function() {
-    var supports = {};
-    beforeEach(function() {
-        supported_platforms.forEach(function(p) {
-            supports[p] = spyOn(platforms[p].parser, 'check_requirements').andReturn(Q());
-        });
-    });
-
-    function expectFailure(p, done, post) {
-        p.then(function() {
-            expect('this call').toBe('fail');
-        }, post).fin(done);
-    }
-
-    it('should require a platform name', function(done) {
-        expectFailure(cordova.raw.platform.supports(project_dir, undefined), done, function(err) {
-            expect(err).toEqual(jasmine.any(Error));
-        });
-    });
-
-    describe('when platform is unknown', function() {
-        it('should reject', function(done) {
-            expectFailure(cordova.raw.platform.supports(project_dir, 'windows-3.1'), done, function(err) {
-                expect(err).toEqual(jasmine.any(Error));
-                done();
-            });
-        });
-    });
-
-    describe('when platform is supported', function() {
-        it('should resolve', function(done) {
-            cordova.raw.platform.supports(project_dir, 'android').then(function() {
-                expect(1).toBe(1);
-            }, fail).fin(done);
-        });
-    });
-
-    describe('when platform is unsupported', function() {
-        it('should reject', function(done) {
-            supported_platforms.forEach(function(p) {
-                supports[p].andReturn(Q.reject(new Error('no sdk')));
-            });
-            expectFailure(cordova.raw.platform.supports(project_dir, 'android'), done, function(err) {
-                expect(err).toEqual(jasmine.any(Error));
-            });
-        });
-    });
-});
-
-describe('platform parsers', function() {
-    it('should be exposed on the platform module', function() {
-        for (var platform in platforms) {
-            expect(cordova.raw.platform[platform]).toBeDefined();
-            for (var prop in platforms[platform]) {
-                expect(cordova.raw.platform[platform][prop]).toBeDefined();
-            }
-        }
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/fde755fe/spec/plugin.spec.js
----------------------------------------------------------------------
diff --git a/spec/plugin.spec.js b/spec/plugin.spec.js
deleted file mode 100644
index d427f00..0000000
--- a/spec/plugin.spec.js
+++ /dev/null
@@ -1,288 +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 cordova = require('../cordova'),
-    path = require('path'),
-    shell = require('shelljs'),
-    child_process = require('child_process'),
-    plugman = require('plugman'),
-    fs = require('fs'),
-    util = require('../src/util'),
-    config = require('../src/config'),
-    hooker = require('../src/hooker'),
-    Q = require('q'),
-    platforms = require('../platforms');
-
-var cwd = process.cwd();
-var supported_platforms = Object.keys(platforms).filter(function(p) { return p != 'www'; }).sort();
-var sample_plugins = ['one','two'];
-var project_dir = path.join('some','path');
-var plugins_dir = path.join(project_dir, 'plugins');
-
-describe('plugin command', function() {
-    var is_cordova,
-        cd_project_root,
-        list_platforms,
-        fire,
-        find_plugins,
-        rm,
-        mkdir,
-        existsSync,
-        exec,
-        prep_spy,
-        plugman_install,
-        plugman_fetch,
-        parsers = {},
-        uninstallPlatform,
-        uninstallPlugin;
-
-    beforeEach(function() {
-        is_cordova = spyOn(util, 'isCordova').andReturn(project_dir);
-        cd_project_root = spyOn(util, 'cdProjectRoot').andReturn(project_dir);
-        fire = spyOn(hooker.prototype, 'fire').andReturn(Q());
-        supported_platforms.forEach(function(p) {
-            parsers[p] = jasmine.createSpy(p + ' update_project').andReturn(Q());
-            spyOn(platforms[p], 'parser').andReturn({});
-        });
-        list_platforms = spyOn(util, 'listPlatforms').andReturn(supported_platforms);
-        find_plugins = spyOn(util, 'findPlugins').andReturn(sample_plugins);
-        rm = spyOn(shell, 'rm');
-        mkdir = spyOn(shell, 'mkdir');
-        existsSync = spyOn(fs, 'existsSync').andReturn(false);
-        exec = spyOn(child_process, 'exec').andCallFake(function(cmd, opts, cb) {
-            if (!cb) cb = opts;
-            cb(0, '', '');
-        });
-        prep_spy = spyOn(cordova.raw, 'prepare').andReturn(Q());
-        plugman_install = spyOn(plugman.raw, 'install').andReturn(Q());
-        plugman_fetch = spyOn(plugman.raw, 'fetch').andCallFake(function(target, plugins_dir, opts) { return Q(path.join(plugins_dir, target)); });
-        plugman_search = spyOn(plugman.raw, 'search').andReturn(Q());
-        uninstallPlatform = spyOn(plugman.raw.uninstall, 'uninstallPlatform').andReturn(Q());
-        uninstallPlugin = spyOn(plugman.raw.uninstall, 'uninstallPlugin').andReturn(Q());
-    });
-
-    describe('failure', function() {
-        function expectFailure(p, done, post) {
-            p.then(function() {
-                expect('this call').toBe('fail');
-            }, post).fin(done);
-        }
-
-        it('should not run outside of a Cordova-based project by calling util.isCordova', function(done) {
-            var msg = 'Dummy message about not being in a cordova dir.';
-            cd_project_root.andThrow(new Error(msg));
-            is_cordova.andReturn(false);
-            expectFailure(Q().then(cordova.raw.plugin), done, function(err) {
-                expect(err.message).toEqual(msg);
-            });
-        });
-        it('should report back an error if used with `add` and no plugin is specified', function(done) {
-            expectFailure(cordova.raw.plugin('add'), done, function(err) {
-                expect(err).toEqual(new Error('You need to qualify `add` or `remove` with one or more plugins!'));
-            });
-        });
-        it('should report back an error if used with `rm` and no plugin is specified', function(done) {
-            expectFailure(cordova.raw.plugin('rm'), done, function(err) {
-                expect(err).toEqual(new Error('You need to qualify `add` or `remove` with one or more plugins!'));
-            });
-        });
-    });
-
-    describe('success', function() {
-        it('should run inside a Cordova-based project by calling util.isCordova', function(done) {
-            cordova.raw.plugin().then(function() {
-                expect(is_cordova).toHaveBeenCalled();
-                done();
-            });
-        });
-
-        describe('`ls`', function() {
-            afterEach(function() {
-                cordova.removeAllListeners('results');
-            });
-            it('should list out no plugins for a fresh project', function(done) {
-                find_plugins.andReturn([]);
-                cordova.on('results', function(res) {
-                    expect(res).toEqual('No plugins added. Use `cordova plugin add <plugin>`.');
-                    done();
-                });
-                cordova.raw.plugin('list');
-            });
-            it('should list out added plugins in a project', function(done) {
-                cordova.on('results', function(res) {
-                    expect(res).toEqual(sample_plugins);
-                    done();
-                });
-                cordova.raw.plugin('list');
-            });
-            it('should resolve with a list of plugins', function(done) {
-                cordova.raw.plugin('list', []).then(function(plugins) {
-                    expect(plugins).toEqual(sample_plugins);
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-        });
-        describe('`add`', function() {
-            it('should call plugman.fetch for each plugin', function(done) {
-                cordova.raw.plugin('add', sample_plugins).then(function() {
-                    sample_plugins.forEach(function(p) {
-                        expect(plugman_fetch).toHaveBeenCalledWith(p, plugins_dir, {});
-                    });
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-            it('should call plugman.install, for each plugin, for every platform', function(done) {
-                cordova.raw.plugin('add', sample_plugins).then(function(err) {
-                    sample_plugins.forEach(function(plug) {
-                        supported_platforms.forEach(function(plat) {
-                            expect(plugman_install).toHaveBeenCalledWith((plat=='blackberry'?'blackberry10':plat), path.join(project_dir, 'platforms', plat), plug, plugins_dir, jasmine.any(Object));
-                        });
-                    });
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-            it('should pass down variables into plugman', function(done) {
-                cordova.raw.plugin('add', "one", "--variable", "foo=bar").then(function() {
-                    supported_platforms.forEach(function(plat) {
-                        expect(plugman_install).toHaveBeenCalledWith(
-                            (plat=='blackberry'?'blackberry10':plat),
-                            path.join(project_dir, 'platforms', plat),
-                            "one",
-                            plugins_dir,
-                            {cli_variables: { FOO: "bar"}}
-                        );
-                    });
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-            it('should resolve without an error', function(done) {
-                cordova.raw.plugin('add', sample_plugins).then(function() {
-                    expect(1).toBe(1);
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-        });
-        describe('`search`', function() {
-            it('should call plugman.search', function(done) {
-                cordova.raw.plugin('search', sample_plugins).then(function() {
-                    expect(plugman_search).toHaveBeenCalledWith(sample_plugins);
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-        });
-        describe('`remove`',function() {
-            var plugin_parser;
-            var subset = ['android', 'wp7'];
-            beforeEach(function() {
-                plugin_parser = spyOn(util, 'plugin_parser').andReturn({
-                    platforms:subset
-                });
-            });
-            it('should throw if plugin is not installed', function(done) {
-                cordova.raw.plugin('rm', 'somethingrandom').then(function() {
-                    expect('this call').toBe('fail');
-                }, function(err) {
-                    expect(err).toEqual(new Error('Plugin "somethingrandom" not added to project.'));
-                }).fin(done);
-            });
-
-            it('should call plugman.uninstall.uninstallPlatform for every matching installedplugin-supportedplatform pair', function(done) {
-                cordova.raw.plugin('rm', sample_plugins).then(function() {
-                    sample_plugins.forEach(function(plug) {
-                        subset.forEach(function(plat) {
-                            expect(uninstallPlatform).toHaveBeenCalledWith(plat, path.join(project_dir, 'platforms', plat), plug, plugins_dir);
-                        });
-                    });
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-            it('should call plugman.uninstall.uninstallPlugin once for every removed plugin', function(done) {
-                uninstallPlugin.reset();
-                cordova.raw.plugin('rm', sample_plugins).then(function() {
-                    expect(uninstallPlugin.callCount).toBe(2);
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-            it('should resolve without an error', function(done) {
-                cordova.raw.plugin('rm', sample_plugins).then(function() {
-                    expect(1).toBe(1);
-                }, function(err) {
-                    expect(err).not.toBeDefined();
-                }).fin(done);
-            });
-        });
-    });
-    describe('hooks', function() {
-        var plugin_parser;
-        beforeEach(function() {
-            plugin_parser = spyOn(util, 'plugin_parser').andReturn({
-                platforms:supported_platforms
-            });
-        });
-        describe('list (ls) hooks', function() {
-            it('should fire before hooks through the hooker module', function(done) {
-                cordova.raw.plugin().then(function() {
-                    expect(fire).toHaveBeenCalledWith('before_plugin_ls');
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-            it('should fire after hooks through the hooker module', function(done) {
-                cordova.raw.plugin().then(function() {
-                    expect(fire).toHaveBeenCalledWith('after_plugin_ls');
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-        });
-        describe('remove (rm) hooks', function() {
-            it('should fire before hooks through the hooker module', function(done) {
-                cordova.raw.plugin('rm', 'two').then(function() {
-                    expect(fire).toHaveBeenCalledWith('before_plugin_rm', {plugins:['two'], options: []});
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-            it('should fire after hooks through the hooker module', function(done) {
-                cordova.raw.plugin('rm', 'one').then(function() {
-                    expect(fire).toHaveBeenCalledWith('after_plugin_rm', {plugins:['one'], options:[]});
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-        });
-        describe('add hooks', function() {
-            it('should fire before and after hooks through the hooker module', function(done) {
-                cordova.raw.plugin('add', 'android').then(function() {
-                    expect(fire).toHaveBeenCalledWith('before_plugin_add', {plugins:['android'], options: []});
-                    expect(fire).toHaveBeenCalledWith('after_plugin_add', {plugins:['android'], options: []});
-                }, function(err) {
-                    expect(err).toBeUndefined();
-                }).fin(done);
-            });
-        });
-    });
-});


[8/8] git commit: CB-6421: Move tests from e2e to spec - cli test

Posted by ka...@apache.org.
CB-6421: Move tests from e2e to spec - cli test

After e2e dir was merged into spec/ there were interferences between the e2e
tests and cli.spec.js. Jasmine runs all tests in a single process, therefore
process-global settings like event listener (un)registration can cause
interference between the tests.

github: close #159


Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/38db7a2d
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/38db7a2d
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/38db7a2d

Branch: refs/heads/master
Commit: 38db7a2db44fbb251df3af1567699df3b1a3ec1e
Parents: f4a9597
Author: Mark Koudritsky <ka...@gmail.com>
Authored: Wed Apr 9 15:23:48 2014 -0400
Committer: Mark Koudritsky <ka...@gmail.com>
Committed: Mon Apr 14 20:28:17 2014 -0400

----------------------------------------------------------------------
 package.json     |  2 +-
 spec/cli.spec.js | 18 ++++++++++--------
 2 files changed, 11 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/38db7a2d/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 87d2eb1..ae02211 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
     "cordova": "./bin/cordova"
   },
   "scripts": {
-    "test": "jasmine-node --color spec e2e"
+    "test": "jasmine-node --color spec"
   },
   "repository": {
     "type": "git",

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/38db7a2d/spec/cli.spec.js
----------------------------------------------------------------------
diff --git a/spec/cli.spec.js b/spec/cli.spec.js
index 835e8eb..c09042d 100644
--- a/spec/cli.spec.js
+++ b/spec/cli.spec.js
@@ -16,11 +16,21 @@
     specific language governing permissions and limitations
     under the License.
 */
+
 var CLI = require("../src/cli"),
     Q = require('q'),
+    plugman = require('plugman'),
     cordova = require("../cordova");
 
 describe("cordova cli", function () {
+    beforeEach(function () {
+        // Event registration is currently process-global. Since all jasmine
+        // tests in a directory run in a single process (and in parallel),
+        // logging events registered as a result of the "--verbose" flag in
+        // CLI testing below would cause lots of logging messages printed out by other specs.
+        spyOn(cordova, "on");
+        spyOn(plugman, "on");
+    });
 
     describe("options", function () {
         describe("version", function () {
@@ -51,10 +61,6 @@ describe("cordova cli", function () {
             spyOn(cordova.raw, "build").andReturn(Q());
         });
 
-        afterEach(function () {
-            cordova.removeAllListeners();
-        });
-
         it("will call command with all arguments passed through", function () {
             new CLI(["node", "cordova", "build", "blackberry10", "-k", "abcd1234"]);
             expect(cordova.raw.build).toHaveBeenCalledWith({verbose: false, silent: false, platforms: ["blackberry10"], options: ["-k", "abcd1234"]});
@@ -91,10 +97,6 @@ describe("cordova cli", function () {
             spyOn(cordova.raw, "plugin").andReturn(Q());
         });
 
-        afterEach(function () {
-            cordova.removeAllListeners();
-        });
-
         it("will call command with all arguments passed through", function () {
             new CLI(["node", "cordova", "plugin", "add", "facebook", "--variable", "FOO=foo"]);
             expect(cordova.raw.plugin).toHaveBeenCalledWith("add", ["facebook", "--variable", "FOO=foo"], {searchpath: undefined});


[4/8] CB-6421: Move tests from e2e to spec

Posted by ka...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/check_reqs.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/check_reqs.js b/e2e/fixtures/platforms/android/cordova/lib/check_reqs.js
deleted file mode 100755
index c064499..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/check_reqs.js
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/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 shell = require('shelljs'),
-    path  = require('path'),
-    fs    = require('fs'),
-    ROOT  = path.join(__dirname, '..', '..');
-
-// Get valid target from framework/project.properties
-module.exports.get_target = function() {
-    if(fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
-        var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'framework', 'project.properties'));
-        return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
-    } else if (fs.existsSync(path.join(ROOT, 'project.properties'))) {
-        // if no target found, we're probably in a project and project.properties is in ROOT.
-        var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties'));
-        return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
-    }
-}
-
-module.exports.check_ant = function() {
-    var test = shell.exec('ant -version', {silent:true, async:false});
-    if(test.code > 0) {
-        console.error('ERROR : executing command \'ant\', make sure you have ant installed and added to your path.');
-        return false;
-    }
-    return true;
-}
-
-module.exports.check_java = function() {
-    if(process.env.JAVA_HOME) {
-        var test = shell.exec('java', {silent:true, async:false});
-        if(test.code > 0) {
-            console.error('ERROR : executing command \'java\', make sure you java environment is set up. Including your JDK and JRE.');
-            return false;
-        }
-        return true;
-    } else {
-        console.error('ERROR : Make sure JAVA_HOME is set, as well as paths to your JDK and JRE for java.');
-        return false;
-    }
-}
-
-module.exports.check_android = function() {
-    var valid_target = this.get_target();
-    var targets = shell.exec('android list targets', {silent:true, async:false});
-
-    if(targets.code > 0 && targets.output.match(/command\snot\sfound/)) {
-        console.error('The command \"android\" failed. Make sure you have the latest Android SDK installed, and the \"android\" command (inside the tools/ folder) is added to your path.');
-        return false;
-    } else if(!targets.output.match(valid_target)) {
-        console.error('Please install Android target ' + valid_target.split('-')[1] + ' (the Android newest SDK). Make sure you have the latest Android tools installed as well. Run \"android\" from your command-line to install/update any missing SDKs or tools.');
-        return false;
-    }
-    return true;
-}
-
-module.exports.run = function() {
-    return this.check_ant() && this.check_java && this.check_android();
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/clean.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/clean.js b/e2e/fixtures/platforms/android/cordova/lib/clean.js
deleted file mode 100755
index 8f14015..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/clean.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/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 shell = require('shelljs'),
-    path  = require('path'),
-    ROOT = path.join(__dirname, '..', '..');
-
-/*
- * Cleans the project using ant
- */
-module.exports.run = function() {
-    var cmd = 'ant clean -f ' + path.join(ROOT, 'build.xml');
-    var result = shell.exec(cmd, {silent:false, async:false});
-    if (result.code > 0) {
-        console.error('ERROR: Failed to clean android project.');
-        console.error(result.output);
-        process.exit(2);
-    }
-}
-
-module.exports.help = function() {
-    console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'clean')));
-    console.log('Cleans the project directory.');
-    process.exit(0);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/device.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/device.js b/e2e/fixtures/platforms/android/cordova/lib/device.js
deleted file mode 100755
index 363dc2b..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/device.js
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/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 shell = require('shelljs'),
-    path  = require('path'),
-    build = require('./build'),
-    appinfo = require('./appinfo'),
-    exec  = require('child_process').exec,
-    ROOT = path.join(__dirname, '..', '..');
-
-/**
- * Returns a list of the device ID's found
- */
-module.exports.list = function() {
-    var cmd = 'adb devices';
-    var result = shell.exec(cmd, {silent:true, async:false});
-    if (result.code > 0) {
-        console.error('Failed to execute android command \'' + cmd + '\'.');
-        process.exit(2);
-    } else {
-        var response = result.output.split('\n');
-        var device_list = [];
-        for (var i = 1; i < response.length; i++) {
-            if (response[i].match(/\w+\tdevice/) && !response[i].match(/emulator/)) {
-                device_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
-            }
-        }
-        return device_list;
-    }
-}
-
-/*
- * Installs a previously built application on the device
- * and launches it.
- */
-module.exports.install = function(target) {
-    var device_list = this.list();
-    if (device_list.length > 0) {
-        // default device
-        target = typeof target !== 'undefined' ? target : device_list[0];
-        if (device_list.indexOf(target) > -1) {
-            var apk_path = build.get_apk();
-            var launchName = appinfo.getActivityName();
-            console.log('Installing app on device...');
-            cmd = 'adb -s ' + target + ' install -r ' + apk_path;
-            var install = shell.exec(cmd, {silent:false, async:false});
-            if (install.error || install.output.match(/Failure/)) {
-                console.error('ERROR : Failed to install apk to device : ');
-                console.error(install.output);
-                process.exit(2);
-            }
-
-            //unlock screen
-            cmd = 'adb -s ' + target + ' shell input keyevent 82';
-            shell.exec(cmd, {silent:true, async:false});
-
-            // launch the application
-            console.log('Launching application...');
-            cmd = 'adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
-            var launch = shell.exec(cmd, {silent:true, async:false});
-            if(launch.code > 0) {
-                console.error('ERROR : Failed to launch application on emulator : ' + launch.error);
-                console.error(launch.output);
-                process.exit(2);
-            } else {
-                console.log('LAUNCH SUCCESS');
-            }
-        } else {
-            console.error('ERROR : Unable to find target \'' + target + '\'.');
-            console.error('Failed to deploy to device.');
-            process.exit(2);
-        }
-    } else {
-        console.error('ERROR : Failed to deploy to device, no devices found.');
-        process.exit(2);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/emulator.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/emulator.js b/e2e/fixtures/platforms/android/cordova/lib/emulator.js
deleted file mode 100755
index cc658a9..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/emulator.js
+++ /dev/null
@@ -1,337 +0,0 @@
-#!/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 shell = require('shelljs'),
-    path  = require('path'),
-    appinfo = require('./appinfo'),
-    build = require('./build'),
-    ROOT  = path.join(__dirname, '..', '..'),
-    new_emulator = 'cordova_emulator';
-
-/**
- * Returns a list of emulator images in the form of objects
- * {
-       name   : <emulator_name>,
-       path   : <path_to_emulator_image>,
-       target : <api_target>,
-       abi    : <cpu>,
-       skin   : <skin>
-   }
- */
-module.exports.list_images = function() {
-    var cmd = 'android list avds';
-    var result = shell.exec(cmd, {silent:true, async:false});
-    if (result.code > 0) {
-        console.error('Failed to execute android command \'' + cmd + '\'.');
-        process.exit(2);
-    } else {
-        var response = result.output.split('\n');
-        var emulator_list = [];
-        for (var i = 1; i < response.length; i++) {
-            // To return more detailed information use img_obj
-            var img_obj = {};
-            if (response[i].match(/Name:\s/)) {
-                img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
-                if (response[i + 1].match(/Path:\s/)) {
-                    i++;
-                    img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
-                }
-                if (response[i + 1].match(/\(API\slevel\s/)) {
-                    i++;
-                    img_obj['target'] = response[i].replace('\r', '');
-                }
-                if (response[i + 1].match(/ABI:\s/)) {
-                    i++;
-                    img_obj['abi'] = response[i].split('ABI: ')[1].replace('\r', '');
-                }
-                if (response[i + 1].match(/Skin:\s/)) {
-                    i++;
-                    img_obj['skin'] = response[i].split('Skin: ')[1].replace('\r', '');
-                }
-
-                emulator_list.push(img_obj);
-            }
-            /* To just return a list of names use this
-            if (response[i].match(/Name:\s/)) {
-                emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
-            }*/
-
-        }
-        return emulator_list;
-    }
-}
-
-/**
- * Will return the closest avd to the projects target
- * or undefined if no avds exist.
- */
-module.exports.best_image = function() {
-    var project_target = this.get_target().replace('android-', '');
-    var images = this.list_images();
-    var closest = 9999;
-    var best = images[0];
-    for (i in images) {
-        var target = images[i].target;
-        if(target) {
-            var num = target.split('(API level ')[1].replace(')', '');
-            if (num == project_target) {
-                return images[i];
-            } else if (project_target - num < closest && project_target > num) {
-                var closest = project_target - num;
-                best = images[i];
-            }
-        }
-    }
-    return best;
-}
-
-module.exports.list_started = function() {
-    var cmd = 'adb devices';
-    var result = shell.exec(cmd, {silent:true, async:false});
-    if (result.code > 0) {
-        console.error('Failed to execute android command \'' + cmd + '\'.');
-        process.exit(2);
-    } else {
-        var response = result.output.split('\n');
-        var started_emulator_list = [];
-        for (var i = 1; i < response.length; i++) {
-            if (response[i].match(/device/) && response[i].match(/emulator/)) {
-                started_emulator_list.push(response[i].replace(/\tdevice/, '').replace('\r', ''));
-            }
-        }
-        return started_emulator_list;
-    }
-}
-
-module.exports.get_target = function() {
-    var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties'));
-    return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
-}
-
-module.exports.list_targets = function() {
-    var target_out = shell.exec('android list targets', {silent:true, async:false}).output.split('\n');
-    var targets = [];
-    for (var i = target_out.length; i >= 0; i--) {
-        if(target_out[i].match(/id:/)) {
-            targets.push(targets[i].split(' ')[1]);
-        }
-    }
-    return targets;
-}
-
-/*
- * Starts an emulator with the given ID,
- * and returns the started ID of that emulator.
- * If no ID is given it will used the first image availible,
- * if no image is availible it will error out (maybe create one?).
- */
-module.exports.start = function(emulator_ID) {
-    var started_emulators = this.list_started();
-    var num_started = started_emulators.length;
-    if (typeof emulator_ID === 'undefined') {
-        var emulator_list = this.list_images();
-        if (emulator_list.length > 0) {
-            emulator_ID = this.best_image().name;
-            console.log('WARNING : no emulator specified, defaulting to ' + emulator_ID);
-        } else {
-            console.error('ERROR : No emulator images (avds) found, if you would like to create an');
-            console.error(' avd follow the instructions provided here : ');
-            console.error(' http://developer.android.com/tools/devices/index.html')
-            console.error(' Or run \'android create avd --name <name> --target <targetID>\' ');
-            console.error(' in on the command line.');
-            process.exit(2);
-            /*console.log('WARNING : no emulators availible, creating \'' + new_emulator + '\'.');
-            this.create_image(new_emulator, this.get_target());
-            emulator_ID = new_emulator;*/
-        }
-    }
-
-    var pipe_null = (process.platform == 'win32' || process.platform == 'win64'? '> NUL' : '> /dev/null');
-    var cmd = 'emulator -avd ' + emulator_ID + ' ' + pipe_null + ' &';
-    if(process.platform == 'win32' || process.platform == 'win64') {
-        cmd = '%comspec% /c start cmd /c ' + cmd;
-    }
-    var result = shell.exec(cmd, {silent:true, async:false}, function(code, output) {
-        if (code > 0) {
-            console.error('Failed to execute android command \'' + cmd + '\'.');
-            console.error(output);
-            process.exit(2);
-        }
-    });
-
-    // wait for emulator to start
-    console.log('Waiting for emulator...');
-    var new_started = this.wait_for_emulator(num_started);
-    var emulator_id;
-    if (new_started.length > 1) {
-        for (i in new_started) {
-            console.log(new_started[i]);
-            console.log(started_emulators.indexOf(new_started[i]));
-            if (started_emulators.indexOf(new_started[i]) < 0) {
-                emulator_id = new_started[i];
-            }
-        }
-    } else {
-        emulator_id = new_started[0];
-    }
-    if (!emulator_id) {
-        console.error('ERROR :  Failed to start emulator, could not find new emulator');
-        process.exit(2);
-    }
-
-    //wait for emulator to boot up
-    process.stdout.write('Booting up emulator (this may take a while)...');
-    this.wait_for_boot(emulator_id);
-    console.log('BOOT COMPLETE');
-
-    //unlock screen
-    cmd = 'adb -s ' + emulator_id + ' shell input keyevent 82';
-    shell.exec(cmd, {silent:false, async:false});
-
-    //return the new emulator id for the started emulators
-    return emulator_id;
-}
-
-/*
- * Waits for the new emulator to apear on the started-emulator list.
- */
-module.exports.wait_for_emulator = function(num_running) {
-    var new_started = this.list_started();
-    if (new_started.length > num_running) {
-        return new_started;
-    } else {
-        this.sleep(1);
-        return this.wait_for_emulator(num_running);
-    }
-}
-
-/*
- * Waits for the boot animation property of the emulator to switch to 'stopped'
- */
-module.exports.wait_for_boot = function(emulator_id) {
-    var cmd;
-    // ShellJS opens a lot of file handles, and the default on OS X is too small.
-    // TODO : This is not working, need to find a better way to increese the ulimit.
-    if(process.platform == 'win32' || process.platform == 'win64') {
-        cmd = 'adb -s ' + emulator_id + ' shell getprop init.svc.bootanim';
-    } else {
-        cmd = 'ulimit -S -n 4096; adb -s ' + emulator_id + ' shell getprop init.svc.bootanim';
-    }
-    var boot_anim = shell.exec(cmd, {silent:true, async:false});
-    if (boot_anim.output.match(/stopped/)) {
-        return;
-    } else {
-        process.stdout.write('.');
-        this.sleep(3);
-        return this.wait_for_boot(emulator_id);
-    }
-}
-
-/*
- * TODO : find a better way to wait for the emulator (maybe using async methods?)
- */
-module.exports.sleep = function(time_sec) {
-    if (process.platform == 'win32' || process.platform == 'win64') {
-        shell.exec('ping 127.0.0.1 -n ' + time_sec, {silent:true, async:false});
-    } else {
-        shell.exec('sleep ' + time_sec, {silent:true, async:false});
-    }
-}
-
-/*
- * Create avd
- * TODO : Enter the stdin input required to complete the creation of an avd.
- */
-module.exports.create_image = function(name, target) {
-    console.log('Creating avd named ' + name);
-    if (target) {
-        var cmd = 'android create avd --name ' + name + ' --target ' + target;
-        var create = shell.exec(cmd, {sient:false, async:false});
-        if (create.error) {
-            console.error('ERROR : Failed to create emulator image : ');
-            console.error(' Do you have the latest android targets including ' + target + '?');
-            console.error(create.output);
-            process.exit(2);
-        }
-    } else {
-        console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
-        var cmd = 'android create avd --name ' + name + ' --target ' + this.list_targets()[0];
-        var create = shell.exec(cmd, {sient:false, async:false});
-        if (create.error) {
-            console.error('ERROR : Failed to create emulator image : ');
-            console.error(create.output);
-            process.exit(2);
-        }
-        console.error('ERROR : Unable to create an avd emulator, no targets found.');
-        console.error('Please insure you have targets availible by runing the "android" command').
-        process.exit(2);
-    }
-}
-
-/*
- * Installs a previously built application on the emulator and launches it.
- * If no target is specified, then it picks one.
- * If no started emulators are found, error out.
- */
-module.exports.install = function(target) {
-    var emulator_list = this.list_started();
-    if (emulator_list.length < 1) {
-        console.error('ERROR : No started emulators found, please start an emultor before deploying your project.');
-        process.exit(2);
-        /*console.log('WARNING : No started emulators found, attemting to start an avd...');
-        this.start(this.best_image().name);*/
-    }
-    // default emulator
-    target = typeof target !== 'undefined' ? target : emulator_list[0];
-    if (emulator_list.indexOf(target) > -1) {
-        console.log('Installing app on emulator...');
-        var apk_path = build.get_apk();
-        var cmd = 'adb -s ' + target + ' install -r ' + apk_path;
-        var install = shell.exec(cmd, {sient:false, async:false});
-        if (install.error || install.output.match(/Failure/)) {
-            console.error('ERROR : Failed to install apk to emulator : ');
-            console.error(install.output);
-            process.exit(2);
-        }
-
-        //unlock screen
-        cmd = 'adb -s ' + target + ' shell input keyevent 82';
-        shell.exec(cmd, {silent:true, async:false});
-
-        // launch the application
-        console.log('Launching application...');
-        var launchName = appinfo.getActivityName();
-        cmd = 'adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launchName;
-        console.log(cmd);
-        var launch = shell.exec(cmd, {silent:false, async:false});
-        if(launch.code > 0) {
-            console.error('ERROR : Failed to launch application on emulator : ' + launch.error);
-            console.error(launch.output);
-            process.exit(2);
-        } else {
-            console.log('LAUNCH SUCCESS');
-        }
-    } else {
-        console.error('ERROR : Unable to find target \'' + target + '\'.');
-        console.error('Failed to deploy to emulator.');
-        process.exit(2);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/install-device
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/install-device b/e2e/fixtures/platforms/android/cordova/lib/install-device
deleted file mode 100755
index 679efbf..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/install-device
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/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 device = require('./device'),
-    args   = process.argv;
-
-if(args.length > 2) {
-    var install_target;
-    if (args[2].substring(0, 9) == '--target=') {
-        install_target = args[2].substring(9, args[2].length);
-        device.install(install_target);
-        process.exit(0);
-     } else {
-        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
-        process.exit(2);
-     }
-} else {
-    device.install();
-    process.exit(0);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/install-emulator
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/install-emulator b/e2e/fixtures/platforms/android/cordova/lib/install-emulator
deleted file mode 100755
index c006eb2..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/install-emulator
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/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;
-
-if(args.length > 2) {
-    var install_target;
-    if (args[2].substring(0, 9) == '--target=') {
-        install_target = args[2].substring(9, args[2].length);
-        emulator.install(install_target);
-        process.exit(0);
-     } else {
-        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
-        process.exit(2);
-     }
-} else {
-    emulator.install();
-    process.exit(0);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/list-devices
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/list-devices b/e2e/fixtures/platforms/android/cordova/lib/list-devices
deleted file mode 100755
index 3ef4efa..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/list-devices
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/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 devices = require('./device');
-
-// Usage support for when args are given
-var device_list = devices.list();
-for(device in device_list) {
-    console.log(device_list[device]);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/list-emulator-images
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/list-emulator-images b/e2e/fixtures/platforms/android/cordova/lib/list-emulator-images
deleted file mode 100755
index 3230537..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/list-emulator-images
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/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 emulators = require('./emulator');
-
-// Usage support for when args are given
-var emulator_list = emulators.list_images();
-for(emulator in emulator_list) {
-    console.log(emulator_list[emulator].name);
-    process.exit(0);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/list-started-emulators
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/list-started-emulators b/e2e/fixtures/platforms/android/cordova/lib/list-started-emulators
deleted file mode 100755
index 525a64c..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/list-started-emulators
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/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 emulators = require('./emulator');
-
-// Usage support for when args are given
-var emulator_list = emulators.list_started();
-for(emulator in emulator_list) {
-    console.log(emulator_list[emulator]);
-    process.exit(0);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/log.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/log.js b/e2e/fixtures/platforms/android/cordova/lib/log.js
deleted file mode 100755
index b85cf60..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/log.js
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/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 shell = require('shelljs'),
-    path  = require('path'),
-    ROOT = path.join(__dirname, '..', '..');
-
-/*
- * Starts running logcat in the shell.
- */
-module.exports.run = function() {
-    var cmd = 'adb logcat | grep -v nativeGetEnabledTags';
-    var result = shell.exec(cmd, {silent:false, async:false});
-    if (result.code > 0) {
-        console.error('ERROR: Failed to run logcat command.');
-        console.error(result.output);
-        process.exit(2);
-    }
-}
-
-module.exports.help = function() {
-    console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'log')));
-    console.log('Gives the logcat output on the command line.');
-    process.exit(0);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/run.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/run.js b/e2e/fixtures/platforms/android/cordova/lib/run.js
deleted file mode 100755
index 787d123..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/run.js
+++ /dev/null
@@ -1,124 +0,0 @@
-#!/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 path  = require('path'),
-    build = require('./build'),
-    emulator = require('./emulator'),
-    device   = require('./device'),
-    ROOT = path.join(__dirname, '..', '..');
-
-/*
- * Runs the application on a device if availible.
- * If not 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.
- */
- module.exports.run = function(args) {
-    var build_type;
-    var install_target;
-
-    for (var i=2; i<args.length; i++) {
-        if (args[i] == '--debug') {
-            build_type = '--debug';
-        } else if (args[i] == '--release') {
-            build_type = '--release';
-        } else if (args[i] == '--nobuild') {
-            build_type = '--nobuild';
-        } else if (args[i] == '--device') {
-            install_target = '--device';
-        } else if (args[i] == '--emulator') {
-            install_target = '--emulator';
-        } else if (args[i].substring(0, 9) == '--target=') {
-            install_target = args[i].substring(9, args[i].length);
-        } else {
-            console.error('ERROR : Run option \'' + args[i] + '\' not recognized.');
-            process.exit(2);
-        }
-    }
-    build.run(build_type);
-    if (install_target == '--device') {
-        device.install();
-    } else if (install_target == '--emulator') {
-        if (emulator.list_started() == 0) {
-            emulator.start();
-        }
-        emulator.install();
-    } else if (install_target) {
-        var devices = device.list();
-        var started_emulators = emulator.list_started();
-        var avds = emulator.list_images();
-        if (devices.indexOf(install_target) > -1) {
-            device.install(install_target);
-        } else if (started_emulators.indexOf(install_target) > -1) {
-            emulator.install(install_target);
-        } else {
-            // if target emulator isn't started, then start it.
-            var emulator_ID;
-            for(avd in avds) {
-                if(avds[avd].name == install_target) {
-                    emulator_ID = emulator.start(install_target);
-                    emulator.install(emulator_ID);
-                    break;
-                }
-            }
-            if(!emulator_ID) {
-                console.error('ERROR : Target \'' + install_target + '\' not found, unalbe to run project');
-                process.exit(2);
-            }
-        }
-    } else {
-        // no target given, deploy to device if availible, otherwise use the emulator.
-        var device_list = device.list();
-        if (device_list.length > 0) {
-            console.log('WARNING : No target specified, deploying to device \'' + device_list[0] + '\'.');
-            device.install(device_list[0])
-        } else {
-            var emulator_list = emulator.list_started();
-            if (emulator_list.length > 0) {
-                console.log('WARNING : No target specified, deploying to emulator \'' + emulator_list[0] + '\'.');
-                emulator.install(emulator_list[0]);
-            } else {
-                console.log('WARNING : No started emulators found, starting an emulator.');
-                var best_avd = emulator.best_image();
-                if(best_avd) {
-                    var emulator_ID = emulator.start(best_avd.name);
-                    console.log('WARNING : No target specified, deploying to emulator \'' + emulator_ID + '\'.');
-                    emulator.install(emulator_ID);
-                } else {
-                    emulator.start();
-                }
-            }
-        }
-    }
-}
-
-module.exports.help = function() {
-    console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'run')) + ' [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-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/lib/start-emulator
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/lib/start-emulator b/e2e/fixtures/platforms/android/cordova/lib/start-emulator
deleted file mode 100755
index 5d6c4dd..0000000
--- a/e2e/fixtures/platforms/android/cordova/lib/start-emulator
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/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;
-
-if(args.length > 2) {
-    var install_target;
-    if (args[2].substring(0, 9) == '--target=') {
-        install_target = args[2].substring(9, args[2].length);
-        emulator.start(install_target);
-        process.exit(0);
-     } else {
-        console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
-        process.exit(2);
-     }
-} else {
-    emulator.start();
-    process.exit(0);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/log
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/log b/e2e/fixtures/platforms/android/cordova/log
deleted file mode 100755
index 087325f..0000000
--- a/e2e/fixtures/platforms/android/cordova/log
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/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 if(reqs.run()) {
-    log.run();
-} else {
-    process.exit(2);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/run
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/run b/e2e/fixtures/platforms/android/cordova/run
deleted file mode 100755
index 57d7345..0000000
--- a/e2e/fixtures/platforms/android/cordova/run
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/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 run  = require('./lib/run'),
-    reqs = require('./lib/check_reqs'),
-    args = process.argv;
-
-// Support basic help commands
-if (args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
-                    args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {
-    run.help();
-} else if(reqs.run()) {
-    run.run(args);
-    process.exit(0);
-} else {
-    process.exit(2);
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/cordova/version
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/cordova/version b/e2e/fixtures/platforms/android/cordova/version
deleted file mode 100755
index de1a76d..0000000
--- a/e2e/fixtures/platforms/android/cordova/version
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/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.
-*/
-
-// Coho updates this line:
-var VERSION = "3.1.0";
-
-console.log(VERSION);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/local.properties
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/local.properties b/e2e/fixtures/platforms/android/local.properties
deleted file mode 100644
index d3f5072..0000000
--- a/e2e/fixtures/platforms/android/local.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must *NOT* be checked into Version Control Systems,
-# as it contains information specific to your local configuration.
-
-# location of the SDK. This is only used by Ant
-# For customization when using a Version Control System, please read the
-# header note.
-sdk.dir=/Users/braden/cordova/android/android-sdk-macosx

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/proguard-project.txt
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/proguard-project.txt b/e2e/fixtures/platforms/android/proguard-project.txt
deleted file mode 100644
index f2fe155..0000000
--- a/e2e/fixtures/platforms/android/proguard-project.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# For more details, see
-#   http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-#   public *;
-#}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/project.properties
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/project.properties b/e2e/fixtures/platforms/android/project.properties
deleted file mode 100644
index a3ee5ab..0000000
--- a/e2e/fixtures/platforms/android/project.properties
+++ /dev/null
@@ -1,14 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-target=android-17

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/res/drawable-hdpi/icon.png
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/res/drawable-hdpi/icon.png b/e2e/fixtures/platforms/android/res/drawable-hdpi/icon.png
deleted file mode 100644
index 4d27634..0000000
Binary files a/e2e/fixtures/platforms/android/res/drawable-hdpi/icon.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/res/drawable-ldpi/icon.png
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/res/drawable-ldpi/icon.png b/e2e/fixtures/platforms/android/res/drawable-ldpi/icon.png
deleted file mode 100644
index cd5032a..0000000
Binary files a/e2e/fixtures/platforms/android/res/drawable-ldpi/icon.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/res/drawable-mdpi/icon.png
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/res/drawable-mdpi/icon.png b/e2e/fixtures/platforms/android/res/drawable-mdpi/icon.png
deleted file mode 100644
index e79c606..0000000
Binary files a/e2e/fixtures/platforms/android/res/drawable-mdpi/icon.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/res/drawable-xhdpi/icon.png
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/res/drawable-xhdpi/icon.png b/e2e/fixtures/platforms/android/res/drawable-xhdpi/icon.png
deleted file mode 100644
index ec7ffbf..0000000
Binary files a/e2e/fixtures/platforms/android/res/drawable-xhdpi/icon.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/res/drawable/icon.png
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/res/drawable/icon.png b/e2e/fixtures/platforms/android/res/drawable/icon.png
deleted file mode 100644
index ec7ffbf..0000000
Binary files a/e2e/fixtures/platforms/android/res/drawable/icon.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/res/values/strings.xml
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/res/values/strings.xml b/e2e/fixtures/platforms/android/res/values/strings.xml
deleted file mode 100644
index 1e706b3..0000000
--- a/e2e/fixtures/platforms/android/res/values/strings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<resources>
-    <string name="app_name">TestBase</string>
-</resources>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/res/xml/config.xml
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/res/xml/config.xml b/e2e/fixtures/platforms/android/res/xml/config.xml
deleted file mode 100644
index 17ca237..0000000
--- a/e2e/fixtures/platforms/android/res/xml/config.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<widget id="org.testing" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
-    <name>Hello Cordova</name>
-    <description>
-        A sample Apache Cordova application that responds to the deviceready event.
-    </description>
-    <access origin="*" />
-    <preference name="loglevel" value="DEBUG" />
-    <feature name="App">
-        <param name="android-package" value="org.apache.cordova.App" />
-    </feature>
-    <author email="dev@cordova.apache.org" href="http://cordova.io">
-        Apache Cordova Team
-    </author>
-    <content src="index.html" />
-    <preference name="fullscreen" value="true" />
-    <preference name="webviewbounce" value="true" />
-</widget>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/src/org/testing/TestBase.java
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/src/org/testing/TestBase.java b/e2e/fixtures/platforms/android/src/org/testing/TestBase.java
deleted file mode 100644
index 928e074..0000000
--- a/e2e/fixtures/platforms/android/src/org/testing/TestBase.java
+++ /dev/null
@@ -1,37 +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.
- */
-
-package org.testing;
-
-import android.os.Bundle;
-import org.apache.cordova.*;
-
-public class TestBase extends CordovaActivity 
-{
-    @Override
-    public void onCreate(Bundle savedInstanceState)
-    {
-        super.onCreate(savedInstanceState);
-        super.init();
-        // Set by <content src="index.html" /> in config.xml
-        super.loadUrl(Config.getStartUrl());
-        //super.loadUrl("file:///android_asset/www/index.html")
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/plugins/fake1/plugin.xml
----------------------------------------------------------------------
diff --git a/e2e/fixtures/plugins/fake1/plugin.xml b/e2e/fixtures/plugins/fake1/plugin.xml
deleted file mode 100644
index ffdc650..0000000
--- a/e2e/fixtures/plugins/fake1/plugin.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
-           id="org.apache.cordova.fakeplugin1"
-      version="0.1.0-dev">
-    <name>Fake1</name>
-    <description>Cordova fake plugin for tests</description>
-    <license>Apache 2.0</license>
-    <keywords>cordova,cli,test</keywords>
-</plugin>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/helpers.js
----------------------------------------------------------------------
diff --git a/e2e/helpers.js b/e2e/helpers.js
deleted file mode 100644
index 3236516..0000000
--- a/e2e/helpers.js
+++ /dev/null
@@ -1,46 +0,0 @@
-
-var path = require('path'),
-    fs = require('fs'),
-    shell = require('shelljs'),
-    os = require('os');
-
-module.exports.tmpDir = function(subdir) {
-    var dir = path.join(os.tmpdir(), 'e2e-test');
-    if (subdir) {
-        dir = path.join(dir, subdir);
-    }
-    shell.mkdir('-p', dir);
-    return dir;
-};
-
-// Returns the platform that should be used for testing on this host platform.
-/*
-var host = os.platform();
-if (host.match(/win/)) {
-    module.exports.testPlatform = 'wp8';
-} else if (host.match(/darwin/)) {
-    module.exports.testPlatform = 'ios';
-} else {
-    module.exports.testPlatform = 'android';
-}
-*/
-
-// Just use Android everywhere; we're mocking out any calls to the `android` binary.
-module.exports.testPlatform = 'android';
-
-// Add the toExist matcher.
-beforeEach(function() {
-    this.addMatchers({
-        'toExist': function() {
-            var notText = this.isNot ? ' not' : '';
-            var self = this;
-
-            this.message = function() {
-                return 'Expected file ' + self.actual + notText + ' to exist.';
-            };
-
-            return fs.existsSync(this.actual);
-        }
-    });
-});
-

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/hooker.spec.js
----------------------------------------------------------------------
diff --git a/e2e/hooker.spec.js b/e2e/hooker.spec.js
deleted file mode 100644
index c85cc59..0000000
--- a/e2e/hooker.spec.js
+++ /dev/null
@@ -1,261 +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 cordova = require('../cordova'),
-    hooker = require('../src/hooker'),
-    shell  = require('shelljs'),
-    path   = require('path'),
-    fs     = require('fs'),
-    os     = require('os'),
-    Q      = require('q'),
-    child_process = require('child_process'),
-    helpers = require('./helpers');
-
-var platform = os.platform();
-var tmpDir = helpers.tmpDir('hooks_test');
-var project = path.join(tmpDir, 'project');
-var dotCordova = path.join(project, '.cordova');
-var hooksDir = path.join(project, '.cordova', 'hooks');
-var ext = platform.match(/(win32|win64)/)?'bat':'sh';
-
-
-// copy fixture
-shell.rm('-rf', project);
-shell.mkdir('-p', project);
-shell.cp('-R', path.join(__dirname, 'fixtures', 'base', '*'), project);
-shell.mkdir('-p', dotCordova);
-shell.cp('-R', path.join(__dirname, 'fixtures', 'hooks_' + ext), dotCordova);
-shell.mv(path.join(dotCordova, 'hooks_' + ext), hooksDir);
-shell.chmod('-R', 'ug+x', hooksDir);
-
-
-describe('hooker', function() {
-    it('should throw if provided directory is not a cordova project', function() {
-        expect(function() {
-            new hooker(tmpDir);
-        }).toThrow();
-    });
-});
-
-describe('global (static) fire method', function() {
-    it('should execute listeners serially', function(done) {
-        var test_event = 'foo';
-        var h1_fired = false;
-        var h1 = function() {
-            expect(h2_fired).toBe(false);
-            // Delay 100 ms here to check that h2 is not executed until after
-            // the promise returned by h1 is resolved.
-            var q = Q.delay(100).then(function() {
-                h1_fired = true;
-            });
-            return q;
-        };
-        var h2_fired = false;
-        var h2 = function() {
-            h2_fired = true;
-            expect(h1_fired).toBe(true);
-            return Q();
-        };
-
-        cordova.on(test_event, h1);
-        cordova.on(test_event, h2);
-        hooker.fire(test_event).then(function() {
-            expect(h1_fired).toBe(true);
-            expect(h2_fired).toBe(true);
-            done();
-        });
-    });
-});
-
-describe('module-level hooks', function() {
-    var handler = jasmine.createSpy().andReturn(Q());
-    var test_event = 'before_build';
-    var h;
-
-    beforeEach(function() {
-        h = new hooker(project);
-    });
-
-    afterEach(function() {
-        cordova.removeAllListeners(test_event);
-        handler.reset();
-    });
-
-    it('should fire handlers using cordova.on', function(done) {
-        cordova.on(test_event, handler);
-        h.fire(test_event)
-        .then(function() {
-            expect(handler).toHaveBeenCalled();
-        })
-        .fail(function(err) {
-            expect(err).not.toBeDefined();
-        })
-        .fin(done);
-    });
-
-    it('should pass the project root folder as parameter into the module-level handlers', function(done) {
-        cordova.on(test_event, handler);
-        h.fire(test_event)
-        .then(function() {
-            expect(handler).toHaveBeenCalledWith({root:project});
-        })
-        .fail(function(err) {
-            console.log(err);
-            expect(err).not.toBeDefined();
-        })
-        .fin(done);
-    });
-
-    it('should be able to stop listening to events using cordova.off', function(done) {
-        cordova.on(test_event, handler);
-        cordova.off(test_event, handler);
-        h.fire(test_event)
-        .then(function() {
-            expect(handler).not.toHaveBeenCalled();
-        })
-        .fail(function(err) {
-            console.log(err);
-            expect(err).toBeUndefined();
-        })
-        .fin(done);
-    });
-
-    it('should allow for hook to opt into asynchronous execution and block further hooks from firing using the done callback', function(done) {
-        var h1_fired = false;
-        var h1 = function() {
-            h1_fired = true;
-            expect(h2_fired).toBe(false);
-            return Q();
-        };
-        var h2_fired = false;
-        var h2 = function() {
-            h2_fired = true;
-            expect(h1_fired).toBe(true);
-            return Q();
-        };
-
-        cordova.on(test_event, h1);
-        cordova.on(test_event, h2);
-        h.fire(test_event).then(function() {
-            expect(h1_fired).toBe(true);
-            expect(h2_fired).toBe(true);
-            done();
-        });
-    });
-
-    it('should pass data object that fire calls into async handlers', function(done) {
-        var data = {
-            "hi":"ho",
-            "offtowork":"wego"
-        };
-        var async = function(opts) {
-            data.root = tmpDir;
-            expect(opts).toEqual(data);
-            return Q();
-        };
-        cordova.on(test_event, async);
-        h.fire(test_event, data).then(done);
-    });
-
-    it('should pass data object that fire calls into sync handlers', function(done) {
-        var data = {
-            "hi":"ho",
-            "offtowork":"wego"
-        };
-        var async = function(opts) {
-            data.root = tmpDir;
-            expect(opts).toEqual(data);
-        };
-        cordova.on(test_event, async);
-        h.fire(test_event, data).then(done);
-    });
-});
-
-
-describe('hooks', function() {
-    var h;
-    beforeEach(function() {
-        h = new hooker(project);
-    });
-
-
-    it('should not error if the hook is unrecognized', function(done) {
-        h.fire('CLEAN YOUR SHORTS GODDAMNIT LIKE A BIG BOY!')
-        .fail(function (err) {
-            expect('Call with unrecogized hook ').toBe('successful.\n' + err);
-        })
-        .fin(done);
-    });
-
-    it('should error if any script exits with non-zero code', function(done) {
-        h.fire('fail').then(function() {
-            expect('the call').toBe('a failure');
-        }, function(err) {
-            expect(err).toBeDefined();
-        })
-        .fin(done);
-    });
-
-    it('should execute all scripts in order', function(done) {
-        h.fire('test')
-        .then(function() {
-            var hooksOrderFile = path.join(project, 'hooks_order.txt');
-            var hooksEnvFile = path.join(project, 'hooks_env.json');
-            var hooksParamsFile = path.join(project, 'hooks_params.txt');
-            expect(hooksOrderFile).toExist();
-            expect(hooksEnvFile).toExist();
-            expect(hooksParamsFile).toExist();
-            expect(path.join(project, 'dotted_hook_should_not_fire.txt')).not.toExist();
-
-            var order = fs.readFileSync(hooksOrderFile, 'ascii').replace(/\W/gm, '');
-            expect(order).toBe('ab');
-
-            var params = fs.readFileSync(hooksParamsFile, 'ascii').trim().trim('"');
-            expect(params).toMatch(project.replace(/\\/g, '\\\\'));
-
-            var env = JSON.parse(fs.readFileSync(hooksEnvFile, 'ascii'));
-            expect(env.CORDOVA_VERSION).toEqual(require('../package').version);
-        })
-        .fail(function(err) {
-            console.log(err);
-            expect('Test hook call').toBe('successful');
-        })
-        .fin(done);
-
-    });
-
-    // Cleanup. Must be the last spec. Is there a better place for final cleanup in Jasmine?
-    it('should not fail during cleanup', function() {
-        process.chdir(path.join(__dirname, '..'));  // Non e2e tests assume CWD is repo root.
-        if(ext == 'sh') {
-            //shell.rm('-rf', tmpDir);
-        } else { // Windows:
-            // For some mysterious reason, both shell.rm and RMDIR /S /Q won't
-            // delete the dir on Windows, but they do remove the files leaving
-            // only folders. But the dir is removed just fine by
-            // shell.rm('-rf', tmpDir) at the top of this file with the next
-            // invocation of this test. The benefit of RMDIR /S /Q is that it
-            // doesn't print warnings like shell.rmdir() that look like this:
-            // rm: could not remove directory (code ENOTEMPTY): C:\Users\...
-            var cmd =  'RMDIR /S /Q ' + tmpDir;
-            child_process.exec(cmd);
-        }
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/platform.spec.js
----------------------------------------------------------------------
diff --git a/e2e/platform.spec.js b/e2e/platform.spec.js
deleted file mode 100644
index e16d51d..0000000
--- a/e2e/platform.spec.js
+++ /dev/null
@@ -1,108 +0,0 @@
-
-var helpers = require('./helpers'),
-    path = require('path'),
-    fs = require('fs'),
-    shell = require('shelljs'),
-    platforms = require('../platforms'),
-    superspawn = require('../src/superspawn'),
-    config = require('../src/config'),
-    Q = require('q'),
-    events = require('../src/events'),
-    cordova = require('../cordova');
-
-var tmpDir = helpers.tmpDir('platform_test');
-var project = path.join(tmpDir, 'project');
-
-var platformParser = platforms[helpers.testPlatform].parser;
-
-describe('platform end-to-end', function() {
-    var results;
-
-    beforeEach(function() {
-        shell.rm('-rf', tmpDir);
-    });
-    afterEach(function() {
-        process.chdir(path.join(__dirname, '..'));  // Needed to rm the dir on Windows.
-        shell.rm('-rf', tmpDir);
-    });
-
-    // Factoring out some repeated checks.
-    function emptyPlatformList() {
-        return cordova.raw.platform('list').then(function() {
-            var installed = results.match(/Installed platforms: (.*)/);
-            expect(installed).toBeDefined();
-            expect(installed[1].indexOf(helpers.testPlatform)).toBe(-1);
-        });
-    }
-
-    function fullPlatformList() {
-        return cordova.raw.platform('list').then(function() {
-            var installed = results.match(/Installed platforms: (.*)/);
-            expect(installed).toBeDefined();
-            expect(installed[1].indexOf(helpers.testPlatform)).toBeGreaterThan(-1);
-        });
-    }
-
-    // The flows we want to test are add, rm, list, and upgrade.
-    // They should run the appropriate hooks.
-    // They should fail when not inside a Cordova project.
-    // These tests deliberately have no beforeEach and afterEach that are cleaning things up.
-    it('should successfully run', function(done) {
-        // cp then mv because we need to copy everything, but that means it'll copy the whole directory.
-        // Using /* doesn't work because of hidden files.
-        shell.cp('-R', path.join(__dirname, 'fixtures', 'base'), tmpDir);
-        shell.mv(path.join(tmpDir, 'base'), project);
-        process.chdir(project);
-
-        // Now we load the config.json in the newly created project and edit the target platform's lib entry
-        // to point at the fixture version. This is necessary so that cordova.prepare can find cordova.js there.
-        var c = config.read(project);
-        c.lib[helpers.testPlatform].uri = path.join(__dirname, 'fixtures', 'platforms', helpers.testPlatform + '-lib');
-        config.write(project, c);
-
-        // The config.json in the fixture project points at fake "local" paths.
-        // Since it's not a URL, the lazy-loader will just return the junk path.
-        spyOn(superspawn, 'spawn').andCallFake(function(cmd, args) {
-            if (cmd.match(/create\b/)) {
-                // This is a call to the bin/create script, so do the copy ourselves.
-                shell.cp('-R', path.join(__dirname, 'fixtures', 'platforms', 'android'), path.join(project, 'platforms'));
-            } else if(cmd.match(/version\b/)) {
-                return Q('3.3.0');
-            } else if(cmd.match(/update\b/)) {
-                fs.writeFileSync(path.join(project, 'platforms', helpers.testPlatform, 'updated'), 'I was updated!', 'utf-8');
-            }
-            return Q();
-        });
-
-        events.on('results', function(res) { results = res; });
-
-        // Check there are no platforms yet.
-        emptyPlatformList().then(function() {
-            // Add the testing platform.
-            return cordova.raw.platform('add', [helpers.testPlatform]);
-        }).then(function() {
-            // Check the platform add was successful.
-            expect(path.join(project, 'platforms', helpers.testPlatform)).toExist();
-            expect(path.join(project, 'merges', helpers.testPlatform)).toExist();
-            expect(path.join(project, 'platforms', helpers.testPlatform, 'cordova')).toExist();
-        }).then(fullPlatformList) // Check for it in platform ls.
-        .then(function() {
-            // Try to update the platform.
-            return cordova.raw.platform('update', [helpers.testPlatform]);
-        }).then(function() {
-            // Our fake update script in the exec mock above creates this dummy file.
-            expect(path.join(project, 'platforms', helpers.testPlatform, 'updated')).toExist();
-        }).then(fullPlatformList) // Platform should still be in platform ls.
-        .then(function() {
-            // And now remove it.
-            return cordova.raw.platform('rm', [helpers.testPlatform]);
-        }).then(function() {
-            // It should be gone.
-            expect(path.join(project, 'platforms', helpers.testPlatform)).not.toExist();
-        }).then(emptyPlatformList) // platform ls should be empty too.
-        .fail(function(err) {
-            expect(err).toBeUndefined();
-        }).fin(done);
-    });
-});
-

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/plugin.spec.js
----------------------------------------------------------------------
diff --git a/e2e/plugin.spec.js b/e2e/plugin.spec.js
deleted file mode 100644
index 2ad7b08..0000000
--- a/e2e/plugin.spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-
-var helpers = require('./helpers'),
-    path = require('path'),
-    fs = require('fs'),
-    shell = require('shelljs'),
-    Q = require('q'),
-    events = require('../src/events'),
-    cordova = require('../cordova');
-
-var tmpDir = helpers.tmpDir('plugin_test');
-var project = path.join(tmpDir, 'project');
-var pluginsDir = path.join(__dirname, 'fixtures', 'plugins');
-var pluginId = 'org.apache.cordova.fakeplugin1';
-
-describe('plugin end-to-end', function() {
-    var results;
-
-    beforeEach(function() {
-        shell.rm('-rf', project);
-    });
-    afterEach(function() {
-        process.chdir(path.join(__dirname, '..'));  // Needed to rm the dir on Windows.
-        shell.rm('-rf', tmpDir);
-    });
-
-    // The flow tested is: ls, add, ls, rm, ls.
-    // Plugin dependencies are not tested as that should be corvered in plugman tests.
-    // TODO (kamrik): Test the 'plugin search' command.
-    it('should successfully run', function(done) {
-        // cp then mv because we need to copy everything, but that means it'll copy the whole directory.
-        // Using /* doesn't work because of hidden files.
-        shell.cp('-R', path.join(__dirname, 'fixtures', 'base'), tmpDir);
-        shell.mv(path.join(tmpDir, 'base'), project);
-        // Copy some platform to avoid working on a project with no platforms.
-        shell.cp('-R', path.join(__dirname, 'fixtures', 'platforms', helpers.testPlatform), path.join(project, 'platforms'));
-        process.chdir(project);
-
-        events.on('results', function(res) { results = res; });
-
-        // Check there are no plugins yet.
-        cordova.raw.plugin('list').then(function() {
-            expect(results).toMatch(/No plugins added/gi);
-        }).then(function() {
-            // Add a fake plugin from fixtures.
-            return cordova.raw.plugin('add', path.join(pluginsDir, 'fake1'));
-        }).then(function() {
-           expect(path.join(project, 'plugins', pluginId, 'plugin.xml')).toExist();
-        }).then(function() {
-            return cordova.raw.plugin('ls');
-        }).then(function() {
-            expect(results).toContain(pluginId);
-            expect(results.length).toEqual(1);
-        }).then(function() {
-            // And now remove it.
-            return cordova.raw.plugin('rm', pluginId);
-        }).then(function() {
-            // The whole dir should be gone.
-            expect(path.join(project, 'plugins', pluginId)).not.toExist();
-        }).then(function() {
-            return cordova.raw.plugin('ls');
-        }).then(function() {
-            expect(results).toMatch(/No plugins added/gi);
-        }).fail(function(err) {
-            console.log(err);
-            expect(err).toBeUndefined();
-        }).fin(done);
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/create.spec.js
----------------------------------------------------------------------
diff --git a/spec/create.spec.js b/spec/create.spec.js
new file mode 100644
index 0000000..ebdfab5
--- /dev/null
+++ b/spec/create.spec.js
@@ -0,0 +1,138 @@
+/**
+    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 helpers = require('./helpers'),
+    path = require('path'),
+    fs = require('fs'),
+    shell = require('shelljs'),
+    Q = require('q'),
+    config = require('../src/config'),
+    events = require('../src/events'),
+    util = require('../src/util'),
+    ConfigParser = require('../src/ConfigParser'),
+    cordova = require('../cordova');
+
+// A utility function to generate all combinations of elements from 2 arrays.
+// crossConcat(['x', 'y'], ['1', '2', '3'])
+// -> [ 'x1', 'x2', 'x3', 'y1', 'y2', 'y3']
+var crossConcat = function(a, b, delimiter){
+    var result = [];
+    delimiter = delimiter || '';
+    for (var i = 0; i < a.length; i++) {
+        for (var j = 0; j < b.length; j++) {
+            result.push(a[i] + delimiter + b[j]);
+        }
+    }
+    return result;
+};
+
+var tmpDir = helpers.tmpDir('create_test');
+var appName = 'TestBase';
+var appId = 'org.testing';
+var project = path.join(tmpDir, appName);
+var cordovaDir = path.join(project, '.cordova');
+var configNormal = {
+      lib: {
+        www: {
+          uri: path.join(__dirname, 'fixtures', 'base', 'www'),
+          version: "testCordovaCreate",
+          id: appName
+        }
+      }
+    };
+var configSymlink = {
+      lib: {
+        www: {
+          uri: path.join(__dirname, 'fixtures', 'base'), // "create" should copy or link the www child of this dir and not the dir itself.
+          link: true
+        }
+      }
+    };
+
+
+describe('create end-to-end', function() {
+
+    beforeEach(function() {
+        shell.rm('-rf', project);
+    });
+    afterEach(function() {
+        process.chdir(path.join(__dirname, '..'));  // Needed to rm the dir on Windows.
+        shell.rm('-rf', tmpDir);
+    });
+
+    function checkProject() {
+        // Check if top level dirs exist.
+        var dirs = ['hooks', 'platforms', 'merges', 'plugins', 'www'];
+        dirs.forEach(function(d) {
+            expect(path.join(project, d)).toExist();
+        });
+
+        expect(path.join(project, 'hooks', 'README.md')).toExist();
+
+        // Check if config files exist.
+        expect(path.join(project, 'www', 'index.html')).toExist();
+
+        // Check that www/config.xml was updated.
+        var configXml = new ConfigParser(path.join(project, 'www', 'config.xml'));
+        expect(configXml.packageName()).toEqual(appId);
+
+        // TODO (kamrik): check somehow that we got the right config.xml from the fixture and not some place else.
+        // expect(configXml.name()).toEqual('TestBase');
+    }
+
+    var results;
+    events.on('results', function(res) { results = res; });
+
+    it('should successfully run with regular config', function(done) {
+        // Call cordova create with no args, should return help.
+        cordova.raw.create()
+        .then(function() {
+            expect(results).toMatch(/synopsis/gi);
+        })
+        .then(function() {
+            // Create a real project
+            return cordova.raw.create(project, appId, appName, configNormal);
+        })
+        .then(checkProject)
+        .fail(function(err) {
+            console.log(err);
+            expect(err).toBeUndefined();
+        })
+        .fin(done);
+    });
+
+    it('should successfully run with symlinked www', function(done) {
+        // Call cordova create with no args, should return help.
+        cordova.raw.create(project, appId, appName, configSymlink)
+        .then(checkProject)
+        .then(function() {
+            // Check that www is really a symlink
+            expect(fs.lstatSync(path.join(project, 'www')).isSymbolicLink()).toBe(true);
+        })
+        .fail(function(err) {
+            if(process.platform.slice(0, 3) == 'win') {
+                // Allow symlink error if not in admin mode
+                expect(err.message).toBe("Symlinks on Windows require Administrator privileges");
+            } else {
+                expect(err).toBeUndefined();
+            }
+        })
+        .fin(done);
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/base/.cordova/config.json
----------------------------------------------------------------------
diff --git a/spec/fixtures/base/.cordova/config.json b/spec/fixtures/base/.cordova/config.json
new file mode 100644
index 0000000..662fc9d
--- /dev/null
+++ b/spec/fixtures/base/.cordova/config.json
@@ -0,0 +1,22 @@
+{
+  "id": "org.testing",
+  "name":"TestBase",
+  "lib": {
+    "android": {
+      "uri": "/some/junk/path",
+      "version": "dev",
+      "id": "cordova-android-dev"
+    },
+    "ios": {
+      "uri": "/some/junk/path",
+      "version": "dev",
+      "id": "cordova-ios-dev"
+    },
+    "wp8": {
+      "uri": "/some/junk/path",
+      "version": "dev",
+      "id": "cordova-wp8-dev"
+    }
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/base/merges/.svn
----------------------------------------------------------------------
diff --git a/spec/fixtures/base/merges/.svn b/spec/fixtures/base/merges/.svn
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/base/platforms/.svn
----------------------------------------------------------------------
diff --git a/spec/fixtures/base/platforms/.svn b/spec/fixtures/base/platforms/.svn
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/base/plugins/.svn
----------------------------------------------------------------------
diff --git a/spec/fixtures/base/plugins/.svn b/spec/fixtures/base/plugins/.svn
new file mode 100644
index 0000000..e69de29

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/base/www/config.xml
----------------------------------------------------------------------
diff --git a/spec/fixtures/base/www/config.xml b/spec/fixtures/base/www/config.xml
new file mode 100644
index 0000000..9e7b9e0
--- /dev/null
+++ b/spec/fixtures/base/www/config.xml
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="org.testing" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>TestBase</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+    <preference name="fullscreen" value="true" />
+    <preference name="webviewbounce" value="true" />
+</widget>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/base/www/css/index.css
----------------------------------------------------------------------
diff --git a/spec/fixtures/base/www/css/index.css b/spec/fixtures/base/www/css/index.css
new file mode 100644
index 0000000..51daa79
--- /dev/null
+++ b/spec/fixtures/base/www/css/index.css
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+* {
+    -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
+}
+
+body {
+    -webkit-touch-callout: none;                /* prevent callout to copy image, etc when tap to hold */
+    -webkit-text-size-adjust: none;             /* prevent webkit from resizing text to fit */
+    -webkit-user-select: none;                  /* prevent copy paste, to allow, change 'none' to 'text' */
+    background-color:#E4E4E4;
+    background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+    background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+    background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+    background-image:-webkit-gradient(
+        linear,
+        left top,
+        left bottom,
+        color-stop(0, #A7A7A7),
+        color-stop(0.51, #E4E4E4)
+    );
+    background-attachment:fixed;
+    font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
+    font-size:12px;
+    height:100%;
+    margin:0px;
+    padding:0px;
+    text-transform:uppercase;
+    width:100%;
+}
+
+/* Portrait layout (default) */
+.app {
+    background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
+    position:absolute;             /* position in the center of the screen */
+    left:50%;
+    top:50%;
+    height:50px;                   /* text area height */
+    width:225px;                   /* text area width */
+    text-align:center;
+    padding:180px 0px 0px 0px;     /* image height is 200px (bottom 20px are overlapped with text) */
+    margin:-115px 0px 0px -112px;  /* offset vertical: half of image height and text area height */
+                                   /* offset horizontal: half of text area width */
+}
+
+/* Landscape layout (with min-width) */
+@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
+    .app {
+        background-position:left center;
+        padding:75px 0px 75px 170px;  /* padding-top + padding-bottom + text area = image height */
+        margin:-90px 0px 0px -198px;  /* offset vertical: half of image height */
+                                      /* offset horizontal: half of image width and text area width */
+    }
+}
+
+h1 {
+    font-size:24px;
+    font-weight:normal;
+    margin:0px;
+    overflow:visible;
+    padding:0px;
+    text-align:center;
+}
+
+.event {
+    border-radius:4px;
+    -webkit-border-radius:4px;
+    color:#FFFFFF;
+    font-size:12px;
+    margin:0px 30px;
+    padding:2px 0px;
+}
+
+.event.listening {
+    background-color:#333333;
+    display:block;
+}
+
+.event.received {
+    background-color:#4B946A;
+    display:none;
+}
+
+@keyframes fade {
+    from { opacity: 1.0; }
+    50% { opacity: 0.4; }
+    to { opacity: 1.0; }
+}
+ 
+@-webkit-keyframes fade {
+    from { opacity: 1.0; }
+    50% { opacity: 0.4; }
+    to { opacity: 1.0; }
+}
+ 
+.blink {
+    animation:fade 3000ms infinite;
+    -webkit-animation:fade 3000ms infinite;
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/base/www/img/logo.png
----------------------------------------------------------------------
diff --git a/spec/fixtures/base/www/img/logo.png b/spec/fixtures/base/www/img/logo.png
new file mode 100644
index 0000000..9519e7d
Binary files /dev/null and b/spec/fixtures/base/www/img/logo.png differ


[6/8] git commit: CB-6421: Move tests from e2e to spec

Posted by ka...@apache.org.
CB-6421: Move tests from e2e to spec

Part 2, move all the files and delete e2e dir.
For history of old overwritten tests in spec try
git log 5cf9d9064005ff7bc6205c05277169b929e52fb5


Project: http://git-wip-us.apache.org/repos/asf/cordova-cli/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-cli/commit/f4a9597a
Tree: http://git-wip-us.apache.org/repos/asf/cordova-cli/tree/f4a9597a
Diff: http://git-wip-us.apache.org/repos/asf/cordova-cli/diff/f4a9597a

Branch: refs/heads/master
Commit: f4a9597a8a4394ca6e943c285e1ad8eab5a31fd7
Parents: fde755f
Author: Mark Koudritsky <ka...@gmail.com>
Authored: Tue Apr 8 18:27:54 2014 -0400
Committer: Mark Koudritsky <ka...@gmail.com>
Committed: Mon Apr 14 20:25:10 2014 -0400

----------------------------------------------------------------------
 e2e/create.spec.js                              |  138 --
 e2e/fixtures/base/.cordova/config.json          |   22 -
 e2e/fixtures/base/merges/.svn                   |    0
 e2e/fixtures/base/platforms/.svn                |    0
 e2e/fixtures/base/plugins/.svn                  |    0
 e2e/fixtures/base/www/config.xml                |   14 -
 e2e/fixtures/base/www/css/index.css             |  115 --
 e2e/fixtures/base/www/img/logo.png              |  Bin 21814 -> 0 bytes
 e2e/fixtures/base/www/index.html                |   43 -
 e2e/fixtures/base/www/js/index.js               |   49 -
 e2e/fixtures/base/www/spec.html                 |   68 -
 e2e/fixtures/hooks_bat/fail/fail.bat            |    2 -
 e2e/fixtures/hooks_bat/test/.dotted.bat         |    2 -
 e2e/fixtures/hooks_bat/test/07.bat              |    3 -
 e2e/fixtures/hooks_bat/test/1.bat               |    5 -
 e2e/fixtures/hooks_sh/fail/fail.sh              |    1 -
 e2e/fixtures/hooks_sh/test/.dotted.sh           |    1 -
 e2e/fixtures/hooks_sh/test/07.sh                |    2 -
 e2e/fixtures/hooks_sh/test/1.sh                 |    4 -
 e2e/fixtures/platforms/android-lib/VERSION      |    1 -
 .../android-lib/framework/assets/www/cordova.js |    1 -
 .../platforms/android/AndroidManifest.xml       |   14 -
 .../platforms/android/assets/www/config.xml     |   14 -
 .../platforms/android/assets/www/cordova.js     | 1712 ------------------
 .../android/assets/www/cordova_plugins.js       |    3 -
 .../platforms/android/assets/www/css/index.css  |  115 --
 .../platforms/android/assets/www/img/logo.png   |  Bin 21814 -> 0 bytes
 .../platforms/android/assets/www/index.html     |   43 -
 .../platforms/android/assets/www/js/index.js    |   49 -
 .../platforms/android/assets/www/spec.html      |   68 -
 e2e/fixtures/platforms/android/build.xml        |   92 -
 e2e/fixtures/platforms/android/cordova/build    |   35 -
 .../platforms/android/cordova/check_reqs        |   27 -
 e2e/fixtures/platforms/android/cordova/clean    |   34 -
 .../platforms/android/cordova/defaults.xml      |   50 -
 .../platforms/android/cordova/lib/appinfo.js    |   41 -
 .../platforms/android/cordova/lib/build.js      |   89 -
 .../platforms/android/cordova/lib/check_reqs.js |   78 -
 .../platforms/android/cordova/lib/clean.js      |   43 -
 .../platforms/android/cordova/lib/device.js     |   95 -
 .../platforms/android/cordova/lib/emulator.js   |  337 ----
 .../android/cordova/lib/install-device          |   38 -
 .../android/cordova/lib/install-emulator        |   38 -
 .../platforms/android/cordova/lib/list-devices  |   28 -
 .../android/cordova/lib/list-emulator-images    |   29 -
 .../android/cordova/lib/list-started-emulators  |   29 -
 .../platforms/android/cordova/lib/log.js        |   43 -
 .../platforms/android/cordova/lib/run.js        |  124 --
 .../android/cordova/lib/start-emulator          |   38 -
 e2e/fixtures/platforms/android/cordova/log      |   33 -
 e2e/fixtures/platforms/android/cordova/run      |   35 -
 e2e/fixtures/platforms/android/cordova/version  |   25 -
 e2e/fixtures/platforms/android/local.properties |   10 -
 .../platforms/android/proguard-project.txt      |   20 -
 .../platforms/android/project.properties        |   14 -
 .../android/res/drawable-hdpi/icon.png          |  Bin 6080 -> 0 bytes
 .../android/res/drawable-ldpi/icon.png          |  Bin 3096 -> 0 bytes
 .../android/res/drawable-mdpi/icon.png          |  Bin 4090 -> 0 bytes
 .../android/res/drawable-xhdpi/icon.png         |  Bin 7685 -> 0 bytes
 .../platforms/android/res/drawable/icon.png     |  Bin 7685 -> 0 bytes
 .../platforms/android/res/values/strings.xml    |    4 -
 .../platforms/android/res/xml/config.xml        |   18 -
 .../android/src/org/testing/TestBase.java       |   37 -
 e2e/fixtures/plugins/fake1/plugin.xml           |   10 -
 e2e/helpers.js                                  |   46 -
 e2e/hooker.spec.js                              |  261 ---
 e2e/platform.spec.js                            |  108 --
 e2e/plugin.spec.js                              |   68 -
 spec/create.spec.js                             |  138 ++
 spec/fixtures/base/.cordova/config.json         |   22 +
 spec/fixtures/base/merges/.svn                  |    0
 spec/fixtures/base/platforms/.svn               |    0
 spec/fixtures/base/plugins/.svn                 |    0
 spec/fixtures/base/www/config.xml               |   14 +
 spec/fixtures/base/www/css/index.css            |  115 ++
 spec/fixtures/base/www/img/logo.png             |  Bin 0 -> 21814 bytes
 spec/fixtures/base/www/index.html               |   43 +
 spec/fixtures/base/www/js/index.js              |   49 +
 spec/fixtures/base/www/spec.html                |   68 +
 spec/fixtures/hooks_bat/fail/fail.bat           |    2 +
 spec/fixtures/hooks_bat/test/.dotted.bat        |    2 +
 spec/fixtures/hooks_bat/test/07.bat             |    3 +
 spec/fixtures/hooks_bat/test/1.bat              |    5 +
 spec/fixtures/hooks_sh/fail/fail.sh             |    1 +
 spec/fixtures/hooks_sh/test/.dotted.sh          |    1 +
 spec/fixtures/hooks_sh/test/07.sh               |    2 +
 spec/fixtures/hooks_sh/test/1.sh                |    4 +
 spec/fixtures/platforms/android-lib/VERSION     |    1 +
 .../android-lib/framework/assets/www/cordova.js |    1 +
 .../platforms/android/AndroidManifest.xml       |   14 +
 .../platforms/android/assets/www/config.xml     |   14 +
 .../platforms/android/assets/www/cordova.js     | 1712 ++++++++++++++++++
 .../android/assets/www/cordova_plugins.js       |    3 +
 .../platforms/android/assets/www/css/index.css  |  115 ++
 .../platforms/android/assets/www/img/logo.png   |  Bin 0 -> 21814 bytes
 .../platforms/android/assets/www/index.html     |   43 +
 .../platforms/android/assets/www/js/index.js    |   49 +
 .../platforms/android/assets/www/spec.html      |   68 +
 spec/fixtures/platforms/android/build.xml       |   92 +
 spec/fixtures/platforms/android/cordova/build   |   35 +
 .../platforms/android/cordova/check_reqs        |   27 +
 spec/fixtures/platforms/android/cordova/clean   |   34 +
 .../platforms/android/cordova/defaults.xml      |   50 +
 .../platforms/android/cordova/lib/appinfo.js    |   41 +
 .../platforms/android/cordova/lib/build.js      |   89 +
 .../platforms/android/cordova/lib/check_reqs.js |   78 +
 .../platforms/android/cordova/lib/clean.js      |   43 +
 .../platforms/android/cordova/lib/device.js     |   95 +
 .../platforms/android/cordova/lib/emulator.js   |  337 ++++
 .../android/cordova/lib/install-device          |   38 +
 .../android/cordova/lib/install-emulator        |   38 +
 .../platforms/android/cordova/lib/list-devices  |   28 +
 .../android/cordova/lib/list-emulator-images    |   29 +
 .../android/cordova/lib/list-started-emulators  |   29 +
 .../platforms/android/cordova/lib/log.js        |   43 +
 .../platforms/android/cordova/lib/run.js        |  124 ++
 .../android/cordova/lib/start-emulator          |   38 +
 spec/fixtures/platforms/android/cordova/log     |   33 +
 spec/fixtures/platforms/android/cordova/run     |   35 +
 spec/fixtures/platforms/android/cordova/version |   25 +
 .../fixtures/platforms/android/local.properties |   10 +
 .../platforms/android/proguard-project.txt      |   20 +
 .../platforms/android/project.properties        |   14 +
 .../android/res/drawable-hdpi/icon.png          |  Bin 0 -> 6080 bytes
 .../android/res/drawable-ldpi/icon.png          |  Bin 0 -> 3096 bytes
 .../android/res/drawable-mdpi/icon.png          |  Bin 0 -> 4090 bytes
 .../android/res/drawable-xhdpi/icon.png         |  Bin 0 -> 7685 bytes
 .../platforms/android/res/drawable/icon.png     |  Bin 0 -> 7685 bytes
 .../platforms/android/res/values/strings.xml    |    4 +
 .../platforms/android/res/xml/config.xml        |   18 +
 .../android/src/org/testing/TestBase.java       |   37 +
 spec/fixtures/plugins/fake1/plugin.xml          |   10 +
 spec/helpers.js                                 |   46 +
 spec/hooker.spec.js                             |  261 +++
 spec/platform.spec.js                           |  108 ++
 spec/plugin.spec.js                             |   68 +
 136 files changed, 4466 insertions(+), 4466 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/create.spec.js
----------------------------------------------------------------------
diff --git a/e2e/create.spec.js b/e2e/create.spec.js
deleted file mode 100644
index ebdfab5..0000000
--- a/e2e/create.spec.js
+++ /dev/null
@@ -1,138 +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 helpers = require('./helpers'),
-    path = require('path'),
-    fs = require('fs'),
-    shell = require('shelljs'),
-    Q = require('q'),
-    config = require('../src/config'),
-    events = require('../src/events'),
-    util = require('../src/util'),
-    ConfigParser = require('../src/ConfigParser'),
-    cordova = require('../cordova');
-
-// A utility function to generate all combinations of elements from 2 arrays.
-// crossConcat(['x', 'y'], ['1', '2', '3'])
-// -> [ 'x1', 'x2', 'x3', 'y1', 'y2', 'y3']
-var crossConcat = function(a, b, delimiter){
-    var result = [];
-    delimiter = delimiter || '';
-    for (var i = 0; i < a.length; i++) {
-        for (var j = 0; j < b.length; j++) {
-            result.push(a[i] + delimiter + b[j]);
-        }
-    }
-    return result;
-};
-
-var tmpDir = helpers.tmpDir('create_test');
-var appName = 'TestBase';
-var appId = 'org.testing';
-var project = path.join(tmpDir, appName);
-var cordovaDir = path.join(project, '.cordova');
-var configNormal = {
-      lib: {
-        www: {
-          uri: path.join(__dirname, 'fixtures', 'base', 'www'),
-          version: "testCordovaCreate",
-          id: appName
-        }
-      }
-    };
-var configSymlink = {
-      lib: {
-        www: {
-          uri: path.join(__dirname, 'fixtures', 'base'), // "create" should copy or link the www child of this dir and not the dir itself.
-          link: true
-        }
-      }
-    };
-
-
-describe('create end-to-end', function() {
-
-    beforeEach(function() {
-        shell.rm('-rf', project);
-    });
-    afterEach(function() {
-        process.chdir(path.join(__dirname, '..'));  // Needed to rm the dir on Windows.
-        shell.rm('-rf', tmpDir);
-    });
-
-    function checkProject() {
-        // Check if top level dirs exist.
-        var dirs = ['hooks', 'platforms', 'merges', 'plugins', 'www'];
-        dirs.forEach(function(d) {
-            expect(path.join(project, d)).toExist();
-        });
-
-        expect(path.join(project, 'hooks', 'README.md')).toExist();
-
-        // Check if config files exist.
-        expect(path.join(project, 'www', 'index.html')).toExist();
-
-        // Check that www/config.xml was updated.
-        var configXml = new ConfigParser(path.join(project, 'www', 'config.xml'));
-        expect(configXml.packageName()).toEqual(appId);
-
-        // TODO (kamrik): check somehow that we got the right config.xml from the fixture and not some place else.
-        // expect(configXml.name()).toEqual('TestBase');
-    }
-
-    var results;
-    events.on('results', function(res) { results = res; });
-
-    it('should successfully run with regular config', function(done) {
-        // Call cordova create with no args, should return help.
-        cordova.raw.create()
-        .then(function() {
-            expect(results).toMatch(/synopsis/gi);
-        })
-        .then(function() {
-            // Create a real project
-            return cordova.raw.create(project, appId, appName, configNormal);
-        })
-        .then(checkProject)
-        .fail(function(err) {
-            console.log(err);
-            expect(err).toBeUndefined();
-        })
-        .fin(done);
-    });
-
-    it('should successfully run with symlinked www', function(done) {
-        // Call cordova create with no args, should return help.
-        cordova.raw.create(project, appId, appName, configSymlink)
-        .then(checkProject)
-        .then(function() {
-            // Check that www is really a symlink
-            expect(fs.lstatSync(path.join(project, 'www')).isSymbolicLink()).toBe(true);
-        })
-        .fail(function(err) {
-            if(process.platform.slice(0, 3) == 'win') {
-                // Allow symlink error if not in admin mode
-                expect(err.message).toBe("Symlinks on Windows require Administrator privileges");
-            } else {
-                expect(err).toBeUndefined();
-            }
-        })
-        .fin(done);
-    });
-});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/base/.cordova/config.json
----------------------------------------------------------------------
diff --git a/e2e/fixtures/base/.cordova/config.json b/e2e/fixtures/base/.cordova/config.json
deleted file mode 100644
index 662fc9d..0000000
--- a/e2e/fixtures/base/.cordova/config.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
-  "id": "org.testing",
-  "name":"TestBase",
-  "lib": {
-    "android": {
-      "uri": "/some/junk/path",
-      "version": "dev",
-      "id": "cordova-android-dev"
-    },
-    "ios": {
-      "uri": "/some/junk/path",
-      "version": "dev",
-      "id": "cordova-ios-dev"
-    },
-    "wp8": {
-      "uri": "/some/junk/path",
-      "version": "dev",
-      "id": "cordova-wp8-dev"
-    }
-  }
-}
-

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/base/merges/.svn
----------------------------------------------------------------------
diff --git a/e2e/fixtures/base/merges/.svn b/e2e/fixtures/base/merges/.svn
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/base/platforms/.svn
----------------------------------------------------------------------
diff --git a/e2e/fixtures/base/platforms/.svn b/e2e/fixtures/base/platforms/.svn
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/base/plugins/.svn
----------------------------------------------------------------------
diff --git a/e2e/fixtures/base/plugins/.svn b/e2e/fixtures/base/plugins/.svn
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/base/www/config.xml
----------------------------------------------------------------------
diff --git a/e2e/fixtures/base/www/config.xml b/e2e/fixtures/base/www/config.xml
deleted file mode 100644
index 9e7b9e0..0000000
--- a/e2e/fixtures/base/www/config.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<widget id="org.testing" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
-    <name>TestBase</name>
-    <description>
-        A sample Apache Cordova application that responds to the deviceready event.
-    </description>
-    <author email="dev@cordova.apache.org" href="http://cordova.io">
-        Apache Cordova Team
-    </author>
-    <content src="index.html" />
-    <access origin="*" />
-    <preference name="fullscreen" value="true" />
-    <preference name="webviewbounce" value="true" />
-</widget>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/base/www/css/index.css
----------------------------------------------------------------------
diff --git a/e2e/fixtures/base/www/css/index.css b/e2e/fixtures/base/www/css/index.css
deleted file mode 100644
index 51daa79..0000000
--- a/e2e/fixtures/base/www/css/index.css
+++ /dev/null
@@ -1,115 +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.
- */
-* {
-    -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
-}
-
-body {
-    -webkit-touch-callout: none;                /* prevent callout to copy image, etc when tap to hold */
-    -webkit-text-size-adjust: none;             /* prevent webkit from resizing text to fit */
-    -webkit-user-select: none;                  /* prevent copy paste, to allow, change 'none' to 'text' */
-    background-color:#E4E4E4;
-    background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
-    background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
-    background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
-    background-image:-webkit-gradient(
-        linear,
-        left top,
-        left bottom,
-        color-stop(0, #A7A7A7),
-        color-stop(0.51, #E4E4E4)
-    );
-    background-attachment:fixed;
-    font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
-    font-size:12px;
-    height:100%;
-    margin:0px;
-    padding:0px;
-    text-transform:uppercase;
-    width:100%;
-}
-
-/* Portrait layout (default) */
-.app {
-    background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
-    position:absolute;             /* position in the center of the screen */
-    left:50%;
-    top:50%;
-    height:50px;                   /* text area height */
-    width:225px;                   /* text area width */
-    text-align:center;
-    padding:180px 0px 0px 0px;     /* image height is 200px (bottom 20px are overlapped with text) */
-    margin:-115px 0px 0px -112px;  /* offset vertical: half of image height and text area height */
-                                   /* offset horizontal: half of text area width */
-}
-
-/* Landscape layout (with min-width) */
-@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
-    .app {
-        background-position:left center;
-        padding:75px 0px 75px 170px;  /* padding-top + padding-bottom + text area = image height */
-        margin:-90px 0px 0px -198px;  /* offset vertical: half of image height */
-                                      /* offset horizontal: half of image width and text area width */
-    }
-}
-
-h1 {
-    font-size:24px;
-    font-weight:normal;
-    margin:0px;
-    overflow:visible;
-    padding:0px;
-    text-align:center;
-}
-
-.event {
-    border-radius:4px;
-    -webkit-border-radius:4px;
-    color:#FFFFFF;
-    font-size:12px;
-    margin:0px 30px;
-    padding:2px 0px;
-}
-
-.event.listening {
-    background-color:#333333;
-    display:block;
-}
-
-.event.received {
-    background-color:#4B946A;
-    display:none;
-}
-
-@keyframes fade {
-    from { opacity: 1.0; }
-    50% { opacity: 0.4; }
-    to { opacity: 1.0; }
-}
- 
-@-webkit-keyframes fade {
-    from { opacity: 1.0; }
-    50% { opacity: 0.4; }
-    to { opacity: 1.0; }
-}
- 
-.blink {
-    animation:fade 3000ms infinite;
-    -webkit-animation:fade 3000ms infinite;
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/base/www/img/logo.png
----------------------------------------------------------------------
diff --git a/e2e/fixtures/base/www/img/logo.png b/e2e/fixtures/base/www/img/logo.png
deleted file mode 100644
index 9519e7d..0000000
Binary files a/e2e/fixtures/base/www/img/logo.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/base/www/index.html
----------------------------------------------------------------------
diff --git a/e2e/fixtures/base/www/index.html b/e2e/fixtures/base/www/index.html
deleted file mode 100644
index bde5741..0000000
--- a/e2e/fixtures/base/www/index.html
+++ /dev/null
@@ -1,43 +0,0 @@
-<!DOCTYPE html>
-<!--
-    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.
--->
-<html>
-    <head>
-        <meta charset="utf-8" />
-        <meta name="format-detection" content="telephone=no" />
-        <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
-        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
-        <link rel="stylesheet" type="text/css" href="css/index.css" />
-        <title>Hello World</title>
-    </head>
-    <body>
-        <div class="app">
-            <h1>Apache Cordova</h1>
-            <div id="deviceready" class="blink">
-                <p class="event listening">Connecting to Device</p>
-                <p class="event received">Device is Ready</p>
-            </div>
-        </div>
-        <script type="text/javascript" src="cordova.js"></script>
-        <script type="text/javascript" src="js/index.js"></script>
-        <script type="text/javascript">
-            app.initialize();
-        </script>
-    </body>
-</html>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/base/www/js/index.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/base/www/js/index.js b/e2e/fixtures/base/www/js/index.js
deleted file mode 100644
index 31d9064..0000000
--- a/e2e/fixtures/base/www/js/index.js
+++ /dev/null
@@ -1,49 +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 app = {
-    // Application Constructor
-    initialize: function() {
-        this.bindEvents();
-    },
-    // Bind Event Listeners
-    //
-    // Bind any events that are required on startup. Common events are:
-    // 'load', 'deviceready', 'offline', and 'online'.
-    bindEvents: function() {
-        document.addEventListener('deviceready', this.onDeviceReady, false);
-    },
-    // deviceready Event Handler
-    //
-    // The scope of 'this' is the event. In order to call the 'receivedEvent'
-    // function, we must explicity call 'app.receivedEvent(...);'
-    onDeviceReady: function() {
-        app.receivedEvent('deviceready');
-    },
-    // Update DOM on a Received Event
-    receivedEvent: function(id) {
-        var parentElement = document.getElementById(id);
-        var listeningElement = parentElement.querySelector('.listening');
-        var receivedElement = parentElement.querySelector('.received');
-
-        listeningElement.setAttribute('style', 'display:none;');
-        receivedElement.setAttribute('style', 'display:block;');
-
-        console.log('Received Event: ' + id);
-    }
-};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/base/www/spec.html
----------------------------------------------------------------------
diff --git a/e2e/fixtures/base/www/spec.html b/e2e/fixtures/base/www/spec.html
deleted file mode 100644
index 71f00de..0000000
--- a/e2e/fixtures/base/www/spec.html
+++ /dev/null
@@ -1,68 +0,0 @@
-<!DOCTYPE html>
-<!--
-    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.
--->
-<html>
-    <head>
-        <title>Jasmine Spec Runner</title>
-
-        <!-- jasmine source -->
-        <link rel="shortcut icon" type="image/png" href="spec/lib/jasmine-1.2.0/jasmine_favicon.png">
-        <link rel="stylesheet" type="text/css" href="spec/lib/jasmine-1.2.0/jasmine.css">
-        <script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine.js"></script>
-        <script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine-html.js"></script>
-
-        <!-- include source files here... -->
-        <script type="text/javascript" src="js/index.js"></script>
-
-        <!-- include spec files here... -->
-        <script type="text/javascript" src="spec/helper.js"></script>
-        <script type="text/javascript" src="spec/index.js"></script>
-
-        <script type="text/javascript">
-            (function() {
-                var jasmineEnv = jasmine.getEnv();
-                jasmineEnv.updateInterval = 1000;
-
-                var htmlReporter = new jasmine.HtmlReporter();
-
-                jasmineEnv.addReporter(htmlReporter);
-
-                jasmineEnv.specFilter = function(spec) {
-                    return htmlReporter.specFilter(spec);
-                };
-
-                var currentWindowOnload = window.onload;
-
-                window.onload = function() {
-                    if (currentWindowOnload) {
-                        currentWindowOnload();
-                    }
-                    execJasmine();
-                };
-
-                function execJasmine() {
-                    jasmineEnv.execute();
-                }
-            })();
-        </script>
-    </head>
-    <body>
-        <div id="stage" style="display:none;"></div>
-    </body>
-</html>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/hooks_bat/fail/fail.bat
----------------------------------------------------------------------
diff --git a/e2e/fixtures/hooks_bat/fail/fail.bat b/e2e/fixtures/hooks_bat/fail/fail.bat
deleted file mode 100644
index a89b4c8..0000000
--- a/e2e/fixtures/hooks_bat/fail/fail.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@ECHO OFF
-EXIT /B 1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/hooks_bat/test/.dotted.bat
----------------------------------------------------------------------
diff --git a/e2e/fixtures/hooks_bat/test/.dotted.bat b/e2e/fixtures/hooks_bat/test/.dotted.bat
deleted file mode 100644
index ada7136..0000000
--- a/e2e/fixtures/hooks_bat/test/.dotted.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@ECHO OFF
-ECHO "Dotted files in hook dirs should not be called" > dotted_hook_should_not_fire.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/hooks_bat/test/07.bat
----------------------------------------------------------------------
diff --git a/e2e/fixtures/hooks_bat/test/07.bat b/e2e/fixtures/hooks_bat/test/07.bat
deleted file mode 100644
index a88c8c5..0000000
--- a/e2e/fixtures/hooks_bat/test/07.bat
+++ /dev/null
@@ -1,3 +0,0 @@
-@ECHO OFF
-rem ECHO this is script 0 in %~dp0
-ECHO b >> hooks_order.txt

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/hooks_bat/test/1.bat
----------------------------------------------------------------------
diff --git a/e2e/fixtures/hooks_bat/test/1.bat b/e2e/fixtures/hooks_bat/test/1.bat
deleted file mode 100644
index be004c5..0000000
--- a/e2e/fixtures/hooks_bat/test/1.bat
+++ /dev/null
@@ -1,5 +0,0 @@
-@ECHO OFF
-rem ECHO this is script 1 in %~dp0
-ECHO a >> hooks_order.txt
-ECHO %1 > hooks_params.txt
-node -e "console.log(JSON.stringify(process.env, null, 2))" > hooks_env.json

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/hooks_sh/fail/fail.sh
----------------------------------------------------------------------
diff --git a/e2e/fixtures/hooks_sh/fail/fail.sh b/e2e/fixtures/hooks_sh/fail/fail.sh
deleted file mode 100755
index 379a4c9..0000000
--- a/e2e/fixtures/hooks_sh/fail/fail.sh
+++ /dev/null
@@ -1 +0,0 @@
-exit 1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/hooks_sh/test/.dotted.sh
----------------------------------------------------------------------
diff --git a/e2e/fixtures/hooks_sh/test/.dotted.sh b/e2e/fixtures/hooks_sh/test/.dotted.sh
deleted file mode 100755
index e5fa07f..0000000
--- a/e2e/fixtures/hooks_sh/test/.dotted.sh
+++ /dev/null
@@ -1 +0,0 @@
-echo "Dotted files in hook dirs should not be called" > dotted_hook_should_not_fire.txt

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/hooks_sh/test/07.sh
----------------------------------------------------------------------
diff --git a/e2e/fixtures/hooks_sh/test/07.sh b/e2e/fixtures/hooks_sh/test/07.sh
deleted file mode 100755
index f410ee2..0000000
--- a/e2e/fixtures/hooks_sh/test/07.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#echo "this is script 0 in `pwd`";
-echo b >> hooks_order.txt

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/hooks_sh/test/1.sh
----------------------------------------------------------------------
diff --git a/e2e/fixtures/hooks_sh/test/1.sh b/e2e/fixtures/hooks_sh/test/1.sh
deleted file mode 100755
index 892869d..0000000
--- a/e2e/fixtures/hooks_sh/test/1.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#echo "this is script 1 in `pwd`";
-echo a >> hooks_order.txt
-echo $1 > hooks_params.txt
-node -e "console.log(JSON.stringify(process.env, null, 2))" > hooks_env.json

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android-lib/VERSION
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android-lib/VERSION b/e2e/fixtures/platforms/android-lib/VERSION
deleted file mode 100644
index 15a2799..0000000
--- a/e2e/fixtures/platforms/android-lib/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-3.3.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android-lib/framework/assets/www/cordova.js
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android-lib/framework/assets/www/cordova.js b/e2e/fixtures/platforms/android-lib/framework/assets/www/cordova.js
deleted file mode 100644
index 91c51fc..0000000
--- a/e2e/fixtures/platforms/android-lib/framework/assets/www/cordova.js
+++ /dev/null
@@ -1 +0,0 @@
-This is a placeholder file.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/AndroidManifest.xml
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/AndroidManifest.xml b/e2e/fixtures/platforms/android/AndroidManifest.xml
deleted file mode 100644
index be3f245..0000000
--- a/e2e/fixtures/platforms/android/AndroidManifest.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" android:windowSoftInputMode="adjustPan" package="org.testing" xmlns:android="http://schemas.android.com/apk/res/android">
-    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <application android:debuggable="true" android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string/app_name">
-        <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/app_name" android:name="TestBase" android:theme="@android:style/Theme.Black.NoTitleBar">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17" />
-</manifest>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/e2e/fixtures/platforms/android/assets/www/config.xml
----------------------------------------------------------------------
diff --git a/e2e/fixtures/platforms/android/assets/www/config.xml b/e2e/fixtures/platforms/android/assets/www/config.xml
deleted file mode 100644
index 9e7b9e0..0000000
--- a/e2e/fixtures/platforms/android/assets/www/config.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<widget id="org.testing" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
-    <name>TestBase</name>
-    <description>
-        A sample Apache Cordova application that responds to the deviceready event.
-    </description>
-    <author email="dev@cordova.apache.org" href="http://cordova.io">
-        Apache Cordova Team
-    </author>
-    <content src="index.html" />
-    <access origin="*" />
-    <preference name="fullscreen" value="true" />
-    <preference name="webviewbounce" value="true" />
-</widget>


[3/8] CB-6421: Move tests from e2e to spec

Posted by ka...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/base/www/index.html
----------------------------------------------------------------------
diff --git a/spec/fixtures/base/www/index.html b/spec/fixtures/base/www/index.html
new file mode 100644
index 0000000..bde5741
--- /dev/null
+++ b/spec/fixtures/base/www/index.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!--
+    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.
+-->
+<html>
+    <head>
+        <meta charset="utf-8" />
+        <meta name="format-detection" content="telephone=no" />
+        <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
+        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
+        <link rel="stylesheet" type="text/css" href="css/index.css" />
+        <title>Hello World</title>
+    </head>
+    <body>
+        <div class="app">
+            <h1>Apache Cordova</h1>
+            <div id="deviceready" class="blink">
+                <p class="event listening">Connecting to Device</p>
+                <p class="event received">Device is Ready</p>
+            </div>
+        </div>
+        <script type="text/javascript" src="cordova.js"></script>
+        <script type="text/javascript" src="js/index.js"></script>
+        <script type="text/javascript">
+            app.initialize();
+        </script>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/base/www/js/index.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/base/www/js/index.js b/spec/fixtures/base/www/js/index.js
new file mode 100644
index 0000000..31d9064
--- /dev/null
+++ b/spec/fixtures/base/www/js/index.js
@@ -0,0 +1,49 @@
+/*
+ * 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 app = {
+    // Application Constructor
+    initialize: function() {
+        this.bindEvents();
+    },
+    // Bind Event Listeners
+    //
+    // Bind any events that are required on startup. Common events are:
+    // 'load', 'deviceready', 'offline', and 'online'.
+    bindEvents: function() {
+        document.addEventListener('deviceready', this.onDeviceReady, false);
+    },
+    // deviceready Event Handler
+    //
+    // The scope of 'this' is the event. In order to call the 'receivedEvent'
+    // function, we must explicity call 'app.receivedEvent(...);'
+    onDeviceReady: function() {
+        app.receivedEvent('deviceready');
+    },
+    // Update DOM on a Received Event
+    receivedEvent: function(id) {
+        var parentElement = document.getElementById(id);
+        var listeningElement = parentElement.querySelector('.listening');
+        var receivedElement = parentElement.querySelector('.received');
+
+        listeningElement.setAttribute('style', 'display:none;');
+        receivedElement.setAttribute('style', 'display:block;');
+
+        console.log('Received Event: ' + id);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/base/www/spec.html
----------------------------------------------------------------------
diff --git a/spec/fixtures/base/www/spec.html b/spec/fixtures/base/www/spec.html
new file mode 100644
index 0000000..71f00de
--- /dev/null
+++ b/spec/fixtures/base/www/spec.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<!--
+    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.
+-->
+<html>
+    <head>
+        <title>Jasmine Spec Runner</title>
+
+        <!-- jasmine source -->
+        <link rel="shortcut icon" type="image/png" href="spec/lib/jasmine-1.2.0/jasmine_favicon.png">
+        <link rel="stylesheet" type="text/css" href="spec/lib/jasmine-1.2.0/jasmine.css">
+        <script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine.js"></script>
+        <script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine-html.js"></script>
+
+        <!-- include source files here... -->
+        <script type="text/javascript" src="js/index.js"></script>
+
+        <!-- include spec files here... -->
+        <script type="text/javascript" src="spec/helper.js"></script>
+        <script type="text/javascript" src="spec/index.js"></script>
+
+        <script type="text/javascript">
+            (function() {
+                var jasmineEnv = jasmine.getEnv();
+                jasmineEnv.updateInterval = 1000;
+
+                var htmlReporter = new jasmine.HtmlReporter();
+
+                jasmineEnv.addReporter(htmlReporter);
+
+                jasmineEnv.specFilter = function(spec) {
+                    return htmlReporter.specFilter(spec);
+                };
+
+                var currentWindowOnload = window.onload;
+
+                window.onload = function() {
+                    if (currentWindowOnload) {
+                        currentWindowOnload();
+                    }
+                    execJasmine();
+                };
+
+                function execJasmine() {
+                    jasmineEnv.execute();
+                }
+            })();
+        </script>
+    </head>
+    <body>
+        <div id="stage" style="display:none;"></div>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/hooks_bat/fail/fail.bat
----------------------------------------------------------------------
diff --git a/spec/fixtures/hooks_bat/fail/fail.bat b/spec/fixtures/hooks_bat/fail/fail.bat
new file mode 100644
index 0000000..a89b4c8
--- /dev/null
+++ b/spec/fixtures/hooks_bat/fail/fail.bat
@@ -0,0 +1,2 @@
+@ECHO OFF
+EXIT /B 1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/hooks_bat/test/.dotted.bat
----------------------------------------------------------------------
diff --git a/spec/fixtures/hooks_bat/test/.dotted.bat b/spec/fixtures/hooks_bat/test/.dotted.bat
new file mode 100644
index 0000000..ada7136
--- /dev/null
+++ b/spec/fixtures/hooks_bat/test/.dotted.bat
@@ -0,0 +1,2 @@
+@ECHO OFF
+ECHO "Dotted files in hook dirs should not be called" > dotted_hook_should_not_fire.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/hooks_bat/test/07.bat
----------------------------------------------------------------------
diff --git a/spec/fixtures/hooks_bat/test/07.bat b/spec/fixtures/hooks_bat/test/07.bat
new file mode 100644
index 0000000..a88c8c5
--- /dev/null
+++ b/spec/fixtures/hooks_bat/test/07.bat
@@ -0,0 +1,3 @@
+@ECHO OFF
+rem ECHO this is script 0 in %~dp0
+ECHO b >> hooks_order.txt

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/hooks_bat/test/1.bat
----------------------------------------------------------------------
diff --git a/spec/fixtures/hooks_bat/test/1.bat b/spec/fixtures/hooks_bat/test/1.bat
new file mode 100644
index 0000000..be004c5
--- /dev/null
+++ b/spec/fixtures/hooks_bat/test/1.bat
@@ -0,0 +1,5 @@
+@ECHO OFF
+rem ECHO this is script 1 in %~dp0
+ECHO a >> hooks_order.txt
+ECHO %1 > hooks_params.txt
+node -e "console.log(JSON.stringify(process.env, null, 2))" > hooks_env.json

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/hooks_sh/fail/fail.sh
----------------------------------------------------------------------
diff --git a/spec/fixtures/hooks_sh/fail/fail.sh b/spec/fixtures/hooks_sh/fail/fail.sh
new file mode 100755
index 0000000..379a4c9
--- /dev/null
+++ b/spec/fixtures/hooks_sh/fail/fail.sh
@@ -0,0 +1 @@
+exit 1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/hooks_sh/test/.dotted.sh
----------------------------------------------------------------------
diff --git a/spec/fixtures/hooks_sh/test/.dotted.sh b/spec/fixtures/hooks_sh/test/.dotted.sh
new file mode 100755
index 0000000..e5fa07f
--- /dev/null
+++ b/spec/fixtures/hooks_sh/test/.dotted.sh
@@ -0,0 +1 @@
+echo "Dotted files in hook dirs should not be called" > dotted_hook_should_not_fire.txt

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/hooks_sh/test/07.sh
----------------------------------------------------------------------
diff --git a/spec/fixtures/hooks_sh/test/07.sh b/spec/fixtures/hooks_sh/test/07.sh
new file mode 100755
index 0000000..f410ee2
--- /dev/null
+++ b/spec/fixtures/hooks_sh/test/07.sh
@@ -0,0 +1,2 @@
+#echo "this is script 0 in `pwd`";
+echo b >> hooks_order.txt

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/hooks_sh/test/1.sh
----------------------------------------------------------------------
diff --git a/spec/fixtures/hooks_sh/test/1.sh b/spec/fixtures/hooks_sh/test/1.sh
new file mode 100755
index 0000000..892869d
--- /dev/null
+++ b/spec/fixtures/hooks_sh/test/1.sh
@@ -0,0 +1,4 @@
+#echo "this is script 1 in `pwd`";
+echo a >> hooks_order.txt
+echo $1 > hooks_params.txt
+node -e "console.log(JSON.stringify(process.env, null, 2))" > hooks_env.json

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android-lib/VERSION
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android-lib/VERSION b/spec/fixtures/platforms/android-lib/VERSION
new file mode 100644
index 0000000..15a2799
--- /dev/null
+++ b/spec/fixtures/platforms/android-lib/VERSION
@@ -0,0 +1 @@
+3.3.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android-lib/framework/assets/www/cordova.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android-lib/framework/assets/www/cordova.js b/spec/fixtures/platforms/android-lib/framework/assets/www/cordova.js
new file mode 100644
index 0000000..91c51fc
--- /dev/null
+++ b/spec/fixtures/platforms/android-lib/framework/assets/www/cordova.js
@@ -0,0 +1 @@
+This is a placeholder file.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/AndroidManifest.xml
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/AndroidManifest.xml b/spec/fixtures/platforms/android/AndroidManifest.xml
new file mode 100644
index 0000000..be3f245
--- /dev/null
+++ b/spec/fixtures/platforms/android/AndroidManifest.xml
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='utf-8'?>
+<manifest android:hardwareAccelerated="true" android:versionCode="1" android:versionName="0.0.1" android:windowSoftInputMode="adjustPan" package="org.testing" xmlns:android="http://schemas.android.com/apk/res/android">
+    <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <application android:debuggable="true" android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string/app_name">
+        <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/app_name" android:name="TestBase" android:theme="@android:style/Theme.Black.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="17" />
+</manifest>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/assets/www/config.xml
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/assets/www/config.xml b/spec/fixtures/platforms/android/assets/www/config.xml
new file mode 100644
index 0000000..9e7b9e0
--- /dev/null
+++ b/spec/fixtures/platforms/android/assets/www/config.xml
@@ -0,0 +1,14 @@
+<?xml version='1.0' encoding='utf-8'?>
+<widget id="org.testing" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
+    <name>TestBase</name>
+    <description>
+        A sample Apache Cordova application that responds to the deviceready event.
+    </description>
+    <author email="dev@cordova.apache.org" href="http://cordova.io">
+        Apache Cordova Team
+    </author>
+    <content src="index.html" />
+    <access origin="*" />
+    <preference name="fullscreen" value="true" />
+    <preference name="webviewbounce" value="true" />
+</widget>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/assets/www/cordova.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/assets/www/cordova.js b/spec/fixtures/platforms/android/assets/www/cordova.js
new file mode 100644
index 0000000..07e3feb
--- /dev/null
+++ b/spec/fixtures/platforms/android/assets/www/cordova.js
@@ -0,0 +1,1712 @@
+// Platform: android
+// 3.1.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.
+*/
+;(function() {
+var CORDOVA_JS_BUILD_LABEL = '3.1.0';
+// file: lib/scripts/require.js
+
+var require,
+    define;
+
+(function () {
+    var modules = {},
+    // Stack of moduleIds currently being built.
+        requireStack = [],
+    // Map of module ID -> index into requireStack of modules currently being built.
+        inProgressModules = {},
+        SEPERATOR = ".";
+
+
+
+    function build(module) {
+        var factory = module.factory,
+            localRequire = function (id) {
+                var resultantId = id;
+                //Its a relative path, so lop off the last portion and add the id (minus "./")
+                if (id.charAt(0) === ".") {
+                    resultantId = module.id.slice(0, module.id.lastIndexOf(SEPERATOR)) + SEPERATOR + id.slice(2);
+                }
+                return require(resultantId);
+            };
+        module.exports = {};
+        delete module.factory;
+        factory(localRequire, module.exports, module);
+        return module.exports;
+    }
+
+    require = function (id) {
+        if (!modules[id]) {
+            throw "module " + id + " not found";
+        } else if (id in inProgressModules) {
+            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+            throw "Cycle in require graph: " + cycle;
+        }
+        if (modules[id].factory) {
+            try {
+                inProgressModules[id] = requireStack.length;
+                requireStack.push(id);
+                return build(modules[id]);
+            } finally {
+                delete inProgressModules[id];
+                requireStack.pop();
+            }
+        }
+        return modules[id].exports;
+    };
+
+    define = function (id, factory) {
+        if (modules[id]) {
+            throw "module " + id + " already defined";
+        }
+
+        modules[id] = {
+            id: id,
+            factory: factory
+        };
+    };
+
+    define.remove = function (id) {
+        delete modules[id];
+    };
+
+    define.moduleMap = modules;
+})();
+
+//Export for use in node
+if (typeof module === "object" && typeof require === "function") {
+    module.exports.require = require;
+    module.exports.define = define;
+}
+
+// file: lib/cordova.js
+define("cordova", function(require, exports, module) {
+
+
+var channel = require('cordova/channel');
+var platform = require('cordova/platform');
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {},
+    windowEventHandlers = {};
+
+document.addEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof documentEventHandlers[e] != 'undefined') {
+        documentEventHandlers[e].subscribe(handler);
+    } else {
+        m_document_addEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.addEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof windowEventHandlers[e] != 'undefined') {
+        windowEventHandlers[e].subscribe(handler);
+    } else {
+        m_window_addEventListener.call(window, evt, handler, capture);
+    }
+};
+
+document.removeEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof documentEventHandlers[e] != "undefined") {
+        documentEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_document_removeEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.removeEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof windowEventHandlers[e] != "undefined") {
+        windowEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_window_removeEventListener.call(window, evt, handler, capture);
+    }
+};
+
+function createEvent(type, data) {
+    var event = document.createEvent('Events');
+    event.initEvent(type, false, false);
+    if (data) {
+        for (var i in data) {
+            if (data.hasOwnProperty(i)) {
+                event[i] = data[i];
+            }
+        }
+    }
+    return event;
+}
+
+
+var cordova = {
+    define:define,
+    require:require,
+    version:CORDOVA_JS_BUILD_LABEL,
+    platformId:platform.id,
+    /**
+     * Methods to add/remove your own addEventListener hijacking on document + window.
+     */
+    addWindowEventHandler:function(event) {
+        return (windowEventHandlers[event] = channel.create(event));
+    },
+    addStickyDocumentEventHandler:function(event) {
+        return (documentEventHandlers[event] = channel.createSticky(event));
+    },
+    addDocumentEventHandler:function(event) {
+        return (documentEventHandlers[event] = channel.create(event));
+    },
+    removeWindowEventHandler:function(event) {
+        delete windowEventHandlers[event];
+    },
+    removeDocumentEventHandler:function(event) {
+        delete documentEventHandlers[event];
+    },
+    /**
+     * Retrieve original event handlers that were replaced by Cordova
+     *
+     * @return object
+     */
+    getOriginalHandlers: function() {
+        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
+        'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
+    },
+    /**
+     * Method to fire event from native code
+     * bNoDetach is required for events which cause an exception which needs to be caught in native code
+     */
+    fireDocumentEvent: function(type, data, bNoDetach) {
+        var evt = createEvent(type, data);
+        if (typeof documentEventHandlers[type] != 'undefined') {
+            if( bNoDetach ) {
+                documentEventHandlers[type].fire(evt);
+            }
+            else {
+                setTimeout(function() {
+                    // Fire deviceready on listeners that were registered before cordova.js was loaded.
+                    if (type == 'deviceready') {
+                        document.dispatchEvent(evt);
+                    }
+                    documentEventHandlers[type].fire(evt);
+                }, 0);
+            }
+        } else {
+            document.dispatchEvent(evt);
+        }
+    },
+    fireWindowEvent: function(type, data) {
+        var evt = createEvent(type,data);
+        if (typeof windowEventHandlers[type] != 'undefined') {
+            setTimeout(function() {
+                windowEventHandlers[type].fire(evt);
+            }, 0);
+        } else {
+            window.dispatchEvent(evt);
+        }
+    },
+
+    /**
+     * Plugin callback mechanism.
+     */
+    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+    callbackId: Math.floor(Math.random() * 2000000000),
+    callbacks:  {},
+    callbackStatus: {
+        NO_RESULT: 0,
+        OK: 1,
+        CLASS_NOT_FOUND_EXCEPTION: 2,
+        ILLEGAL_ACCESS_EXCEPTION: 3,
+        INSTANTIATION_EXCEPTION: 4,
+        MALFORMED_URL_EXCEPTION: 5,
+        IO_EXCEPTION: 6,
+        INVALID_ACTION: 7,
+        JSON_EXCEPTION: 8,
+        ERROR: 9
+    },
+
+    /**
+     * Called by native code when returning successful result from an action.
+     */
+    callbackSuccess: function(callbackId, args) {
+        try {
+            cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
+        } catch (e) {
+            console.log("Error in error callback: " + callbackId + " = "+e);
+        }
+    },
+
+    /**
+     * Called by native code when returning error result from an action.
+     */
+    callbackError: function(callbackId, args) {
+        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+        // Derive success from status.
+        try {
+            cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
+        } catch (e) {
+            console.log("Error in error callback: " + callbackId + " = "+e);
+        }
+    },
+
+    /**
+     * Called by native code when returning the result from an action.
+     */
+    callbackFromNative: function(callbackId, success, status, args, keepCallback) {
+        var callback = cordova.callbacks[callbackId];
+        if (callback) {
+            if (success && status == cordova.callbackStatus.OK) {
+                callback.success && callback.success.apply(null, args);
+            } else if (!success) {
+                callback.fail && callback.fail.apply(null, args);
+            }
+
+            // Clear callback if not expecting any more results
+            if (!keepCallback) {
+                delete cordova.callbacks[callbackId];
+            }
+        }
+    },
+    addConstructor: function(func) {
+        channel.onCordovaReady.subscribe(function() {
+            try {
+                func();
+            } catch(e) {
+                console.log("Failed to run constructor: " + e);
+            }
+        });
+    }
+};
+
+
+module.exports = cordova;
+
+});
+
+// file: lib/android/android/nativeapiprovider.js
+define("cordova/android/nativeapiprovider", function(require, exports, module) {
+
+/**
+ * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi.
+ */
+
+var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi');
+var currentApi = nativeApi;
+
+module.exports = {
+    get: function() { return currentApi; },
+    setPreferPrompt: function(value) {
+        currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi;
+    },
+    // Used only by tests.
+    set: function(value) {
+        currentApi = value;
+    }
+};
+
+});
+
+// file: lib/android/android/promptbasednativeapi.js
+define("cordova/android/promptbasednativeapi", function(require, exports, module) {
+
+/**
+ * Implements the API of ExposedJsApi.java, but uses prompt() to communicate.
+ * This is used only on the 2.3 simulator, where addJavascriptInterface() is broken.
+ */
+
+module.exports = {
+    exec: function(service, action, callbackId, argsJson) {
+        return prompt(argsJson, 'gap:'+JSON.stringify([service, action, callbackId]));
+    },
+    setNativeToJsBridgeMode: function(value) {
+        prompt(value, 'gap_bridge_mode:');
+    },
+    retrieveJsMessages: function(fromOnlineEvent) {
+        return prompt(+fromOnlineEvent, 'gap_poll:');
+    }
+};
+
+});
+
+// file: lib/common/argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+    'A': 'Array',
+    'D': 'Date',
+    'N': 'Number',
+    'S': 'String',
+    'F': 'Function',
+    'O': 'Object'
+};
+
+function extractParamName(callee, argIndex) {
+    return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
+}
+
+function checkArgs(spec, functionName, args, opt_callee) {
+    if (!moduleExports.enableChecks) {
+        return;
+    }
+    var errMsg = null;
+    var typeName;
+    for (var i = 0; i < spec.length; ++i) {
+        var c = spec.charAt(i),
+            cUpper = c.toUpperCase(),
+            arg = args[i];
+        // Asterix means allow anything.
+        if (c == '*') {
+            continue;
+        }
+        typeName = utils.typeName(arg);
+        if ((arg === null || arg === undefined) && c == cUpper) {
+            continue;
+        }
+        if (typeName != typeMap[cUpper]) {
+            errMsg = 'Expected ' + typeMap[cUpper];
+            break;
+        }
+    }
+    if (errMsg) {
+        errMsg += ', but got ' + typeName + '.';
+        errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+        // Don't log when running unit tests.
+        if (typeof jasmine == 'undefined') {
+            console.error(errMsg);
+        }
+        throw TypeError(errMsg);
+    }
+}
+
+function getValue(value, defaultValue) {
+    return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+
+});
+
+// file: lib/common/base64.js
+define("cordova/base64", function(require, exports, module) {
+
+var base64 = exports;
+
+base64.fromArrayBuffer = function(arrayBuffer) {
+    var array = new Uint8Array(arrayBuffer);
+    return uint8ToBase64(array);
+};
+
+//------------------------------------------------------------------------------
+
+/* This code is based on the performance tests at http://jsperf.com/b64tests
+ * This 12-bit-at-a-time algorithm was the best performing version on all
+ * platforms tested.
+ */
+
+var b64_6bit = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+var b64_12bit;
+
+var b64_12bitTable = function() {
+    b64_12bit = [];
+    for (var i=0; i<64; i++) {
+        for (var j=0; j<64; j++) {
+            b64_12bit[i*64+j] = b64_6bit[i] + b64_6bit[j];
+        }
+    }
+    b64_12bitTable = function() { return b64_12bit; };
+    return b64_12bit;
+};
+
+function uint8ToBase64(rawData) {
+    var numBytes = rawData.byteLength;
+    var output="";
+    var segment;
+    var table = b64_12bitTable();
+    for (var i=0;i<numBytes-2;i+=3) {
+        segment = (rawData[i] << 16) + (rawData[i+1] << 8) + rawData[i+2];
+        output += table[segment >> 12];
+        output += table[segment & 0xfff];
+    }
+    if (numBytes - i == 2) {
+        segment = (rawData[i] << 16) + (rawData[i+1] << 8);
+        output += table[segment >> 12];
+        output += b64_6bit[(segment & 0xfff) >> 6];
+        output += '=';
+    } else if (numBytes - i == 1) {
+        segment = (rawData[i] << 16);
+        output += table[segment >> 12];
+        output += '==';
+    }
+    return output;
+}
+
+});
+
+// file: lib/common/builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each(objects, func, context) {
+    for (var prop in objects) {
+        if (objects.hasOwnProperty(prop)) {
+            func.apply(context, [objects[prop], prop]);
+        }
+    }
+}
+
+function clobber(obj, key, value) {
+    exports.replaceHookForTesting(obj, key);
+    obj[key] = value;
+    // Getters can only be overridden by getters.
+    if (obj[key] !== value) {
+        utils.defineGetter(obj, key, function() {
+            return value;
+        });
+    }
+}
+
+function assignOrWrapInDeprecateGetter(obj, key, value, message) {
+    if (message) {
+        utils.defineGetter(obj, key, function() {
+            console.log(message);
+            delete obj[key];
+            clobber(obj, key, value);
+            return value;
+        });
+    } else {
+        clobber(obj, key, value);
+    }
+}
+
+function include(parent, objects, clobber, merge) {
+    each(objects, function (obj, key) {
+        try {
+            var result = obj.path ? require(obj.path) : {};
+
+            if (clobber) {
+                // Clobber if it doesn't exist.
+                if (typeof parent[key] === 'undefined') {
+                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                } else if (typeof obj.path !== 'undefined') {
+                    // If merging, merge properties onto parent, otherwise, clobber.
+                    if (merge) {
+                        recursiveMerge(parent[key], result);
+                    } else {
+                        assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                    }
+                }
+                result = parent[key];
+            } else {
+                // Overwrite if not currently defined.
+                if (typeof parent[key] == 'undefined') {
+                    assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                } else {
+                    // Set result to what already exists, so we can build children into it if they exist.
+                    result = parent[key];
+                }
+            }
+
+            if (obj.children) {
+                include(result, obj.children, clobber, merge);
+            }
+        } catch(e) {
+            utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
+        }
+    });
+}
+
+/**
+ * Merge properties from one object onto another recursively.  Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge(target, src) {
+    for (var prop in src) {
+        if (src.hasOwnProperty(prop)) {
+            if (target.prototype && target.prototype.constructor === target) {
+                // If the target object is a constructor override off prototype.
+                clobber(target.prototype, prop, src[prop]);
+            } else {
+                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+                    recursiveMerge(target[prop], src[prop]);
+                } else {
+                    clobber(target, prop, src[prop]);
+                }
+            }
+        }
+    }
+}
+
+exports.buildIntoButDoNotClobber = function(objects, target) {
+    include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function(objects, target) {
+    include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+    include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
+
+});
+
+// file: lib/common/channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+    nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady*              Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
+ * onDeviceReady*              User event fired to indicate that Cordova is ready
+ * onResume                    User event fired to indicate a start/resume lifecycle event
+ * onPause                     User event fired to indicate a pause lifecycle event
+ * onDestroy*                  Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ *      pause                 App has moved to background
+ *      resume                App has returned to foreground
+ *
+ * Listeners can be registered as:
+ *      document.addEventListener("deviceready", myDeviceReadyListener, false);
+ *      document.addEventListener("resume", myResumeListener, false);
+ *      document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ *      window.onload
+ *      window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type  String the channel name
+ */
+var Channel = function(type, sticky) {
+    this.type = type;
+    // Map of guid -> function.
+    this.handlers = {};
+    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+    this.state = sticky ? 1 : 0;
+    // Used in sticky mode to remember args passed to fire().
+    this.fireArgs = null;
+    // Used by onHasSubscribersChange to know if there are any listeners.
+    this.numHandlers = 0;
+    // Function that is called when the first listener is subscribed, or when
+    // the last listener is unsubscribed.
+    this.onHasSubscribersChange = null;
+},
+    channel = {
+        /**
+         * Calls the provided function only after all of the channels specified
+         * have been fired. All channels must be sticky channels.
+         */
+        join: function(h, c) {
+            var len = c.length,
+                i = len,
+                f = function() {
+                    if (!(--i)) h();
+                };
+            for (var j=0; j<len; j++) {
+                if (c[j].state === 0) {
+                    throw Error('Can only use join with sticky channels.');
+                }
+                c[j].subscribe(f);
+            }
+            if (!len) h();
+        },
+        create: function(type) {
+            return channel[type] = new Channel(type, false);
+        },
+        createSticky: function(type) {
+            return channel[type] = new Channel(type, true);
+        },
+
+        /**
+         * cordova Channels that must fire before "deviceready" is fired.
+         */
+        deviceReadyChannelsArray: [],
+        deviceReadyChannelsMap: {},
+
+        /**
+         * Indicate that a feature needs to be initialized before it is ready to be used.
+         * This holds up Cordova's "deviceready" event until the feature has been initialized
+         * and Cordova.initComplete(feature) is called.
+         *
+         * @param feature {String}     The unique feature name
+         */
+        waitForInitialization: function(feature) {
+            if (feature) {
+                var c = channel[feature] || this.createSticky(feature);
+                this.deviceReadyChannelsMap[feature] = c;
+                this.deviceReadyChannelsArray.push(c);
+            }
+        },
+
+        /**
+         * Indicate that initialization code has completed and the feature is ready to be used.
+         *
+         * @param feature {String}     The unique feature name
+         */
+        initializationComplete: function(feature) {
+            var c = this.deviceReadyChannelsMap[feature];
+            if (c) {
+                c.fire();
+            }
+        }
+    };
+
+function forceFunction(f) {
+    if (typeof f != 'function') throw "Function required as first argument!";
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function(f, c) {
+    // need a function to call
+    forceFunction(f);
+    if (this.state == 2) {
+        f.apply(c || this, this.fireArgs);
+        return;
+    }
+
+    var func = f,
+        guid = f.observer_guid;
+    if (typeof c == "object") { func = utils.close(c, f); }
+
+    if (!guid) {
+        // first time any channel has seen this subscriber
+        guid = '' + nextGuid++;
+    }
+    func.observer_guid = guid;
+    f.observer_guid = guid;
+
+    // Don't add the same handler more than once.
+    if (!this.handlers[guid]) {
+        this.handlers[guid] = func;
+        this.numHandlers++;
+        if (this.numHandlers == 1) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function(f) {
+    // need a function to unsubscribe
+    forceFunction(f);
+
+    var guid = f.observer_guid,
+        handler = this.handlers[guid];
+    if (handler) {
+        delete this.handlers[guid];
+        this.numHandlers--;
+        if (this.numHandlers === 0) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function(e) {
+    var fail = false,
+        fireArgs = Array.prototype.slice.call(arguments);
+    // Apply stickiness.
+    if (this.state == 1) {
+        this.state = 2;
+        this.fireArgs = fireArgs;
+    }
+    if (this.numHandlers) {
+        // Copy the values first so that it is safe to modify it from within
+        // callbacks.
+        var toCall = [];
+        for (var item in this.handlers) {
+            toCall.push(this.handlers[item]);
+        }
+        for (var i = 0; i < toCall.length; ++i) {
+            toCall[i].apply(this, fireArgs);
+        }
+        if (this.state == 2 && this.numHandlers) {
+            this.numHandlers = 0;
+            this.handlers = {};
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+channel.createSticky('onPluginsReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Event to indicate a destroy lifecycle event
+channel.createSticky('onDestroy');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onDOMContentLoaded');
+
+module.exports = channel;
+
+});
+
+// file: lib/android/exec.js
+define("cordova/exec", function(require, exports, module) {
+
+/**
+ * Execute a cordova command.  It is up to the native side whether this action
+ * is synchronous or asynchronous.  The native side can return:
+ *      Synchronous: PluginResult object as a JSON string
+ *      Asynchronous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success    The success callback
+ * @param {Function} fail       The fail callback
+ * @param {String} service      The name of the service to use
+ * @param {String} action       Action to be run in cordova
+ * @param {String[]} [args]     Zero or more arguments to pass to the method
+ */
+var cordova = require('cordova'),
+    nativeApiProvider = require('cordova/android/nativeapiprovider'),
+    utils = require('cordova/utils'),
+    base64 = require('cordova/base64'),
+    jsToNativeModes = {
+        PROMPT: 0,
+        JS_OBJECT: 1,
+        // This mode is currently for benchmarking purposes only. It must be enabled
+        // on the native side through the ENABLE_LOCATION_CHANGE_EXEC_MODE
+        // constant within CordovaWebViewClient.java before it will work.
+        LOCATION_CHANGE: 2
+    },
+    nativeToJsModes = {
+        // Polls for messages using the JS->Native bridge.
+        POLLING: 0,
+        // For LOAD_URL to be viable, it would need to have a work-around for
+        // the bug where the soft-keyboard gets dismissed when a message is sent.
+        LOAD_URL: 1,
+        // For the ONLINE_EVENT to be viable, it would need to intercept all event
+        // listeners (both through addEventListener and window.ononline) as well
+        // as set the navigator property itself.
+        ONLINE_EVENT: 2,
+        // Uses reflection to access private APIs of the WebView that can send JS
+        // to be executed.
+        // Requires Android 3.2.4 or above.
+        PRIVATE_API: 3
+    },
+    jsToNativeBridgeMode,  // Set lazily.
+    nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT,
+    pollEnabled = false,
+    messagesFromNative = [];
+
+function androidExec(success, fail, service, action, args) {
+    // Set default bridge modes if they have not already been set.
+    // By default, we use the failsafe, since addJavascriptInterface breaks too often
+    if (jsToNativeBridgeMode === undefined) {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+    }
+
+    // Process any ArrayBuffers in the args into a string.
+    for (var i = 0; i < args.length; i++) {
+        if (utils.typeName(args[i]) == 'ArrayBuffer') {
+            args[i] = base64.fromArrayBuffer(args[i]);
+        }
+    }
+
+    var callbackId = service + cordova.callbackId++,
+        argsJson = JSON.stringify(args);
+
+    if (success || fail) {
+        cordova.callbacks[callbackId] = {success:success, fail:fail};
+    }
+
+    if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) {
+        window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson;
+    } else {
+        var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson);
+        // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
+        // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.
+        if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && messages === "@Null arguments.") {
+            androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
+            androidExec(success, fail, service, action, args);
+            androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+            return;
+        } else {
+            androidExec.processMessages(messages);
+        }
+    }
+}
+
+function pollOnceFromOnlineEvent() {
+    pollOnce(true);
+}
+
+function pollOnce(opt_fromOnlineEvent) {
+    var msg = nativeApiProvider.get().retrieveJsMessages(!!opt_fromOnlineEvent);
+    androidExec.processMessages(msg);
+}
+
+function pollingTimerFunc() {
+    if (pollEnabled) {
+        pollOnce();
+        setTimeout(pollingTimerFunc, 50);
+    }
+}
+
+function hookOnlineApis() {
+    function proxyEvent(e) {
+        cordova.fireWindowEvent(e.type);
+    }
+    // The network module takes care of firing online and offline events.
+    // It currently fires them only on document though, so we bridge them
+    // to window here (while first listening for exec()-releated online/offline
+    // events).
+    window.addEventListener('online', pollOnceFromOnlineEvent, false);
+    window.addEventListener('offline', pollOnceFromOnlineEvent, false);
+    cordova.addWindowEventHandler('online');
+    cordova.addWindowEventHandler('offline');
+    document.addEventListener('online', proxyEvent, false);
+    document.addEventListener('offline', proxyEvent, false);
+}
+
+hookOnlineApis();
+
+androidExec.jsToNativeModes = jsToNativeModes;
+androidExec.nativeToJsModes = nativeToJsModes;
+
+androidExec.setJsToNativeBridgeMode = function(mode) {
+    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
+        console.log('Falling back on PROMPT mode since _cordovaNative is missing. Expected for Android 3.2 and lower only.');
+        mode = jsToNativeModes.PROMPT;
+    }
+    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
+    jsToNativeBridgeMode = mode;
+};
+
+androidExec.setNativeToJsBridgeMode = function(mode) {
+    if (mode == nativeToJsBridgeMode) {
+        return;
+    }
+    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
+        pollEnabled = false;
+    }
+
+    nativeToJsBridgeMode = mode;
+    // Tell the native side to switch modes.
+    nativeApiProvider.get().setNativeToJsBridgeMode(mode);
+
+    if (mode == nativeToJsModes.POLLING) {
+        pollEnabled = true;
+        setTimeout(pollingTimerFunc, 1);
+    }
+};
+
+// Processes a single message, as encoded by NativeToJsMessageQueue.java.
+function processMessage(message) {
+    try {
+        var firstChar = message.charAt(0);
+        if (firstChar == 'J') {
+            eval(message.slice(1));
+        } else if (firstChar == 'S' || firstChar == 'F') {
+            var success = firstChar == 'S';
+            var keepCallback = message.charAt(1) == '1';
+            var spaceIdx = message.indexOf(' ', 2);
+            var status = +message.slice(2, spaceIdx);
+            var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
+            var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
+            var payloadKind = message.charAt(nextSpaceIdx + 1);
+            var payload;
+            if (payloadKind == 's') {
+                payload = message.slice(nextSpaceIdx + 2);
+            } else if (payloadKind == 't') {
+                payload = true;
+            } else if (payloadKind == 'f') {
+                payload = false;
+            } else if (payloadKind == 'N') {
+                payload = null;
+            } else if (payloadKind == 'n') {
+                payload = +message.slice(nextSpaceIdx + 2);
+            } else if (payloadKind == 'A') {
+                var data = message.slice(nextSpaceIdx + 2);
+                var bytes = window.atob(data);
+                var arraybuffer = new Uint8Array(bytes.length);
+                for (var i = 0; i < bytes.length; i++) {
+                    arraybuffer[i] = bytes.charCodeAt(i);
+                }
+                payload = arraybuffer.buffer;
+            } else if (payloadKind == 'S') {
+                payload = window.atob(message.slice(nextSpaceIdx + 2));
+            } else {
+                payload = JSON.parse(message.slice(nextSpaceIdx + 1));
+            }
+            cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
+        } else {
+            console.log("processMessage failed: invalid message:" + message);
+        }
+    } catch (e) {
+        console.log("processMessage failed: Message: " + message);
+        console.log("processMessage failed: Error: " + e);
+        console.log("processMessage failed: Stack: " + e.stack);
+    }
+}
+
+// This is called from the NativeToJsMessageQueue.java.
+androidExec.processMessages = function(messages) {
+    if (messages) {
+        messagesFromNative.push(messages);
+        // Check for the reentrant case, and enqueue the message if that's the case.
+        if (messagesFromNative.length > 1) {
+            return;
+        }
+        while (messagesFromNative.length) {
+            // Don't unshift until the end so that reentrancy can be detected.
+            messages = messagesFromNative[0];
+            // The Java side can send a * message to indicate that it
+            // still has messages waiting to be retrieved.
+            if (messages == '*') {
+                messagesFromNative.shift();
+                window.setTimeout(pollOnce, 0);
+                return;
+            }
+
+            var spaceIdx = messages.indexOf(' ');
+            var msgLen = +messages.slice(0, spaceIdx);
+            var message = messages.substr(spaceIdx + 1, msgLen);
+            messages = messages.slice(spaceIdx + msgLen + 1);
+            processMessage(message);
+            if (messages) {
+                messagesFromNative[0] = messages;
+            } else {
+                messagesFromNative.shift();
+            }
+        }
+    }
+};
+
+module.exports = androidExec;
+
+});
+
+// file: lib/common/init.js
+define("cordova/init", function(require, exports, module) {
+
+var channel = require('cordova/channel');
+var cordova = require('cordova');
+var modulemapper = require('cordova/modulemapper');
+var platform = require('cordova/platform');
+var pluginloader = require('cordova/pluginloader');
+
+var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];
+
+function logUnfiredChannels(arr) {
+    for (var i = 0; i < arr.length; ++i) {
+        if (arr[i].state != 2) {
+            console.log('Channel not fired: ' + arr[i].type);
+        }
+    }
+}
+
+window.setTimeout(function() {
+    if (channel.onDeviceReady.state != 2) {
+        console.log('deviceready has not fired after 5 seconds.');
+        logUnfiredChannels(platformInitChannelsArray);
+        logUnfiredChannels(channel.deviceReadyChannelsArray);
+    }
+}, 5000);
+
+// Replace navigator before any modules are required(), to ensure it happens as soon as possible.
+// We replace it so that properties that can't be clobbered can instead be overridden.
+function replaceNavigator(origNavigator) {
+    var CordovaNavigator = function() {};
+    CordovaNavigator.prototype = origNavigator;
+    var newNavigator = new CordovaNavigator();
+    // This work-around really only applies to new APIs that are newer than Function.bind.
+    // Without it, APIs such as getGamepads() break.
+    if (CordovaNavigator.bind) {
+        for (var key in origNavigator) {
+            if (typeof origNavigator[key] == 'function') {
+                newNavigator[key] = origNavigator[key].bind(origNavigator);
+            }
+        }
+    }
+    return newNavigator;
+}
+if (window.navigator) {
+    window.navigator = replaceNavigator(window.navigator);
+}
+
+if (!window.console) {
+    window.console = {
+        log: function(){}
+    };
+}
+if (!window.console.warn) {
+    window.console.warn = function(msg) {
+        this.log("warn: " + msg);
+    };
+}
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+// Listen for DOMContentLoaded and notify our channel subscribers.
+if (document.readyState == 'complete' || document.readyState == 'interactive') {
+    channel.onDOMContentLoaded.fire();
+} else {
+    document.addEventListener('DOMContentLoaded', function() {
+        channel.onDOMContentLoaded.fire();
+    }, false);
+}
+
+// _nativeReady is global variable that the native side can set
+// to signify that the native code is ready. It is a global since
+// it may be called before any cordova JS is ready.
+if (window._nativeReady) {
+    channel.onNativeReady.fire();
+}
+
+modulemapper.clobbers('cordova', 'cordova');
+modulemapper.clobbers('cordova/exec', 'cordova.exec');
+modulemapper.clobbers('cordova/exec', 'Cordova.exec');
+
+// Call the platform-specific initialization.
+platform.bootstrap && platform.bootstrap();
+
+pluginloader.load(function() {
+    channel.onPluginsReady.fire();
+});
+
+/**
+ * Create all cordova objects once native side is ready.
+ */
+channel.join(function() {
+    modulemapper.mapModules(window);
+
+    platform.initialize && platform.initialize();
+
+    // Fire event to notify that all objects are created
+    channel.onCordovaReady.fire();
+
+    // Fire onDeviceReady event once page has fully loaded, all
+    // constructors have run and cordova info has been received from native
+    // side.
+    channel.join(function() {
+        require('cordova').fireDocumentEvent('deviceready');
+    }, channel.deviceReadyChannelsArray);
+
+}, platformInitChannelsArray);
+
+
+});
+
+// file: lib/common/modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder'),
+    moduleMap = define.moduleMap,
+    symbolList,
+    deprecationMap;
+
+exports.reset = function() {
+    symbolList = [];
+    deprecationMap = {};
+};
+
+function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
+    if (!(moduleName in moduleMap)) {
+        throw new Error('Module ' + moduleName + ' does not exist.');
+    }
+    symbolList.push(strategy, moduleName, symbolPath);
+    if (opt_deprecationMessage) {
+        deprecationMap[symbolPath] = opt_deprecationMessage;
+    }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.runs = function(moduleName) {
+    addEntry('r', moduleName, null);
+};
+
+function prepareNamespace(symbolPath, context) {
+    if (!symbolPath) {
+        return context;
+    }
+    var parts = symbolPath.split('.');
+    var cur = context;
+    for (var i = 0, part; part = parts[i]; ++i) {
+        cur = cur[part] = cur[part] || {};
+    }
+    return cur;
+}
+
+exports.mapModules = function(context) {
+    var origSymbols = {};
+    context.CDV_origSymbols = origSymbols;
+    for (var i = 0, len = symbolList.length; i < len; i += 3) {
+        var strategy = symbolList[i];
+        var moduleName = symbolList[i + 1];
+        var module = require(moduleName);
+        // <runs/>
+        if (strategy == 'r') {
+            continue;
+        }
+        var symbolPath = symbolList[i + 2];
+        var lastDot = symbolPath.lastIndexOf('.');
+        var namespace = symbolPath.substr(0, lastDot);
+        var lastName = symbolPath.substr(lastDot + 1);
+
+        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+        var parentObj = prepareNamespace(namespace, context);
+        var target = parentObj[lastName];
+
+        if (strategy == 'm' && target) {
+            builder.recursiveMerge(target, module);
+        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
+            if (!(symbolPath in origSymbols)) {
+                origSymbols[symbolPath] = target;
+            }
+            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+        }
+    }
+};
+
+exports.getOriginalSymbol = function(context, symbolPath) {
+    var origSymbols = context.CDV_origSymbols;
+    if (origSymbols && (symbolPath in origSymbols)) {
+        return origSymbols[symbolPath];
+    }
+    var parts = symbolPath.split('.');
+    var obj = context;
+    for (var i = 0; i < parts.length; ++i) {
+        obj = obj && obj[parts[i]];
+    }
+    return obj;
+};
+
+exports.reset();
+
+
+});
+
+// file: lib/android/platform.js
+define("cordova/platform", function(require, exports, module) {
+
+module.exports = {
+    id: 'android',
+    bootstrap: function() {
+        var channel = require('cordova/channel'),
+            cordova = require('cordova'),
+            exec = require('cordova/exec'),
+            modulemapper = require('cordova/modulemapper');
+
+        // Tell the native code that a page change has occurred.
+        exec(null, null, 'PluginManager', 'startup', []);
+        // Tell the JS that the native side is ready.
+        channel.onNativeReady.fire();
+
+        // TODO: Extract this as a proper plugin.
+        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
+
+        // Inject a listener for the backbutton on the document.
+        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
+        backButtonChannel.onHasSubscribersChange = function() {
+            // If we just attached the first handler or detached the last handler,
+            // let native know we need to override the back button.
+            exec(null, null, "App", "overrideBackbutton", [this.numHandlers == 1]);
+        };
+
+        // Add hardware MENU and SEARCH button handlers
+        cordova.addDocumentEventHandler('menubutton');
+        cordova.addDocumentEventHandler('searchbutton');
+
+        // Let native code know we are all done on the JS side.
+        // Native code will then un-hide the WebView.
+        channel.onCordovaReady.subscribe(function() {
+            exec(null, null, "App", "show", []);
+        });
+    }
+};
+
+});
+
+// file: lib/android/plugin/android/app.js
+define("cordova/plugin/android/app", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+module.exports = {
+    /**
+    * Clear the resource cache.
+    */
+    clearCache:function() {
+        exec(null, null, "App", "clearCache", []);
+    },
+
+    /**
+    * Load the url into the webview or into new browser instance.
+    *
+    * @param url           The URL to load
+    * @param props         Properties that can be passed in to the activity:
+    *      wait: int                           => wait msec before loading URL
+    *      loadingDialog: "Title,Message"      => display a native loading dialog
+    *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error
+    *      clearHistory: boolean              => clear webview history (default=false)
+    *      openExternal: boolean              => open in a new browser (default=false)
+    *
+    * Example:
+    *      navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
+    */
+    loadUrl:function(url, props) {
+        exec(null, null, "App", "loadUrl", [url, props]);
+    },
+
+    /**
+    * Cancel loadUrl that is waiting to be loaded.
+    */
+    cancelLoadUrl:function() {
+        exec(null, null, "App", "cancelLoadUrl", []);
+    },
+
+    /**
+    * Clear web history in this web view.
+    * Instead of BACK button loading the previous web page, it will exit the app.
+    */
+    clearHistory:function() {
+        exec(null, null, "App", "clearHistory", []);
+    },
+
+    /**
+    * Go to previous page displayed.
+    * This is the same as pressing the backbutton on Android device.
+    */
+    backHistory:function() {
+        exec(null, null, "App", "backHistory", []);
+    },
+
+    /**
+    * Override the default behavior of the Android back button.
+    * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
+    *
+    * Note: The user should not have to call this method.  Instead, when the user
+    *       registers for the "backbutton" event, this is automatically done.
+    *
+    * @param override        T=override, F=cancel override
+    */
+    overrideBackbutton:function(override) {
+        exec(null, null, "App", "overrideBackbutton", [override]);
+    },
+
+    /**
+    * Exit and terminate the application.
+    */
+    exitApp:function() {
+        return exec(null, null, "App", "exitApp", []);
+    }
+};
+
+});
+
+// file: lib/common/pluginloader.js
+define("cordova/pluginloader", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+// Helper function to inject a <script> tag.
+function injectScript(url, onload, onerror) {
+    var script = document.createElement("script");
+    // onload fires even when script fails loads with an error.
+    script.onload = onload;
+    script.onerror = onerror || onload;
+    script.src = url;
+    document.head.appendChild(script);
+}
+
+function onScriptLoadingComplete(moduleList, finishPluginLoading) {
+    // Loop through all the plugins and then through their clobbers and merges.
+    for (var i = 0, module; module = moduleList[i]; i++) {
+        if (module) {
+            try {
+                if (module.clobbers && module.clobbers.length) {
+                    for (var j = 0; j < module.clobbers.length; j++) {
+                        modulemapper.clobbers(module.id, module.clobbers[j]);
+                    }
+                }
+
+                if (module.merges && module.merges.length) {
+                    for (var k = 0; k < module.merges.length; k++) {
+                        modulemapper.merges(module.id, module.merges[k]);
+                    }
+                }
+
+                // Finally, if runs is truthy we want to simply require() the module.
+                // This can be skipped if it had any merges or clobbers, though,
+                // since the mapper will already have required the module.
+                if (module.runs && !(module.clobbers && module.clobbers.length) && !(module.merges && module.merges.length)) {
+                    modulemapper.runs(module.id);
+                }
+            }
+            catch(err) {
+                // error with module, most likely clobbers, should we continue?
+            }
+        }
+    }
+
+    finishPluginLoading();
+}
+
+// Handler for the cordova_plugins.js content.
+// See plugman's plugin_loader.js for the details of this object.
+// This function is only called if the really is a plugins array that isn't empty.
+// Otherwise the onerror response handler will just call finishPluginLoading().
+function handlePluginsObject(path, moduleList, finishPluginLoading) {
+    // Now inject the scripts.
+    var scriptCounter = moduleList.length;
+
+    if (!scriptCounter) {
+        finishPluginLoading();
+        return;
+    }
+    function scriptLoadedCallback() {
+        if (!--scriptCounter) {
+            onScriptLoadingComplete(moduleList, finishPluginLoading);
+        }
+    }
+
+    for (var i = 0; i < moduleList.length; i++) {
+        injectScript(path + moduleList[i].file, scriptLoadedCallback);
+    }
+}
+
+function injectPluginScript(pathPrefix, finishPluginLoading) {
+    injectScript(pathPrefix + 'cordova_plugins.js', function(){
+        try {
+            var moduleList = require("cordova/plugin_list");
+            handlePluginsObject(pathPrefix, moduleList, finishPluginLoading);
+        } catch (e) {
+            // Error loading cordova_plugins.js, file not found or something
+            // this is an acceptable error, pre-3.0.0, so we just move on.
+            finishPluginLoading();
+        }
+    }, finishPluginLoading); // also, add script load error handler for file not found
+}
+
+function findCordovaPath() {
+    var path = null;
+    var scripts = document.getElementsByTagName('script');
+    var term = 'cordova.js';
+    for (var n = scripts.length-1; n>-1; n--) {
+        var src = scripts[n].src;
+        if (src.indexOf(term) == (src.length - term.length)) {
+            path = src.substring(0, src.length - term.length);
+            break;
+        }
+    }
+    return path;
+}
+
+// Tries to load all plugins' js-modules.
+// This is an async process, but onDeviceReady is blocked on onPluginsReady.
+// onPluginsReady is fired when there are no plugins to load, or they are all done.
+exports.load = function(callback) {
+    var pathPrefix = findCordovaPath();
+    if (pathPrefix === null) {
+        console.log('Could not find cordova.js script tag. Plugin loading may fail.');
+        pathPrefix = '';
+    }
+    injectPluginScript(pathPrefix, callback);
+};
+
+
+});
+
+// file: lib/common/urlutil.js
+define("cordova/urlutil", function(require, exports, module) {
+
+var urlutil = exports;
+var anchorEl = document.createElement('a');
+
+/**
+ * For already absolute URLs, returns what is passed in.
+ * For relative URLs, converts them to absolute ones.
+ */
+urlutil.makeAbsolute = function(url) {
+  anchorEl.href = url;
+  return anchorEl.href;
+};
+
+});
+
+// file: lib/common/utils.js
+define("cordova/utils", function(require, exports, module) {
+
+var utils = exports;
+
+/**
+ * Defines a property getter / setter for obj[key].
+ */
+utils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) {
+    if (Object.defineProperty) {
+        var desc = {
+            get: getFunc,
+            configurable: true
+        };
+        if (opt_setFunc) {
+            desc.set = opt_setFunc;
+        }
+        Object.defineProperty(obj, key, desc);
+    } else {
+        obj.__defineGetter__(key, getFunc);
+        if (opt_setFunc) {
+            obj.__defineSetter__(key, opt_setFunc);
+        }
+    }
+};
+
+/**
+ * Defines a property getter for obj[key].
+ */
+utils.defineGetter = utils.defineGetterSetter;
+
+utils.arrayIndexOf = function(a, item) {
+    if (a.indexOf) {
+        return a.indexOf(item);
+    }
+    var len = a.length;
+    for (var i = 0; i < len; ++i) {
+        if (a[i] == item) {
+            return i;
+        }
+    }
+    return -1;
+};
+
+/**
+ * Returns whether the item was found in the array.
+ */
+utils.arrayRemove = function(a, item) {
+    var index = utils.arrayIndexOf(a, item);
+    if (index != -1) {
+        a.splice(index, 1);
+    }
+    return index != -1;
+};
+
+utils.typeName = function(val) {
+    return Object.prototype.toString.call(val).slice(8, -1);
+};
+
+/**
+ * Returns an indication of whether the argument is an array or not
+ */
+utils.isArray = function(a) {
+    return utils.typeName(a) == 'Array';
+};
+
+/**
+ * Returns an indication of whether the argument is a Date or not
+ */
+utils.isDate = function(d) {
+    return utils.typeName(d) == 'Date';
+};
+
+/**
+ * Does a deep clone of the object.
+ */
+utils.clone = function(obj) {
+    if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') {
+        return obj;
+    }
+
+    var retVal, i;
+
+    if(utils.isArray(obj)){
+        retVal = [];
+        for(i = 0; i < obj.length; ++i){
+            retVal.push(utils.clone(obj[i]));
+        }
+        return retVal;
+    }
+
+    retVal = {};
+    for(i in obj){
+        if(!(i in retVal) || retVal[i] != obj[i]) {
+            retVal[i] = utils.clone(obj[i]);
+        }
+    }
+    return retVal;
+};
+
+/**
+ * Returns a wrapped version of the function
+ */
+utils.close = function(context, func, params) {
+    if (typeof params == 'undefined') {
+        return function() {
+            return func.apply(context, arguments);
+        };
+    } else {
+        return function() {
+            return func.apply(context, params);
+        };
+    }
+};
+
+/**
+ * Create a UUID
+ */
+utils.createUUID = function() {
+    return UUIDcreatePart(4) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(2) + '-' +
+        UUIDcreatePart(6);
+};
+
+/**
+ * Extends a child object from a parent object using classical inheritance
+ * pattern.
+ */
+utils.extend = (function() {
+    // proxy used to establish prototype chain
+    var F = function() {};
+    // extend Child from Parent
+    return function(Child, Parent) {
+        F.prototype = Parent.prototype;
+        Child.prototype = new F();
+        Child.__super__ = Parent.prototype;
+        Child.prototype.constructor = Child;
+    };
+}());
+
+/**
+ * Alerts a message in any available way: alert or console.log.
+ */
+utils.alert = function(msg) {
+    if (window.alert) {
+        window.alert(msg);
+    } else if (console && console.log) {
+        console.log(msg);
+    }
+};
+
+
+//------------------------------------------------------------------------------
+function UUIDcreatePart(length) {
+    var uuidpart = "";
+    for (var i=0; i<length; i++) {
+        var uuidchar = parseInt((Math.random() * 256), 10).toString(16);
+        if (uuidchar.length == 1) {
+            uuidchar = "0" + uuidchar;
+        }
+        uuidpart += uuidchar;
+    }
+    return uuidpart;
+}
+
+
+});
+
+window.cordova = require('cordova');
+// file: lib/scripts/bootstrap.js
+
+require('cordova/init');
+
+})();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/assets/www/cordova_plugins.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/assets/www/cordova_plugins.js b/spec/fixtures/platforms/android/assets/www/cordova_plugins.js
new file mode 100644
index 0000000..b58b5dd
--- /dev/null
+++ b/spec/fixtures/platforms/android/assets/www/cordova_plugins.js
@@ -0,0 +1,3 @@
+cordova.define('cordova/plugin_list', function(require, exports, module) {
+module.exports = []
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/assets/www/css/index.css
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/assets/www/css/index.css b/spec/fixtures/platforms/android/assets/www/css/index.css
new file mode 100644
index 0000000..51daa79
--- /dev/null
+++ b/spec/fixtures/platforms/android/assets/www/css/index.css
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+* {
+    -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */
+}
+
+body {
+    -webkit-touch-callout: none;                /* prevent callout to copy image, etc when tap to hold */
+    -webkit-text-size-adjust: none;             /* prevent webkit from resizing text to fit */
+    -webkit-user-select: none;                  /* prevent copy paste, to allow, change 'none' to 'text' */
+    background-color:#E4E4E4;
+    background-image:linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+    background-image:-webkit-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+    background-image:-ms-linear-gradient(top, #A7A7A7 0%, #E4E4E4 51%);
+    background-image:-webkit-gradient(
+        linear,
+        left top,
+        left bottom,
+        color-stop(0, #A7A7A7),
+        color-stop(0.51, #E4E4E4)
+    );
+    background-attachment:fixed;
+    font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
+    font-size:12px;
+    height:100%;
+    margin:0px;
+    padding:0px;
+    text-transform:uppercase;
+    width:100%;
+}
+
+/* Portrait layout (default) */
+.app {
+    background:url(../img/logo.png) no-repeat center top; /* 170px x 200px */
+    position:absolute;             /* position in the center of the screen */
+    left:50%;
+    top:50%;
+    height:50px;                   /* text area height */
+    width:225px;                   /* text area width */
+    text-align:center;
+    padding:180px 0px 0px 0px;     /* image height is 200px (bottom 20px are overlapped with text) */
+    margin:-115px 0px 0px -112px;  /* offset vertical: half of image height and text area height */
+                                   /* offset horizontal: half of text area width */
+}
+
+/* Landscape layout (with min-width) */
+@media screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
+    .app {
+        background-position:left center;
+        padding:75px 0px 75px 170px;  /* padding-top + padding-bottom + text area = image height */
+        margin:-90px 0px 0px -198px;  /* offset vertical: half of image height */
+                                      /* offset horizontal: half of image width and text area width */
+    }
+}
+
+h1 {
+    font-size:24px;
+    font-weight:normal;
+    margin:0px;
+    overflow:visible;
+    padding:0px;
+    text-align:center;
+}
+
+.event {
+    border-radius:4px;
+    -webkit-border-radius:4px;
+    color:#FFFFFF;
+    font-size:12px;
+    margin:0px 30px;
+    padding:2px 0px;
+}
+
+.event.listening {
+    background-color:#333333;
+    display:block;
+}
+
+.event.received {
+    background-color:#4B946A;
+    display:none;
+}
+
+@keyframes fade {
+    from { opacity: 1.0; }
+    50% { opacity: 0.4; }
+    to { opacity: 1.0; }
+}
+ 
+@-webkit-keyframes fade {
+    from { opacity: 1.0; }
+    50% { opacity: 0.4; }
+    to { opacity: 1.0; }
+}
+ 
+.blink {
+    animation:fade 3000ms infinite;
+    -webkit-animation:fade 3000ms infinite;
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/assets/www/img/logo.png
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/assets/www/img/logo.png b/spec/fixtures/platforms/android/assets/www/img/logo.png
new file mode 100644
index 0000000..9519e7d
Binary files /dev/null and b/spec/fixtures/platforms/android/assets/www/img/logo.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/assets/www/index.html
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/assets/www/index.html b/spec/fixtures/platforms/android/assets/www/index.html
new file mode 100644
index 0000000..bde5741
--- /dev/null
+++ b/spec/fixtures/platforms/android/assets/www/index.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<!--
+    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.
+-->
+<html>
+    <head>
+        <meta charset="utf-8" />
+        <meta name="format-detection" content="telephone=no" />
+        <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
+        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
+        <link rel="stylesheet" type="text/css" href="css/index.css" />
+        <title>Hello World</title>
+    </head>
+    <body>
+        <div class="app">
+            <h1>Apache Cordova</h1>
+            <div id="deviceready" class="blink">
+                <p class="event listening">Connecting to Device</p>
+                <p class="event received">Device is Ready</p>
+            </div>
+        </div>
+        <script type="text/javascript" src="cordova.js"></script>
+        <script type="text/javascript" src="js/index.js"></script>
+        <script type="text/javascript">
+            app.initialize();
+        </script>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/assets/www/js/index.js
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/assets/www/js/index.js b/spec/fixtures/platforms/android/assets/www/js/index.js
new file mode 100644
index 0000000..31d9064
--- /dev/null
+++ b/spec/fixtures/platforms/android/assets/www/js/index.js
@@ -0,0 +1,49 @@
+/*
+ * 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 app = {
+    // Application Constructor
+    initialize: function() {
+        this.bindEvents();
+    },
+    // Bind Event Listeners
+    //
+    // Bind any events that are required on startup. Common events are:
+    // 'load', 'deviceready', 'offline', and 'online'.
+    bindEvents: function() {
+        document.addEventListener('deviceready', this.onDeviceReady, false);
+    },
+    // deviceready Event Handler
+    //
+    // The scope of 'this' is the event. In order to call the 'receivedEvent'
+    // function, we must explicity call 'app.receivedEvent(...);'
+    onDeviceReady: function() {
+        app.receivedEvent('deviceready');
+    },
+    // Update DOM on a Received Event
+    receivedEvent: function(id) {
+        var parentElement = document.getElementById(id);
+        var listeningElement = parentElement.querySelector('.listening');
+        var receivedElement = parentElement.querySelector('.received');
+
+        listeningElement.setAttribute('style', 'display:none;');
+        receivedElement.setAttribute('style', 'display:block;');
+
+        console.log('Received Event: ' + id);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f4a9597a/spec/fixtures/platforms/android/assets/www/spec.html
----------------------------------------------------------------------
diff --git a/spec/fixtures/platforms/android/assets/www/spec.html b/spec/fixtures/platforms/android/assets/www/spec.html
new file mode 100644
index 0000000..71f00de
--- /dev/null
+++ b/spec/fixtures/platforms/android/assets/www/spec.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<!--
+    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.
+-->
+<html>
+    <head>
+        <title>Jasmine Spec Runner</title>
+
+        <!-- jasmine source -->
+        <link rel="shortcut icon" type="image/png" href="spec/lib/jasmine-1.2.0/jasmine_favicon.png">
+        <link rel="stylesheet" type="text/css" href="spec/lib/jasmine-1.2.0/jasmine.css">
+        <script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine.js"></script>
+        <script type="text/javascript" src="spec/lib/jasmine-1.2.0/jasmine-html.js"></script>
+
+        <!-- include source files here... -->
+        <script type="text/javascript" src="js/index.js"></script>
+
+        <!-- include spec files here... -->
+        <script type="text/javascript" src="spec/helper.js"></script>
+        <script type="text/javascript" src="spec/index.js"></script>
+
+        <script type="text/javascript">
+            (function() {
+                var jasmineEnv = jasmine.getEnv();
+                jasmineEnv.updateInterval = 1000;
+
+                var htmlReporter = new jasmine.HtmlReporter();
+
+                jasmineEnv.addReporter(htmlReporter);
+
+                jasmineEnv.specFilter = function(spec) {
+                    return htmlReporter.specFilter(spec);
+                };
+
+                var currentWindowOnload = window.onload;
+
+                window.onload = function() {
+                    if (currentWindowOnload) {
+                        currentWindowOnload();
+                    }
+                    execJasmine();
+                };
+
+                function execJasmine() {
+                    jasmineEnv.execute();
+                }
+            })();
+        </script>
+    </head>
+    <body>
+        <div id="stage" style="display:none;"></div>
+    </body>
+</html>